-1

I'm trying to make a C++/CLI dll to wrap a managed assembly so it can be called from VBA inside Excel (I specifically want to avoid using COM). It shall only support 64 bit.

I have based my test code on the dotnet cpp-cli sample and added four additional native entry points:

extern "C" MIXEDLIBRARY_API int __stdcall CalcIntByVal(const int value)
{
    return 42 + value;
}

extern "C" MIXEDLIBRARY_API double __stdcall CalcDoubleByVal(const double value)
{
    return 3.14 + value;
}

extern "C" MIXEDLIBRARY_API int __stdcall CalcIntByRef(const int* value)
{
    return 42 + *value;
}

extern "C" MIXEDLIBRARY_API double __stdcall CalcDoubleByRef(const double* value)
{
    return 3.14 + *value;
}

I made a small Excel VBA sample that I debug from Visual Studio (use excel as debugging command or attach to process).

It first calls the two 'ByRef' methods then the 'ByVal' methods. Here is the VBA code:

Option Explicit
Private Declare PtrSafe Function SetDllDirectoryW Lib "kernel32" (ByVal lpPathName As LongPtr) As Long

Private Declare PtrSafe Function CalcIntByVal Lib "MixedLibrary.dll" (ByVal value As Long) As Long
Private Declare PtrSafe Function CalcDoubleByVal Lib "MixedLibrary.dll" (ByVal value As Double) As Double
Private Declare PtrSafe Function CalcIntByRef Lib "MixedLibrary.dll" (ByRef value As Long) As Long
Private Declare PtrSafe Function CalcDoubleByRef Lib "MixedLibrary.dll" (ByRef value As Double) As Double


Private Sub CommandRun_Click()
    
    Dim dllPath As String
    dllPath = "MixedLibrary.dll"  ' <- native x64 shim
    
    Dim dllDir As String
    
    dllDir = "C:\temp\\cpp-cli\bin\Debug\x64"  ' <- folder with shim *and* its deps

    ' 1) Add dir so dependencies are found
    Call SetDllDirectoryW(StrPtr(dllDir))
    
    Dim myNumber As Long
    Dim dnum As Double
    dnum = 456#
    myNumber = 123
    
    ' ByRef calls NOT causing exception
    ' Call the C++ method with int
    myNumber = CalcIntByRef(myNumber)
    
    ' Call double
    dnum = CalcDoubleByRef(dnum)
    
    ' ByVal call causing exception
    myNumber = CalcIntByVal(myNumber)
    dnum = CalcDoubleByVal(dnum)
   
    
End Sub

No issue is seen with the first two XXXByRef calls, but with the XXXByVal calls an access violation exception is seen on entry to both methods.

Exception seen on call to CalcDoubleByVal

The value of the argument is also not transferred correctly for the CalcDoubleByVal method.

The exception seems to indicate that the stack or memory has been corrupted, but I cannot find the root cause.

A sample solution can be found here.

https://drive.google.com/file/d/1IyqTzAHGkzZAkBV0JyWlDp8cjnWL2EFP/view?usp=sharing

When debugging the top of the call stack at the time of exception is:

kernel32.dll!IsBadStringPtrA()  Unknown

VBE7.DLL!MereLogWinApi(struct serDllTemplate *,unsigned short,void *)   Unknown

VBE7.DLL!DllFunctionCall()  Unknown

So it seems to be connected with some logging inside VBE7.dll just prior to making the dll call.

From the dissassembly:

 sub         rsp,18h  

 test        rdx,rdx  

 je          IsBadStringPtrA+3Dh (07FFBDBA10B0Dh)  

 test        rcx,rcx  

 je          IsBadStringPtrA+45h (07FFBDBA10B15h)  

 mov         qword ptr [rsp],rcx  

 lea         r8,[rdx-1]  

 lea         r8,[r8+rcx]  

 mov         al,byte ptr [rcx]  

 test        al,al

It fails in the last line, because what seem like it is interpreting the argument as a string.

9
  • 1
    Can you provide a compileable version of the MixedLibrary.dll source rather than an isolated code snippet please? It would make it much easier to test and reproduce your results. Commented Oct 28 at 15:51
  • @MartinBrown Good point. I've shared a full sample here: drive.google.com/file/d/1IyqTzAHGkzZAkBV0JyWlDp8cjnWL2EFP/… Commented Oct 29 at 7:32
  • Sorry but 42MB is a bit on the big side for an MRE. I had in mind not more than a few hundred lines of sourcecode that you have changed not the entire CPP-CLI package. Commented Oct 29 at 9:26
  • @MartinBrown I have now trimmed the zip down to just 96 KB with just two projects inside. Compile solution and debug MixedLibrary project using Excel as command - should be quite minimal. Commented Oct 29 at 13:07
  • I'm a bit confused by your latest description above. Does call ByVal work for all standard types particularly char, int and double ? You say ByRef fails on entry to the function? What I was going to suggest was declare an array in VBA and pass two consecutive elements as ByRef to a test function and return the difference of their addresses. But that won't work if the code is failing on entry. Commented Oct 30 at 10:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.