Invalid Outside Procedure when defining DLL function in VBA - excel

Private Declare PtrSafe Function GenerateActiveTypicalWorksheet Lib "C:\Program Files\EPLAN\EEC One\2.7.3\Platform64\W3ApiBase.dll" Alias "EecOne.GenerateActiveTypicalWorksheet" () As Integer
Call Application.Run("EecOne.GenerateActiveTypicalWorksheet")
End Function
Private Sub Workbook_Open()
GenerateActiveTypicalWorksheet
End Sub
I'm trying to call a function within the .dll file and I get the error 'Invalid outside procedure'.
This is the only piece of documentation available for the dll/API I'm trying to use:
and this:

Syntax should be like this:
Private Declare PtrSafe Function GenerateActiveTypicalWorksheet Lib "C:\Program Files\EPLAN\EEC One\2.7.3\Platform64\W3ApiBase.dll" Alias "EecOne.GenerateActiveTypicalWorksheet" () As Integer
Private Sub Workbook_Open()
GenerateActiveTypicalWorksheet
End Sub
Note that Private Declare PtrSafe Function is just like a reference to a function in a library. It's just to make it available and has no source code and no End Function. It's more like a link to a function.
Issue here was that these two lines …
Call Application.Run("EecOne.GenerateActiveTypicalWorksheet")
End Function
were not within a function or procedure therefore you got the error …
Invalid outside procedure

Related

Creating sub folders using a path

Below is the code where I create subfolder A from the path on cell E3. This is the path: C:\SW\A. But what if I want to create these subfolders (A and B and C) using 1 path like C:\SW\A\B\C? This doesn't create the subfolders.
Sub MakeFolders()
Dim path As String
'mkdir function
path = Range("E3").Value
MkDir path
End Sub
any idea how to make 3 subfolders using only 1 path?
The Win32API, MakeSureDirectoryExists, will do what you're asking for - it will check if each folder in the path exists, and if not, it will make it. To use APIs, you need to make sure that Declaration component sits at the start of a module (along with its accompanying function, BuildDirPath)
#If VBA7 Then
Private Declare PtrSafe Function MakeSureDirectoryPathExists Lib "imagehlp.dll" (ByVal DirPath As String) As Long
#Else
Private Declare Function MakeSureDirectoryPathExists Lib "imagehlp.dll" (ByVal DirPath As String) As Long
#End If
Function BuildDirPath(ByVal Path As String) As Boolean
BuildDirPath = CBool(MakeSureDirectoryPathExists(Path) = 1)
End Function
To use it, it's simply a matter of calling the function BuildDirPath.
Debug.Print BuildDirPath("C:\SW\A\B\C")
It will return a TRUE value if it was successful. I should add that this API is limited to ASCII characters and does not support Unicode - which means that it cannot be used for a non-Western character set (e.g., Japanese hiragana). Hope that helps.

Pass instance of class module in sub procedure

I have a class module called game which calls a sub from another class module called gameUi. This sub receives an instance of a class module called board.
game class module:
Private board As New board
Private gameUi As New gameUi
Sub Init()
gameUi.Init board
End Sub
gameUi class module:
Private board As board
Sub Init(gameBoard As board)
board = gameBoard
End Sub
I keep getting this error and I can't understand why:
I have other sub / functions in other class modules that receive parameters such as Integers and Strings but I don't get this error there. It seems it just happens when I pass an instance of a class module.
I've tried passing another class module to the sub and it happens the same. Also tried adding the ByVal or ByRef options but the result is the error shown.
If anybody could help I would be very appreciated. Thank you for your time!

Sub works differently through button on the worksheet

So I've spent the evening trying to design snake in VBA. Great stuff. It seemed to be working fine whenever I ran the Main Sub from the VBA window (by clicking the play button in the top ribbon), however when I added a button on the worksheet for the same sub, it runs with no errors but the controls don't behave in the same way. Originally each time you press an arrow you just change direction, however when running the macro through a button you can keep holding the arrow in the direction you're going and it speeds up the snake, so the cell select behaves as it normally would in Excel, rather than as required in snake. This defeats the purpose of the game as the rest of the snake can't catch up with the head and creates gaps within allowing the user to just jump through it.
I'm using GetAsyncKeyState to read key presses:
#If VBA7 Then
Private Declare PtrSafe Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
#Else
Private Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
#End If
Private Const VK_LEFT = &H25 'LEFT ARROW key
Private Const VK_UP = &H26 'UP ARROW key
Private Const VK_RIGHT = &H27 'RIGHT ARROW key
Private Const VK_DOWN = &H28 'DOWN ARROW key
And then calling this with If Statements:
' Key press handling
WasteTime (speed)
If GetAsyncKeyState(VK_DOWN) Then
PressDown
ElseIf GetAsyncKeyState(VK_UP) Then
PressUp
ElseIf GetAsyncKeyState(VK_LEFT) Then
PressLeft
ElseIf GetAsyncKeyState(VK_RIGHT) Then
PressRight
End If
' Offset by key direction or default
ActiveCell.Offset(cellrow, cellcol).Select
For reference, this is all that each key function does:
Function PressUp()
cellrow = -1
cellcol = 0
End Function
Any help would be greatly appreciated. I suspect this has something to do with me declaring the GetAsyncKeyState function in the General Declarations section, but as I've never done this before, can't quite work out what I'm doing wrong. Thanks :)

Possible syntax mistake? "Expecting =" In a Sub call from a UserForm

I want to call a Sub I declared at it gives a compilation error saying that it expects a =.
The Sub call is in a UserForm_Initialize event procedure.
The code is as follows.
In a module:
Public Sub FillCb(Ar() As String, Cb As ComboBox)
Cb.Clear
For I = 1 To Application.CountA(Ar)
Cb.AddItem (Ar(I))
Next I
End Sub
In the UserForm code:
Private Sub UserForm_Initialize()
LblDate.Caption = Date
FillCb(LibrosNoPrestados, CbLibro)
End Sub
This code is giving me error.
I analized the code line by line using the debugger and commenting the las line inside the Initialize event, and it works fine up to that point. The error is thrown at compile time in the
FillCb(LibrosNoPrestados, CbLibro)
The rest of the code is not needed here since as I said it works fine, but the syntax in that last line must be wrong and I can't see the mistake.
A VBA "feature". If you are calling a sub routine without the "Call" keyword then don't use parentheses, if you use the "Call" keyword then you need the parentheses.
Eg
Call FillCb(LibrosNoPrestados, CbLibro)
Or
FillCb LibrosNoPrestados, CbLibro
Here's Microsoft's documentation:
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/call-statement

Replace path to function or object with Rubberduck

I've come across a couple of scenarios where I'd like a robust method to change the path (blah.blah.blah.myObject) to an object or routine, and I wonder if this is possible with Rubberduck
First scenario: I have a lot of calls to some routine Bar() in my code. I've decided to make that function a member of a class or addin Foo. So I'd like to replace all calls to Bar with Foo.Bar(). i.e.
Sub TestCode()
Bar
End Sub
becomes
Sub TestCode()
Foo.Bar
End Sub
for some publicly declared Foo object
In another situation, I have the following types declared in a class:
Private Type TSubList
Member1 As Long
Member2 As String
End Type
Private Type TList
Member3 As TSubList
Member4 As Double
End Type
Private this As TList
And the call sites look like this:
Private Sub TestCode()
Debug.Print this.Member4, this.Member3.Member1 'dot through 2 levels
End Sub
I want to condense the type into a single type like this
Private Type TList
Member1 As Long
Member2 As String
Member4 As Double
End Type
Private this As TList
Meaning my call site becomes
Private Sub TestCode()
Debug.Print this.Member4, this.Member1 'replace with single level
End Sub
Does Rubberduck have a more robust way of adding or removing elements of a path to a function/variable than a simple find & replace?

Resources