Передать BSTR из функции C++ DLL в приложение VB6

У меня есть этот код в моем приложении VB6:

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

Output.AddItem FileGetParentFolder(FileText.Text)

Вывод — это список, FileText — это текстовое поле, содержащее путь к файлу. Моя C++ DLL содержит эту функцию:

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

где Path определяется как LPCSTR. Аргумент отлично входит в мою DLL, но что бы я ни пытался вернуть, приложение VB6 показывает только мусор. Я попробовал несколько разных методов с SysAllocStringByteLength, приведя аргумент SysAllocString к LPCWSTR и другим вариантам. Либо я вижу только первую букву строки, либо вижу только Y с точками, а не настоящую строку. Кто-нибудь знает, каков реальный метод создания и передачи действительных BSTR с С++ на VB6?


person Felix Dombek    schedule 26.05.2011    source источник


Ответы (2)


Надеюсь, это укажет вам правильное направление. Из памяти...

VB6 использует COM BSTR (символьные строки шириной 2 байта) внутри, но при обмене данными с внешними DLL использует однобайтовые или многобайтовые строки. (Вероятно, UTF-8, но я точно не помню.) Ваш путь typedef к LPCSTR является строкой ANSI, и поэтому вы можете получить ее правильно. Возвращаемое значение, которое вы создаете, представляет собой строку расширенных символов, но VB ожидает строку ANSI. Вам нужно будет использовать WideCharToMultiByte для преобразования возвращаемого значения перед его возвратом.

Кажется немного странным, что VB выполняет это неявное преобразование, но так оно и есть. (Насколько я помню.)

person Ciaran Keating    schedule 26.05.2011
comment
+1 См. также примечания Microsoft по вызову C DLls из VB. Написано для VB5, но никогда не обновлялось для VB6. Однако это на 99,9% актуально для VB6. Приветствую Карла Петерсона, который разместил этот документ на своем замечательном сайте VB6. - person MarkJ; 26.05.2011
comment
VB6 по умолчанию не использует UTF8. Он использует кодировку .NET Encoding.Default (обычно Windows-1252 в Западной Европе). - person Wolfgang Grinfeld; 18.07.2018

Если вы настаиваете на использовании сигнатуры функции, вам нужно подготовить собственную библиотеку типов для VB6, которая включает это

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

В Declares типы параметров As String автоматически преобразуются в строку ANSI, то есть LPSTR. Единственный способ передать/получить строку Unicode (LPWSTR или BSTR) — это использовать объявление функции typelib API.

Помимо этого, вы всегда можете использовать параметры As Long в объявлении и ожидать LPWSTR, но тогда потребителю придется оборачивать строки в StrPtr при каждом вызове функции API.

person wqw    schedule 26.05.2011