Search code examples
vbadllimport32-bit

Problems using a C++ Dll with Excel 2016 32bit


im looking for a solution, that a DLL is not running on Excel 2016 32bit. I've tried so much in the recent weeks, that i have no idea left. I only get it running on Excel 64bit, I have two different DLL's for that. I use Visual Studio 2022, but have also tried it to compile in VB 2017. I'm getting Runtime Error 453 "Cant find entry point in dll". If i use the declatarion with the path "Private Declare Function crypt32 Lib "Path\crypt32.dll" Alias "_crypt32@4" (ByVal inputs As String) As String", i get Runtime error 53 "Cant find file".

Starting with the C++ Code:

C++ 64bit DLL:

#include "pch.h"
#include <Windows.h>
#include <OleAuto.h>

extern "C" __declspec(dllexport) BSTR crypt64(BSTR input) {
    wchar_t output[2]; 
    wchar_t inputChar = input[0];


    if (inputChar >= L'A' && inputChar <= L'Z') {
        inputChar = (inputChar - L'A' + 1) % 26 + L'A'; 
    }
    else if (inputChar >= L'a' && inputChar <= L'z') {
        inputChar = (inputChar - L'a' + 1) % 26 + L'a'; 
    }

    switch (inputChar) {
    case L'a': output[0] = L't'; break;

    default: output[0] = inputChar; break; 
    }

    output[1] = L'\0'; 

    return SysAllocString(output); 
}

extern "C" __declspec(dllexport) void FreeBSTR(BSTR bstr) {
    SysFreeString(bstr);
}

C++ 32bit DLL:

#include "pch.h"
#include <Windows.h>
#include <OleAuto.h>

extern "C" __declspec(dllexport) BSTR __stdcall crypt32(BSTR input) {
    wchar_t output[2]; 
    wchar_t inputChar = input[0];


    if (inputChar >= L'A' && inputChar <= L'Z') {
        inputChar = (inputChar - L'A' + 1) % 26 + L'A'; 
    }
    else if (inputChar >= L'a' && inputChar <= L'z') {
        inputChar = (inputChar - L'a' + 1) % 26 + L'a'; 
    }

    switch (inputChar) {
    case L'a': output[0] = L't'; break;

    default: output[0] = inputChar; break; 
    }

    output[1] = L'\0'; 

    return SysAllocString(output); 
}

extern "C" __declspec(dllexport) void FreeBSTR(BSTR bstr) {
    SysFreeString(bstr);
}

Its not the whole C++ Code, just testwise to make it work.

VBA Code:

Option Explicit

#If Win64 Then
    Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
    Private Declare PtrSafe Function crypt64 Lib "crypt64.dll" (ByVal inputs As String) As String
#Else
    Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
    Private Declare Function crypt32 Lib "crypt32.dll" Alias "_crypt32@4" (ByVal inputs As String) As String
#End If

Sub dllcheck(inputs As String)
    Dim dllPath As String, hModule As Long

    #If Win64 Then
        dllPath = ThisWorkbook.Path & "\Code\crypt64.dll"
    #Else
        dllPath = ThisWorkbook.Path & "\Code\crypt32.dll"
    #End If

    hModule = LoadLibrary(dllPath)
    If hModule = 0 Then
        MsgBox "Error"
        Exit Sub
    Else
        MsgBox "Connected to DLL"
    End If
End Sub

Sub testconnect()

    Dim result As String

    #If Win64 Then
        dllcheck ""
        result = crypt64("5")
        MsgBox result
    #Else
        dllcheck ""
        result = crypt32("5")
        MsgBox result
    #End If
    
End Sub

Here is my Dumpbin:

ordinal hint RVA      name

      1    0 00011055 FreeBSTR
      2    1 00011334 _crypt32@4

Thanks for reviewing.

Tried it without the __stdcall convention, tried to write a Header already, but couldnt get it started. I also used VBA Code that was directly linked to the path (Private Declare Function crypt32 Lib "Path\crypt32.dll" Alias "_crypt32@4" (ByVal inputs As String) As String)


Solution

  • I don't know why you need 2 functions or 2 files. Here's a simplified version.

    crypt.cpp (for current content, crypt.c would probably be a better name):

    #include <Windows.h>
    #include <OleAuto.h>
    
    #define CRYPT_EXPORT_API __declspec(dllexport)
    
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    CRYPT_EXPORT_API BSTR crypt(const BSTR input);
    CRYPT_EXPORT_API void freeBSTR(BSTR bstr);
    
    #if defined(__cplusplus)
    }
    #endif
    
    
    BSTR crypt(const BSTR input)
    {
        wchar_t output[2]; 
        wchar_t i0 = input[0];
    
        if ((i0 >= L'A') && (i0 <= L'Z')) {
            i0 = (i0 - L'A' + 1) % 26 + L'A'; 
        } else if ((i0 >= L'a') && (i0 <= L'z')) {
            i0 = (i0 - L'a' + 1) % 26 + L'a'; 
        }
    
        switch (i0) {
        case L'a':
            output[0] = L't';
            break;
        default:
            output[0] = i0;
            break; 
        }
        output[1] = L'\0'; 
        return SysAllocString(output);
    }
    
    
    void freeBSTR(BSTR bstr)
    {
        SysFreeString(bstr);
    }
    

    Output (split in 2 parts for clarity):

    • Build:

      [cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079122180]> sopr.bat
      ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
      
      [prompt]>
      [prompt]> dir /b
      crypt.cpp
      
      [prompt]> :: Configure VS22 for 032bit
      [prompt]> "c:\Install\pc064\Microsoft\VisualStudioCommunity\2022\VC\Auxiliary\Build\vcvarsall.bat" x86 > nul
      
      [prompt]>
      [prompt]> cl /nologo /MD /DDLL crypt.cpp  /link /NOLOGO /DLL /OUT:libcrypt32.dll OleAut32.lib
      crypt.cpp
         Creating library libcrypt32.lib and object libcrypt32.exp
      
      [prompt]>
      [prompt]> dir /b
      crypt.cpp
      crypt.obj
      libcrypt32.dll
      libcrypt32.exp
      libcrypt32.lib
      
      [prompt]>
      [prompt]> :: Configure VS22 for 064bit
      [prompt]> "c:\Install\pc064\Microsoft\VisualStudioCommunity\2022\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul
      
      [prompt]>
      [prompt]> cl /nologo /MD /DDLL crypt.cpp  /link /NOLOGO /DLL /OUT:libcrypt64.dll OleAut32.lib
      crypt.cpp
         Creating library libcrypt64.lib and object libcrypt64.exp
      
      [prompt]>
      [prompt]> dir /b
      crypt.cpp
      crypt.obj
      libcrypt32.dll
      libcrypt32.exp
      libcrypt32.lib
      libcrypt64.dll
      libcrypt64.exp
      libcrypt64.lib
      
    • Test (same Cmd window):

      [prompt]> :: ---------- Check the 064bit .dll ----------
      [prompt]> :: Exports
      [prompt]> dumpbin /nologo /exports .\libcrypt64.dll
      
      Dump of file .\libcrypt64.dll
      
      File Type: DLL
      
        Section contains the following exports for libcrypt64.dll
      
          00000000 characteristics
          FFFFFFFF time date stamp
              0.00 version
                 1 ordinal base
                 2 number of functions
                 2 number of names
      
          ordinal hint RVA      name
      
                1    0 00001000 crypt
                2    1 00001100 freeBSTR
      
        Summary
      
              1000 .data
              1000 .pdata
              1000 .rdata
              1000 .reloc
              1000 .text
      
      [prompt]>
      [prompt]> :: Architecture
      [prompt]> dumpbin /headers .\libcrypt64.dll | findstr "machine"
                  8664 machine (x64)
      
      [prompt]>
      [prompt]> :: ---------- Check the 032bit .dll ----------
      [prompt]> :: Exports
      [prompt]> dumpbin /nologo /exports .\libcrypt32.dll
      
      Dump of file .\libcrypt32.dll
      
      File Type: DLL
      
        Section contains the following exports for libcrypt32.dll
      
          00000000 characteristics
          FFFFFFFF time date stamp
              0.00 version
                 1 ordinal base
                 2 number of functions
                 2 number of names
      
          ordinal hint RVA      name
      
                1    0 00001000 crypt
                2    1 000010D0 freeBSTR
      
        Summary
      
              1000 .data
              1000 .rdata
              1000 .reloc
              2000 .text
      
      [prompt]>
      [prompt]> :: Architecture
      [prompt]> dumpbin /headers .\libcrypt32.dll | findstr "machine"
                   14C machine (x86)
                         32 bit word machine
      

    Same function name, so the VBA code could be cleaned by that 064bit / 032bit ugliness (only thing that differs is the .dll name).

    Check: