VBA error 49 and error 424 when calling C# DLL from Access VBA using unmamagedexports

339 views Asked by At

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.

1

There are 1 answers

1
Krish On

Your declaration for the DLL is incomplete or missing Data Type. Change

Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" ()

to

Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" () As Object

Note

Previous versions of Visual Basic allowed you to declare parameters As Any, meaning that data of any data type could be used. Visual Basic requires that you use a specific data type for all Declare statements.

read more here and try again.