Dear community,
I have an issue with COM interop. I need to marshal a C-Style array of interface pointers. I have changed IL to get this array marshaled correctly but I have issues accessing the array elements in the managed code. Below are the IDL as well as my three tries that did not work.
Any suggestions?
Thanks,
dpomt
IDL
[local] HRESULT Next([in] ULONG cElems, [out] ISomeObject *prgElems, [out] ULONG *pcFetched); \
[call_as(Next)] HRESULT RemNext([in] ULONG cElems, [out, size_is(cElems), length_is(*pcFetched)] xxx *prgElems, [out] ULONG *pcFetched); \
Generated IL (tlbimp+ildasm)
instance void RemNext([in] uint32 cElems,
[out] class SomeLib.ISomeObject& marshal( interface ) prgElems,
[out] uint32& pcFetched) runtime managed internalcall
Try #1:
change il to and use then ilasm to recompile:
a) //[in][out] native int& pElemens ==> ref pElements
b) //[out] native int& pElemens ==> out pElements
IntPtr pElements =Marshal.AllocCoTaskMem(iFetchSize * Marshal.SizeOf(typeof(int)));
try
{
while (true)
{
int iFetchSize = 25;
int hr = enumBDO.RemNext((uint)iFetchSize,ref pElements, out uiFetched);
// ^^^ a) ref pElements, b) out pElements
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
IntPtr pCurrent = pElements; // array!
for (int i = 0; i < uiFetched; ++i)
{
ISomeObject bdoTmp = (ISomeObject)Marshal.GetObjectForIUnknown(pCurrent);
//bdoTmp is COMObject but accessing it fails (COMObject is null)
listBDOs.Add(bdoTmp);
pCurrent = (IntPtr)((int)pCurrent +Marshal.SizeOf(typeof(int)));
}
if (hr ==HRESULTS.S_FALSE)
break;
}
}
finally
{
Marshal.FreeCoTaskMem(pElements);
}
è bdoTmp here is a __COMObject, but its content is null
Try #2:
same change of il code as #1 but different code accessing IntPtr
a) //[in][out] native int& pElemens ==> ref pElements
b) //[out] native int& pElemens ==> out pElements
IntPtr pElements =Marshal.AllocCoTaskMem(iFetchSize * Marshal.SizeOf(typeof(int)));
try
{
while (true)
{
int iFetchSize = 25;
int hr = enumBDO.RemNext((uint)iFetchSize,ref pElements, out uiFetched);
// ^^^ a) ref pElements, b) out pElements
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
IntPtr[] managedArray2 = newIntPtr[uiFetched];
Marshal.Copy(pElements, managedArray2, 0, (int)uiFetched);
foreach (IntPtr pin managedArray2)
{
ISomeObject bdoTmp = (ISomeObject)Marshal.GetObjectForIUnknown(p);
// ^^^{"Unknown error (Exception from HRESULT: 0x80004005 (E_FAIL))"}
// System.SystemException {System.Runtime.InteropServices.COMException}
listBDOs.Add(bdoTmp);
}
if (hr ==HRESULTS.S_FALSE)
break;
}
}
finally
{
Marshal.FreeCoTaskMem(pElements);
}
è Marshal.GetObjectForIUnknown(p); will fail here (see error message on comment above)
Try #3:
same change of il code as #1 but different code accessing IntPtr
a) //[in][out] native int& pElemens ==> ref pElements
b) //[out] native int& pElemens ==> out pElements
IntPtr pElements =Marshal.AllocCoTaskMem(iFetchSize * Marshal.SizeOf(typeof(int)));
try
{
while (true)
{
int iFetchSize = 25;
int hr = enumBDO.RemNext((uint)iFetchSize,ref pElements, out uiFetched);
// ^^^ a) ref pElements, b) out pElements
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
ISomeObject[] bdoArr =newISomeObject [iFetchSize];
int hr = enumBDO.RemNext((uint)iFetchSize,ref bdoArr, out uiFetched);// crash here
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
for (int i=0; i<uiFetched; ++i)
{
ISomeObject bdoTmp = bdoArr[i];
listBDOs.Add(bdoTmp);
}
}
}
finally
{
Marshal.FreeCoTaskMem(pElements);
}
è application crashes for call enumBDO.RemNext
Any ideas what I am acutally doing wrong?
I read somewhere to use LPARRAY with sizeparam but did not find a possibily to to this in IL.