We have a legacy COM DLL with the following simplified IDL for some method:
AllocateMemory( [in] LONG lSize, [out] LONG *pAddr );
Implementation of this method contains the following:
BYTE *pArr = (BYTE*)CoTaskMemAlloc( lSize );
*pAddr = &pArr;
The address of newly allocated memory is returned as a long value back to the caller.
C++ clients utilizing this COM object can invoke that method and then access the memory as follows:
//---- C++ ----------------
long lSize = 10;
long lAddr;
pCOMObj->AllocateMemory( lSize, &lAddr );
byte **bArray = (byte**)lAddr;
for (int i = 0; i < iSize; i++)
{
printf( "array[%d] = %d\n", i, (*bArray)[i] );
}
// Now deallocate memory.
CoTaskMemFree( *bArray );
//--------------------
All works well from C++ COM client.
The same COM DLL was added as a reference to a Visual Studio 2010 project.
Our goal is to be able to do the same from C# client using Interop:
//---- C# ----------------
int iSize = 10;
int iAddr = 0;
objCOM.AllocateMemory( iSize, ref iAddr );
...
// ??? *UNKNOWN*
// At this point we need to be able to access allocated memory pointed to by iAddr.
// The following does NOT work, i.e., no errors occur but array contents are totally
// different from what has been initialized inside AllocateMemory() method, implying
// that totally different memory is being accessed/copied:
byte [] bArray = new byte [iSize];
IntPtr rAddr = new IntPtr( iAddr );
// Marshal the array from an unmanaged to a managed heap.
Marshal.Copy( rAddr, bArray, 0, iSize );
for (int i=0; i < iSize; i++)
Console.WriteLine( bArray[i] );
// Release the unmanaged array.
Marshal.FreeCoTaskMem( rAddr );
//--------------------
Does anyone know of a potential solution?
There is a ReadIntPtr method to read a native width pointer from an address. It will work on both architectures, unlike ReadInt32
Firstly, you must build as only x86- that code will fail on 64bit. Secondly, you must use unsafe
code to perform such a conversion in C#.
IntPtr bAddr = new IntPtr( iAddr ); // bAddr = (byte**)iAddr
IntPtr rAddr = new IntPtr(Marshal.ReadInt32(bAddr)); //rAddr = (*bAddr);
byte [] bArray = new byte [iSize];
// Marshal the array from an unmanaged to a managed heap.
Marshal.Copy( rAddr, bArray, 0, iSize );
for (int i=0; i < iSize; i++)
Console.WriteLine( bArray[i] );
// Release the unmanaged array.
Marshal.FreeCoTaskMem( rAddr );
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.