9

I created a DLL containing a function named "koduj". Calling this function by using it inside an Excel worksheet cell returns the desired result. Calling "koduj" from VBA returns wrong answer.

koduj needs two arguments: string nr_id and integer x1. It calculates sum of nr_id's letters in ASCII representation and adds x1. Calculated sum is than returned.

I was following instructions found here.

Here's my .cpp sourcefile:

#include<Windows.h>
#include<string>
using namespace std;


//Convert BSTR to wstring for convenience
wstring BSTR_to_wstring (BSTR text){
    return wstring(text, SysStringLen(text));
}

//Calculate sum of letters in ASCII representation
int ASCII_sum (wstring ws){
    int sum = 0;
    for (unsigned int i = 0; i < ws.length(); i++)
        sum += ws[i];
    return sum;
}

//"koduj" function
int _stdcall koduj (BSTR nr_id, int & x1){
    wstring ws_nr_id = BSTR_to_wstring(nr_id);
    return ASCII_sum(ws_nr_id) + x1;
}

Here's my VBA function declaration:

Declare Function koduj _
Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer

By writing:

=koduj("aaa";1)

Inside a worksheet cell I get desired result (292)

Debugging this VBA code:

Sub test()

Dim a As Integer
a = koduj("aaa", 1)

End Sub

reveals wrong result (a = 24930)

I believe my C++ code is fine, as it works properly when called from Excel's worksheet.

GSerg
  • 76,472
  • 17
  • 159
  • 346
browning0
  • 901
  • 2
  • 11
  • 21
  • Try dimensioning `a` as Variant - do you get the same result? – enderland Oct 07 '13 at 00:47
  • @enderland that's right, the same (wrong) value. – browning0 Oct 07 '13 at 05:35
  • This is interesting to me. I've replicated the same issue on my machine, also note that koduj("***") of any three lowercase characters returns the same value. Also note that if you do `Debug.Print koduj("Ab", 1) - koduj("Aa", 1)` you get 256, which strikes me as quite odd. – enderland Oct 07 '13 at 13:25

4 Answers4

4

The reason is that even though VBA strings are internally UTF-16, VB always converts them to ASCII before talking to the outside world (Declared functions, file input/output). So when you Declare a parameter As String, VBA automatically converts the string and passes it out as ASCII. The matching parameter type on the C++ side should be LPSTR or LPCSTR.

If you want to use BSTR on the C++ side, you need to also create an IDL file for that function, compile it into a TLB and reference the TLB from VBA, only then VBA will respect and use BSTR.

Another problem is that C++'s int translates to VBA's Long.

The reason why it works when called from Excel sheet is that apparently Excel ignores the VBA rules for string conversion. I believe this to be a bug.

GSerg
  • 76,472
  • 17
  • 159
  • 346
-1

Try declare a as long: Dim a As Long

anefeletos
  • 672
  • 7
  • 19
-1

I'm guessing from the magnitude of the error that it's the numeric parameter that's going wrong - I would try more explicitly declaring the parameter type in your test VBA routine (probably Integer) and accepting it as that specific type on the C++ side (signed short, in that case).

There's a great Microsoft article about all this at http://msdn.microsoft.com/en-us/library/office/bb687915(v=office.15).aspx.

Chris Rae
  • 5,627
  • 2
  • 36
  • 51
-1

Not intended to be a complete answer, but your second parameter's type looks wrong.

Your DLL function: int _stdcall koduj (BSTR nr_id, int & x1) declares x1 as a reference to a (presumably) 32-bit integer.

Your VBA declaration: Declare Function koduj Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer declares y as a pointer to a 16-bit integer.

I'd suggest try changing VBA declaration as follows:

Declare Function koduj _ Lib "<dll_directory_and_full_name>" (ByVal x As String, ByVal y As Long) As Long

And, switching your DLL function signature to pass x1 by value:

int _stdcall koduj (BSTR nr_id, int x1)

Boris Glick
  • 202
  • 1
  • 4
  • Yes, the Integer/Long situation is as you describe and should be fixed. However it has nothing to do with the string not arriving as bstr. – GSerg Mar 20 '23 at 10:45