我似乎無法在從 COM C 程式填充的 C# 程式中獲取位元組陣列。C# 程式包含對 C DLL 的參考,并通過以下方式實體化:
_wiCore = new WebInspectorCoreLib.WICore();
實際通話
uint imageSize = *image byte count*; // set to size of image being retrieved
var arr = new byte[imageSize];
_wiCore.GetFlawImage(1, 0, ref imageSize, out arr);
C IDL:
[id(5)] HRESULT GetFlawImage([in] ULONG flawID, [in] USHORT station, [in, out] ULONG *pImageSize, [out] BYTE *pImageBytes);
這將正確回傳影像大小,但陣列中沒有任何內容。我還嘗試了簽名(pImageBytes 的額外間接級別):
[id(5)] HRESULT GetFlawImage([in] ULONG flawID, [in] USHORT station, [in, out] ULONG *pImageSize, [out] BYTE **pImageBytes);
在 C# 中傳入一個 IntPtr 但這回傳包含影像位元組地址的記憶體地址,而不是影像位元組。
對我做錯了什么有任何想法嗎?
uj5u.com熱心網友回復:
有多種方法可以將陣列從 C 傳回。
例如,您可以像嘗試那樣使用原始位元組陣列。它可以作業,但在 .NET 中不太實用,因為它不是.NET 喜歡的COM 自動化型別。
所以,假設我們有這個 .idl:
interface IBlah : IUnknown
{
HRESULT GetBytes([out] int *count, [out] unsigned char **bytes);
}
這是一個示例本機實作:
STDMETHODIMP CBlah::GetBytes(int* count, unsigned char** bytes)
{
if (!count || !bytes)
return E_INVALIDARG;
*count = numBytes;
*bytes = (unsigned char*)CoTaskMemAlloc(*count);
if (!*bytes)
return E_OUTOFMEMORY;
for (unsigned char i = 0; i < *count; i )
{
(*bytes)[i] = i;
}
return S_OK;
}
還有一個示例 C# 呼叫代碼(請注意,當它不是 COM 自動化型別時,.NET 型別庫匯入器不知道指標之外的任何內容,因此它只是盲目地將引數定義為 IntPtr):
var obj = (IBlah)Activator.CreateInstance(myType);
// we must allocate a pointer (to a byte array pointer)
var p = Marshal.AllocCoTaskMem(IntPtr.Size);
try
{
obj.GetBytes(out var count, p);
var bytesPtr = Marshal.ReadIntPtr(p);
try
{
var bytes = new byte[count];
Marshal.Copy(bytesPtr, bytes, 0, bytes.Length);
// here bytes is filled
}
finally
{
// here, we *must* use the same allocator than used in native code
Marshal.FreeCoTaskMem(bytesPtr);
}
}
finally
{
Marshal.FreeCoTaskMem(p);
}
注意:這在行程外場景中不起作用,因為 .idl 不完整以支持此等。
或者,您可以使用 COM 自動化型別,例如 SAFEARRAY(或包裝 VARIANT)。這也允許您將它與其他語言(例如 VB/VBA、腳本引擎等)一起使用
所以,我們可以擁有這個 .idl:
HRESULT GetBytesAsArray([out] SAFEARRAY(BYTE)* array);
這個示例本機實作(有點復雜,因為 COM 自動化不是針對 C/C ,而是針對 VB/VBA/Scripting 物件......):
STDMETHODIMP CBlah::GetBytesAsArray(SAFEARRAY** array)
{
if (!array)
return E_INVALIDARG;
// create a 1-dim array of UI1 (byte)
*array = SafeArrayCreateVector(VT_UI1, 0, numBytes);
if (!*array)
return E_OUTOFMEMORY;
unsigned char* bytes;
HRESULT hr = SafeArrayAccessData(*array, (void**)&bytes); // check errors
if (FAILED(hr))
{
SafeArrayDestroy(*array);
return hr;
}
for (unsigned char i = 0; i < numBytes; i )
{
bytes[i] = i;
}
SafeArrayUnaccessData(*array);
return S_OK;
}
正如預期的那樣,示例 C# 代碼要簡單得多:
var obj = (IBlah)Activator.CreateInstance(myType);
obj.GetBytesAsArray(out var bytesArray);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/330391.html
