Доступ к неуправляемой памяти по адресу, выделенному в COM / C ++ из C # через Interop - PullRequest
1 голос
/ 18 марта 2012

У нас есть устаревшая COM DLL со следующим упрощенным IDL для некоторого метода:

AllocateMemory( [in] LONG lSize, [out] LONG *pAddr );

Реализация этого метода содержит следующее:

BYTE *pArr = (BYTE*)CoTaskMemAlloc( lSize );  
*pAddr = &pArr;  

Адрес вновь выделенной памятивозвращается в качестве длинного значения вызывающей стороне.

Клиенты C ++, использующие этот COM-объект, могут вызвать этот метод и затем получить доступ к памяти следующим образом:

//---- 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 ); 
//--------------------

Все работает хорошо из C ++ COMклиент.

Та же COM DLL была добавлена ​​в качестве ссылки на проект Visual Studio 2010.
Наша цель - сделать то же самое из клиента C # с помощью 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 );  
//--------------------

Кто-нибудь знает о возможном решении?

Ответы [ 2 ]

0 голосов
/ 18 марта 2012
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 );  
0 голосов
/ 18 марта 2012

Во-первых, вы должны собрать только x86 - этот код не будет работать на 64-битной системе.Во-вторых, вы должны использовать код unsafe для выполнения такого преобразования в C #.

...