Как преобразовать IntPtr обратно в объект - PullRequest
4 голосов
/ 08 апреля 2009

Все, это продолжение предыдущего вопроса здесь: C # форматирование внешних параметров функции Dll

Вот конкретно код, который я пытаюсь преобразовать в C #:

FILES_GetMemoryMapping((LPSTR)(LPCTSTR)MapFile, &Size, (LPSTR)MapName, &PacketSize, pMapping, &PagePerSector);
// Allocate the mapping structure memory
pMapping = (PMAPPING)malloc(sizeof(MAPPING));
pMapping->NbSectors = 0;
pMapping->pSectors = (PMAPPINGSECTOR) malloc((Size) * sizeof(MAPPINGSECTOR));

// Get the mapping info
FILES_GetMemoryMapping((LPSTR)(LPCTSTR)MapFile, &Size, (LPSTR)(LPCTSTR)MapName, &PacketSize, pMapping, &PagePerSector);

Функция "FILES_GetMemoryMapping" вызывается дважды, я полагаю, первый раз - для получения размера структуры, а второй - для ее фактического заполнения.

"pMapping" - это указатель на структуру в C ++. В моем коде на C # у меня pMapping как тип IntPtr. Следующая строка, которую я могу преобразовать в:

pMapping = Marshal.AllocHGlobal(Marshal.SizeOf(new UM0516.Mapping()));

С (UM0516.Mapping) структурой. Круто, поэтому я только что выделил место, на которое указывает IntPtr. Теперь для следующей строки ... "pMapping-> NbSectors = 0;"

Как мне предположить войти в выделенное теперь пространство неуправляемой памяти, набрать его как структуру (UM0516.Mapping) и установить один из его членов? Затем удостоверьтесь, что я не слишком с ним связывался, чтобы во второй раз я вызвал «FILES_GetMemoryMapping», теперь он может использовать эту структуру ??

- Хорошо, я воспользовался некоторыми советами, и теперь получил следующее:

Я попытался это сделать, и при первом вызове FILES_GetMemoryMapping я получил исключение «AccessViolationException is unhandled»

Вот что у меня есть:

string filepath = @"C:\blah.blah";
string MapFile = @"D:\blah.blah";
UM0516.Mapping myMapping = new UM0516.Mapping();
IntPtr pMapping = Marshal.AllocHGlobal(Marshal.SizeOf(myMapping));
Marshal.StructureToPtr(myMapping, pMapping, false);
ushort PacketSize = 0;
ushort size = 0;
string MapName = String.Empty;
byte PagePerSector = 0;

uint b7 = UM0516.FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, pMapping, out PagePerSector);

Как вы думаете, это исключение происходит из параметра "pMapping"? Может ли это прийти от чего-то еще, что я прошел?

Ответы [ 2 ]

10 голосов
/ 08 апреля 2009

Чтобы получить IntPtr, вам нужно создать свою структуру, установить любые параметры, которые вам могут понадобиться, выделить память, как у вас уже есть, затем позвонить ..

System.Runtime.InteropServices.Marshal.StructureToPtr(yourStructVariable, pMapping, false);

Это скопирует данные из вашей заполненной структуры в выделенную память.

Чтобы скопировать данные из памяти в новую структуру с именем 'mapping', позвоните ...

UM0516.Mapping mapping = (UM0516.Mapping)System.Runtime.InteropServices.Marshal.PtrToStructure(pMapping, typeof(UM0516.Mapping))
0 голосов
/ 10 июля 2014

Чтобы преобразовать IntPtr обратно в объект, я использовал метод, который делает это:

if (ptrToUnwrap == IntPtr.Zero)
    return null;
GCHandle handle = (GCHandle)ptrToUnwrap;
object handledObj = handle.Target;
if (handles.unfreed.Contains(handle))
    handles.unfreed.Remove(handle);
handle.Free();
return handledObj;

(handles.unfreed - список несвободных GCHandles, которые автоматически освобождаются, когда дескрипторы удаляются или завершаются)

...