Приведение BSTR как char * в dll;различные результаты, зависящие от VBA / C # вызывающего - PullRequest
1 голос
/ 10 июня 2010

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

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

Обе они являются надстройками Excel для версий Office, выпущенных до 2007 года и более поздней версии 2007 года и использующих более быстрый 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);
}

Ответы [ 2 ]

1 голос
/ 10 июня 2010

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

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

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

Самое простое решение состоит в том, чтобы метод Test принял параметр char* и удалил аннотацию сортировки в версии C #.

1 голос
/ 10 июня 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...