1

I have this code in my VB6 app:

Private Declare Function FileGetParentFolder Lib "Z-FileIO.dll" _
(ByVal path As String) As String

Output.AddItem FileGetParentFolder(FileText.Text)

Output is a list, FileText is a text field containing a file path. My C++ DLL contains this function:

extern "C" BSTR ZFILEIO_API FileGetParentFolder(Path p)
{
    try {
        return SysAllocString(boost::filesystem::path(p).parent_path().c_str());
    } catch (...) {
        return SysAllocString(L"");
    }
}

where Path is typedef'd as LPCSTR. The argument comes into my DLL perfectly, but whatever I try to pass back, the VB6 app shows only garbage. I tried several different methods with SysAllocStringByteLength, casting the SysAllocString argument to LPCWSTR and other variants. Either, I only see the first letter of the string, or I see only Y's with dots, just not the real string. Does anyone know what the real method is for creating and passing valid BSTRs from C++ to VB6?

Felix Dombek
  • 13,664
  • 17
  • 79
  • 131

2 Answers2

2

Hopefully this will point you in the right direction. From memory...

VB6 uses COM BSTRs (2-byte wide character strings) internally, but when communicating with external DLLs it uses single- or multi-byte strings. (Probably UTF-8, but I don't remember for sure.) Your Path typedef to LPCSTR is an ANSI string, and that's why you can receive it correctly. The return value you generate is a wide-character string, but VB is expecting an ANSI string. You'll need to use WideCharToMultiByte to convert your return value before returning it.

Seems a little odd that VB does this implicit conversion, but that's the way it is. (As far as I remember.)

Ciaran Keating
  • 2,793
  • 21
  • 19
  • +1 See also [Microsoft's notes on calling C DLls from VB](http://vb.mvps.org/tips/vb5dll.asp). Written for VB5, but never updated for VB6. However it is 99.9% relevant for VB6. All hail Karl Peterson who is hosting this document on his [wonderful VB6 site](http://vb.mvps.org/) – MarkJ May 26 '11 at 11:17
  • VB6 does not use UTF8 by default. It uses the .NET Encoding.Default encoding (typically Windows-1252 in Western Europe). – Wolfgang Grinfeld Jul 18 '18 at 10:02
2

If you insist on using the function signature then you have to prepare a custom typelib for VB6 that includes this

[dllname("Z-FileIO.dll")]
module ZFileIO
{
    [entry("FileGetParentFolder")]
    BSTR FileGetParentFolder ([in] LPWSTR path);
};

In Declares param-types As String are automagically converted to ANSI string, i.e. LPSTR. The only way to pass/receive a unicode string (LPWSTR or BSTR) is by using typelib API function declaration.

Other than that you can always use As Long params in the declaration and expect LPWSTRs but then the consumer will have to wrap strings in StrPtr on every call to the API function.

wqw
  • 11,771
  • 1
  • 33
  • 41