У меня есть функция 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);
}
Причина связана с тем, как вы упорядочиваете данные.
Объявление VB не содержит аннотаций к параметру string
и, следовательно, оно будет маршалировано как обычный параметр char *
. CLR не может выполнять проверку типа для pinvoke и по существу помещает char *
в слот, который ожидает BSTR
.Однако ваш код немедленно преобразует его в char *
и устраняет проблему маршалинга.
В примере C # вы явно указали маршалинг строки
как BSTR
. BSTR
на самом деле является строкой, которая использует под капотом wchar
. Выполняя простое преобразование в char *
, вы по существу преобразуете wchar *
в char *
, что объясняет, почему вы видите только первый символ.
Самое простое решение - просто дать методу Test взять параметр char *
и удалить аннотацию маршалинга в версии C #.
BSTR - это строки Unicode. Как видите, если вы попытаетесь использовать строку LE Unicode в качестве ANSI, вы получите только первую букву (если это ASCII и т. Д.)
Класс CComBSTR ATL / MFC может помочь: вы можете прикрепить BSTR, который вы получить, и я думаю, что он выполнит однобайтовое преобразование за вас. Это также может быть безопаснее использовать, если вы хотите использовать строки Unicode внутри - я не думаю, что BSTR гарантированно оканчиваются нулем (они имеют длину с индексом -1). [править] исправлено dkackman ниже, спасибо.
Лучшим решением было бы преобразовать OtherClass для использования строк Unicode, а не MBCS, или, если он используется только в контексте COM, вы можете преобразовать его даже для использования BSTR. Тогда ваша программа будет лучше поддерживать интернационализацию, расширение ваших рынков и т. Д. Однако это не всегда простое преобразование.