2009-04-08 13 views
0

Ich halte einen Access bekommen, wenn die folgenden von einem externen DLL Aufruf:Access während P/Invoke Hilfe

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

, die einen Prototyp hat, dass ich Setup als solche haben:

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

Jetzt , das Argument, das dies verursacht, ist höchstwahrscheinlich der 5. (IntPtr pMapping). Ich habe diesen Code von einer C++ App in C# portiert. Das fünfte Argument oben ist ein Zeiger auf eine Struktur, die auch einen Zeiger auf eine andere Struktur enthält. Unten ist, wie ich diese sctructs Setup:

[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; 
    } 

Die C++ Äquivalent davon sind wie folgt:

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; 

Ich habe ein Gefühl, das ich etwas falsch gemacht haben entweder mit der Portierung über diese Strukturen oder Portierung über der Funktionsprototyp. Eine Marshalling-Ausgabe von Somesort.

Die Funktion ganz oben in diesem Post wird zweimal in meinem Code aufgerufen. Einmal mit pMapping auf Null gesetzt (dies bringt einen Wert in "size"). Der Speicher wird dann unter Verwendung dieses Größenparameters für eine neue Struktur zugewiesen, und die Funktion wird nun erneut aufgerufen, wobei ein Zeiger auf diesen zugewiesenen Speicherplatz für pMapping verwendet wird. (pMapping hat auch einen Zeiger für die andere Struktur, der während dieser Zeit auch etwas Platz zugewiesen wird).

ist der alten C++ Code, der dies erreicht:

ich die richtige Menge an Speicherplatz nicht war die Zuteilung
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); 

ich zunächst dachte, so dass ich den alten C++ Code oben ausprobiert und fand heraus, dass:

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

habe ich die gleiche Prüfung in meinem C# -Code und fanden die folgende:

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

Wir haben hier ein Problem. Die Mapping-Struktur sollte eine Größe von 272 haben, aber ihre einzige 16. Ich denke, ich könnte nur eine schnelle Lösung, ich manuell 272 statt 16 hier zugeordnet, aber es immer noch mit einer AccessViolationException.

Haben Sie eine Idee, wie Sie das beheben können? Oder was könnte noch schief gehen?

Antwort

1

' Prototyp 'war nicht das richtige Wort, ich mag "DLLImport declaration" besser.

Und ich habe es gerade funktioniert.

so in C++:

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

zu 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; 
} 

Ein Zeichen-Array ist kein String und sollte als ein Array von Zeichen behandelt werden .... Wer hätte das gedacht : P

0

Ich habe nicht durch all das gearbeitet, ich fürchte, aber wenn Sie Strukturen mit 'char *' s haben und Sie sie als 'String' marshallen, dann sollten Sie vorsichtig sein dekorieren mit den entsprechenden CharSet = CharSet.Ansi Attributen.

Eine Sache, das zu Ihrem Eintrag hinzuzufügen wäre nützlich, ist der C++ Prototyp für die Funktion (ich würde nicht auf Ihre DLLImport Erklärung als ‚Prototyp‘ beziehen, aber das könnte ich einfach sein.)

1

According to MSDN sollten Sie einen StringBuilder für einen Puffer fester Länge übergeben. Versuchen Sie Folgendes oder eine Variante (ungetestet):

[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

Ich denke, das läuft auf die "Structs kann keine explizite parameterlose Konstruktoren" Einschränkung ... – dlchambers