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):

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

    Check: