2009-04-08 3 views
0

я получаю сообщение AccessViolationException при вызове вытекающих из внешнего DLL:AccessViolationException при P/Invoke Помощь

FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, pMapping, out PagePerSector); 

который имеет прототип, который я установки как таковые:

[DllImport("Files.DLL", SetLastError = true)] 
    public static extern uint FILES_GetMemoryMapping(
     [MarshalAs(UnmanagedType.LPStr)] 
     string pPathFile, 
     out ushort Size, 
     [MarshalAs(UnmanagedType.LPStr)] 
     string MapName, 
     out ushort PacketSize, 
     IntPtr pMapping, 
     out byte PagesPerSector); 

сейчас , аргумент, который вызывает это, скорее всего, пятый (IntPtr pMapping). Я перенес этот код из C++-приложения в C#. 5-й аргумент выше - указатель на структуру, которая также содержит указатель на другую структуру. Ниже, как у меня есть эти sctructs установка:

[StructLayout(LayoutKind.Sequential)] 
    public struct MappingSector 
    { 
     [MarshalAs(UnmanagedType.LPStr)] 
     public string Name; 
     public uint dwStartAddress; 
     public uint dwAliasedAddress; 
     public uint dwSectorIndex; 
     public uint dwSectorSize; 
     public byte bSectorType; 
     public bool UseForOperation; 
     public bool UseForErase; 
     public bool UseForUpload; 
     public bool UseForWriteProtect; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct Mapping 
    { 
     public byte nAlternate; 
     [MarshalAs(UnmanagedType.LPStr, SizeConst=260)] 
     public string Name; 
     public uint NbSectors; 
     public IntPtr pSectors; 
    } 

C++ эквивалент этих следующим образом:

typedef struct { 
    char*  Name; 
    DWORD  dwStartAddress; 
    DWORD  dwAliasedAddress; 
    DWORD  dwSectorIndex; 
    DWORD  dwSectorSize; 
    BYTE  bSectorType; 
    BOOL  UseForOperation; 
    BOOL  UseForErase; 
    BOOL  UseForUpload; 
    BOOL  UseForWriteProtect; 
} MAPPINGSECTOR, *PMAPPINGSECTOR; 

typedef struct { 
    BYTE   nAlternate; 
    char   Name[MAX_PATH]; // MAX_PATH = 260 
    DWORD   NbSectors; 
    PMAPPINGSECTOR pSectors; 
} MAPPING, *PMAPPING; 

У меня есть чувство, что я сделал что-то не так с любым переносом над этими структурами, или перенос через прототип функции. Маршалинская проблема somesort.

Функция, которая находится в верхней части этого сообщения, дважды вызывается в моем коде. Однажды, когда pMapping установлен в null (это ставит значение в «size»). Затем память выделяется для новой структуры с использованием этого параметра размера, и функция снова вызывается с использованием указателя на это выделенное пространство памяти для pMapping. (pMapping также имеет указатель на другую структуру, которая также получает некоторое пространство, выделенное за это время).

Вот код старого 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)); 
printf("mapsectorsize: <%d>\n", football); 
printf("pMappingsize: <%d>\n", f2); 
// Get the mapping info 
FILES_GetMemoryMapping((LPSTR)(LPCTSTR)MapFile, &Size, (LPSTR)(LPCTSTR)MapName, &PacketSize, pMapping, &PagePerSector); 

Первоначально я думал, что я не выделяя необходимое количество пространства, поэтому я попробовал старый C++ кода, приведенным выше, и выяснил, что:

sizeof(MAPPING) = 272 
and 
sizeof(PMAPPINGSECTOR) = 40 

Я сделал ту же проверку в моих C# код и нашел следующий:

Marshal.SizeOf(new Mapping()) = 16 
and 
Marshal.SizeOF(new MappingSector()) = 40 

У нас проблема. Структура Mapping должна быть размером 272, но ее единственное 16. Думаю, что я мог бы просто быстро исправить, я вручную выделил 272 вместо 16 здесь, но он все еще ошибся с AccessViolationException.

Любая идея о том, как исправить это? Или что еще может пойти не так?

ответ

1

' прототип "не было правильного слова, мне больше нравится" DLLImport declaration ".

И я только что заработал.

так в C++:

typedef struct { 
    BYTE      nAlternate; 
    char      Name[MAX_PATH]; // MAX_PATH = 260 
    DWORD      NbSectors; 
    PMAPPINGSECTOR  pSectors;  
} 

на C#:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] 
public struct Mapping 
{ 
    public byte nAlternate; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=260)] 
    public char[] Name; 
    public uint NbSectors; 
    public IntPtr pSectors; 
} 

символьный массив не является строкой, и следует рассматривать как массив символов .... Кто бы мог подумать : P

0

Я не пробовал все это, я боюсь, но если у вас есть структуры с символом «char», и вы сортируете их как «строку», тогда вы должны быть осторожны украшая вещи соответствующими атрибутами CharSet = CharSet.Ansi.

Одна вещь, которая бы полезно добавить к вашей проводке является прототипом C++ для функции (я бы не относиться к вашей декларации DllImport как «прототип», но это может быть просто меня.)

1

According to MSDN, вы должны передать StringBuilder для буфера фиксированной длины. Попробуйте следующее или какой-либо вариант (непроверенный):

[StructLayout(LayoutKind.Sequential)] 
public struct Mapping 
{ 
    public byte nAlternate; 
    [MarshalAs(UnmanagedType.LPStr, SizeConst=260)] 
    public StringBuilder Name; 
    public uint NbSectors; 
    public IntPtr pSectors; 

    public Mapping() 
    { 
     Name = new StringBuilder(259); 
     //This will be a buffer of size 260 (259 chars + '\0') 
    } 
} 
+0

Я думаю, что это противоречит принципу «Структуры не могут содержать явные без параметров конструкторы» ... – dlchambers

Смежные вопросы