2011-07-28 61 views
4

我目前遇到需要傳遞SAFEARRAY(GUID)作爲從C++到C#的返回值的問題。GUID的COM SAFEARRAY從C++返回到C#

目前C#端正在使用從Tlbimp.exe(類型庫導入程序)生成的Interop dll。

的IDL是:

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

我也試過[出,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()填充當我得到80070057的HRESULT(參數不正確)。這可能是由於它採用VT_CLSID參數以及

我可以手動SafeArrayAccessData()

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

填充它,但我從C#端得到一個錯誤: 「的值不在範圍內預期範圍「

我不知道如何完成通過retval或out參數返回SAFEARRAY(GUID)到C#所需的功能。

它似乎應該很簡單 - 在IDL中有很多地方我已經通過了GUID,沒有任何UDT或編組。一切工作正常,直到我需要通過SAFEARRAY他們。

任何幫助表示讚賞,感謝 提前

回答

3

你是絕對正確的 - 問題是,VT_CLSID沒有在任何VARIANT或SAFEARRAY允許的。歸結爲GUID不是自動化兼容類型。

我經常需要做同樣的事情,你正在嘗試。解決此問題的最簡單方法是將GUID轉換爲字符串,然後傳遞SAFEARRAY(VT_BSTR)。它在一定程度上違背了穀物的做法,但是我認爲你可以認爲無論如何都會進行編組,這種轉換是一種編組方式。

+0

謝謝你,所以沒有辦法做到這一點?我認爲這將是可能的,因爲我已經在使用這種風格:'HRESULT SendGuid( \t \t [in] GUID guid);'在idl中的許多地方傳遞一個GUID。我真的希望保持界面的純潔。它更合約,以避免只使用字符串:( – Steve

+0

我同意,並希望自己這樣做。但是,這是不可能的。原因是ActiveX /自動化是COM的子集,旨在使它容易後期腳本語言通過IDispatch與COM對象通信SAFEARRAY和VARIANT是這個自動化子集的一部分,但VT_CLSID不是。你的SendGuid(GUID)方法不是自動化兼容的,但它仍然是完美的COM。不要讓你的界面自動化兼容,只要你使用SAFEARRAY類型,你付出代價。 –

2

執行此操作的方式涉及將GUID作爲UDT(用戶定義的類型)傳遞。爲此,我們使用一個將用SafeArrayCreateEx初始化的VT_RECORD元素SAFEARRAY。但首先,我們必須得到一個指向IRecordInfo的指針來描述類型。

由於GUID是在Windows/COM頭文件中定義的,並且沒有uuid連接,所以我們必須使用別的東西來獲得IRecordInfo接口。基本上,這兩個選項是創建具有在自己的類型庫相同的內存佈局GUID一個結構或使用的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);