2
votes

I'm working on a graphical interface written in VB6, where I have to call function contained in a certain DLL written in C. Because of a known limitation I had to implement a trick that allows me to load this DLL in a implicit way.

This is possible creating an IDL file, compile it with MIDL and reference the resulting .tlb file in the VB6 project.

The problem is that VB6 strings and C arrays of char do not match, so I can't pass (and get back) them to the DLL.

The prototype of the C function is:

int __stdcall myFunc(char filename_in[], char filename_out[], char ErrMsg[]);

What should I write in the IDL file and how should I call it from VB6?

Thanks.

3
It looks more like a char array than a string. - GolezTrol
@GolezTrol Yep, you are right, it's a mistake call them string, I did it because in VB6 I just know strings and not arrays of char. - Beppe
I think you'd either need to use the Declare Function myFunc lib "MyDLL" syntax or write a proper COM interface using BSTRs (unicode strings with a length prefix at word -1) not char[]. - Rup
@Beppe As you know I've been following this thread. Please explain why you can't just use Declare Function? As far as I am aware, you will be able to do this in addition to your tlb trick to workaround the TLS issue. - David Heffernan
@David Do you mean I can use Declare Function combined with the tlb trick? I didn't try it out yet. I thought that declaring functions in that way would have brought the problem back. I should check it. Thanks - Beppe

3 Answers

3
votes

You must use BSTR to use VB6 compatible strings. It is the standard COM string type, it stores Unicode strings in utf-16 encoding, just like the Win32 api.

 int __stdcall myFunc(BSTR filename_in, BSTR filename_out, BSTR* ErrMsg);

You can cast the in args to WCHAR* directly, use WideCharToMultiByte() if you need to convert to char* (best avoided). Use SysFreeString if *ErrMsg is not null to release an existing string before assigning it. Use SysAllocString to allocate the ErrMsg string. It must be a utf-16 string as well, MultiByteToWideChar() if necessary again to convert from char*. Or use a string literal that's prefixed with L, like L"Oops".

2
votes

VB6 has no problems consuming stdcall functions with ANSI strings params. Just use [in] LPSTR filename_in in IDL and the run-time does the UNICODE<->ANSI conversion automagically.

The "magic" works for [out] params too.

0
votes

Thanks to GSerg and wqw I found the solution to this problem:

In the IDL file the char arrays should be declared as LPSTR, so the prototype of the function looks like:

int _stdcall myFunc(LPSTR file_name_in, LPSTR file_name_out, LPSTR ErrMsg)

note that ErrMsg is declared exactly as the other arrays, even if it will contains an output message (readable on the VB6 side).

On the VB6 side the strings should be allocated as:

Dim file_name_in As String * 256
Dim file_name_out As String * 256
Dim ErrMsg As String * 256

Doing so these strings are allocated with a limited size of 256, thus being compatible with the char arrays in the C DLL.

Hope this will help someone else.

Regards,

G.B.