Кастинг BSTR как символ* в dll; различные результаты depnding на вызывающей стороне VBA/C#

У меня есть функция dll, которая берет параметры BSTR. Они сняты как символ* прежде чем быть используемым для других вещей.

Когда dll называют из кода VBA, это работает. Однако, когда это называют из кода C#, только на первый символ указывают.

Оба из них являются дополнениями Excel для пред2007 и 2007 + версии Office, которые называют в более быстрый C++ AddIn. Они называют его непосредственно, не через Excel.

Объявление функции VBA:

Private Declare Function Test Lib "ExcelAddIn.xll" (ByVal param As String) As String

Объявление функции C#:

[DllImport("ExcelAddIn.xll", CharSet=CharSet.Ansi)]
[return:MarshalAs(UnmanagedType.BStr)]
private static extern string Test([MarshalAs(UnmanagedType.BStr)] string param);

При отладке dll и наблюдении входа значения BSTR, они, кажется, корректны от обоих; просто C# единственные броски первый символ.

Charset=CharSet.Unicode не имеет никакого значения.

Код C++.

BSTR __stdcall Test(BSTR param)
{
char* Param= "";

if(param!= NULL)
    Param= (char*)param;

    return OtherClass.DoOtherStuff(Param);
}
1
задан Community 11 January 2019 в 13:49
поделиться

2 ответа

Причина связана с тем, как вы упорядочиваете данные.

Объявление VB не содержит аннотаций к параметру string и, следовательно, оно будет маршалировано как обычный параметр char * . CLR не может выполнять проверку типа для pinvoke и по существу помещает char * в слот, который ожидает BSTR .Однако ваш код немедленно преобразует его в char * и устраняет проблему маршалинга.

В примере C # вы явно указали маршалинг строки как BSTR . BSTR на самом деле является строкой, которая использует под капотом wchar . Выполняя простое преобразование в char * , вы по существу преобразуете wchar * в char * , что объясняет, почему вы видите только первый символ.

Самое простое решение - просто дать методу Test взять параметр char * и удалить аннотацию маршалинга в версии C #.

1
ответ дан 2 September 2019 в 23:51
поделиться

BSTR - это строки Unicode. Как видите, если вы попытаетесь использовать строку LE Unicode в качестве ANSI, вы получите только первую букву (если это ASCII и т. Д.)

Класс CComBSTR ATL / MFC может помочь: вы можете прикрепить BSTR, который вы получить, и я думаю, что он выполнит однобайтовое преобразование за вас. Это также может быть безопаснее использовать, если вы хотите использовать строки Unicode внутри - я не думаю, что BSTR гарантированно оканчиваются нулем (они имеют длину с индексом -1). [править] исправлено dkackman ниже, спасибо.

Лучшим решением было бы преобразовать OtherClass для использования строк Unicode, а не MBCS, или, если он используется только в контексте COM, вы можете преобразовать его даже для использования BSTR. Тогда ваша программа будет лучше поддерживать интернационализацию, расширение ваших рынков и т. Д. Однако это не всегда простое преобразование.

1
ответ дан 2 September 2019 в 23:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: