In our environment our main application uses MS Access for a front-end. The back-ends are Access, MySQL and MariaDB. Some of the routines we need are only available in C# so we have to be able to call .NET dll routines from VBA. I did some testing with registered dlls (using RegASM) and it worked fine. However, for the installs on client machines, we really need to be able to get to the shared dlls WITHOUT registering them.
I have been trying to get dynamically loaded libraries in MS Access VBA to work for a long time now. I thought I was close when I found this example: Canonical: How to call .NET methods from Excel VBA
I typed in the example verbatim and built it using Visual Studio 2017 Community. Then I tried to run it in two different test environments. The first was a Windows 7 Pro (64 bit) box with MS Office Pro 2010 (32 bit). The second test box has Windows 10 Pro (64 bit) and MS Office 2016 Pro (64 bit). The result was the same on both, except for the error number/message.
Here is the sample code from the above link (I hope reposting the snippet is not a breach of etiquette. I wanted to make this post easier to follow):
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class YOUR_MAIN_CLASS
{
[return: MarshalAs(UnmanagedType.BStr)]
public string FN_RETURN_TEXT(string iMsg)
{
return "You have sent me: " + iMsg + "...";
}
}
static class UnmanagedExports
{
[DllExport]
[return: MarshalAs(UnmanagedType.IDispatch)]
static Object YOUR_DLL_OBJECT()
{
return new YOUR_MAIN_CLASS();
}
}
Here is the VBA code. The only difference is that I did not use the "PtrSafe" qualifier in the Access 2010 32 bit test, but I did use it for the Access 2016 64 bit Access test. I set the Visual Studio Platform Target to x86 for the test with 32 bit Access and to x64 for the 64 bit Access. Other than that, everything was the same.
Option Compare Database
Option Explicit
Public Declare PtrSafe Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" ()
Public Sub TestLoad()
LoadLibrary ("C:\Users\lab\Documents\Visual Studio 2017\Projects\NonRegisteredDLL\NonRegisteredDLL\bin\Debug\NonRegisteredDLL.dll")
Dim mObj As Object
' Error occurs on next line
Set mObj = YOUR_DLL_OBJECT()
Debug.Print mObj.FN_RETURN_TEXT("Testing...")
End Sub
When the code is run, the errors always occur at the "Set mObj" line.
In the Access 2010 32 bit test, the error is:
Run-time error '49': Bad DLL calling convention
In the Access 2016 64 bit test, the error is:
Run-time error '424': Object required
On both tests, I ran DumpBin and the result seemed fine:
>dumpbin nonregistereddll.dll /exports
Dump of file nonregistereddll.dll
File Type: DLL
Section contains the following exports for \NonRegisteredDLL.dll
00000000 characteristics
5C0FF158 time date stamp Tue Dec 11 10:18:16 2018
0.00 version
0 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
0 0 0000283E YOUR_DLL_OBJECT
Summary
2000 .reloc
2000 .rsrc
2000 .sdata
2000 .text
>
Based upon a few other posts here on stackoverflow, I also experimented with the CallingConvention parameter on the DllExport but the result was always the same. I was very surprised that I couldn't get the example to work as I had entered it directly from the other post and I double-checked to make sure it was copied correctly. Any help would be greatly appreciated.
Your declaration for the DLL is incomplete or missing
Data Type
. Changeto
read more here and try again.