COM SAFEARRAY GUID возвращается из C ++ в C # - PullRequest
6 голосов
/ 29 июля 2011

В настоящее время я сталкиваюсь с проблемой необходимости передачи SAFEARRAY (GUID) в качестве возвращаемого значения из C ++ в C #.

В настоящее время сторона C # использует dll Interop, сгенерированный из Tlbimp.exe (Импорт библиотеки типов).

IDL:

HRESULT GetGuids(
    [out]SAFEARRAY(GUID)* guids);

Я также пробовал [out, retval]

Сигнатура функции:

HRESULT
WINAPI
MyClass::GetGuids(SAFEARRAY** guids)

Если я использую SafeArrayCreate() или SafeArrayCreateVector():

SAFEARRAY* psa
psa = SafeArrayCreate(VT_CLSID, 1, rgsabound);

, я получаю указатель NULL SAFEARRAY, который должен указывать на E_OUTOFMEMORY, что неверно.

Я обнаружил, что VT_CLSID только для наборов свойств Ole, а не для SAFEARRAY: http://poi.apache.org/apidocs/org/apache/poi/hpsf/Variant.html Это указывает на то, что CLSID равен

Я также пробовал альтернативные способы построения безопасного массивас: SafeArrayAllocDescriptor() и SafeArrayAllocData().

hResult = SafeArrayAllocDescriptor(1, guids)
hResult = SafeArrayAllocData(*guids);

Это позволяет мне создать массив, но при заполнении его SafeArrayPutElement() я получаю HRESULT 0x80070057 (параметр неверен).Вероятно, это связано с тем, что он также принимает параметр VT_CLSID

. Я могу заполнить его вручную с помощью SafeArrayAccessData()

GUID* pData = NULL;
hResult = SafeArrayAccessData(*guids, (void**)&pData);

, но я получаю ошибку со стороны C #:«Значение не попадает в ожидаемый диапазон»

Я не уверен, как выполнить желаемую функциональность возврата SAFEARRAY (GUID) в C # с помощью параметра retval или out.

Кажется, все должно быть просто - в IDL есть много областей, где я уже передаю GUID без каких-либо UDT или сортировки.Все работает нормально, пока мне не нужно передать их в SAFEARRAY.

Любая помощь приветствуется, заранее спасибо

Ответы [ 2 ]

5 голосов
/ 29 июля 2011

Вы абсолютно правы - проблема в том, что VT_CLSID не разрешен ни в VARIANT, ни в SAFEARRAY.Это сводится к тому, что GUID не является типом, совместимым с Automation.

Мне часто нужно делать то же самое, что и вы.Самый простой способ обойти эту проблему - преобразовать GUID в строку, а затем передать SAFEARRAY (VT_BSTR).Это несколько противоречит факту этого преобразования, но я полагаю, вы могли бы принять мнение, что в любом случае происходит маршалинг, и это преобразование является разновидностью маршалинга.

3 голосов
/ 17 февраля 2013

Способ сделать это включает передачу идентификаторов GUID как UDT (пользовательский тип).

Для этого мы используем SAFEARRAY элементов VT_RECORD, которые будут инициализированы с SafeArrayCreateEx. Но сначала мы должны получить указатель на IRecordInfo, который может описать тип.

Поскольку GUID определен в заголовках windows / COM и к нему не прикреплен uuid, мы должны использовать что-то еще, чтобы получить интерфейс IRecordInfo. По сути, есть два варианта: создать структуру, имеющую ту же структуру памяти, что и GUID в вашей собственной TypeLib, или использовать mscorlib :: Guid, определенный в mscorlib.tlb

#import <mscorlib.tlb> no_namespace named_guids

IRecordInfo* pRecordInfo = NULL;
GetRecordInfoFromGuids( LIBID_mscorlib, 1, 0, 0, __uuidof(Guid), &pRecordInfo );

SafeArrayCreateEx( VT_RECORD, 1, &sab, pRecordInfo );
...