I keep getting an AccessViolationException when calling the following from an external DLL:
FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, pMapping, out PagePerSector);
Which has a prototype that I’ve setup as such:
[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);
Now, the argument that is causing this is most likely the 5th one (IntPtr pMapping). I’ve ported this code over from a C++ app into C#. The 5th argument above is a pointer to a struct which also contains a pointer to another struct. Below is how I have these 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; }
The C++ equivalent of these are as follows:
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;
I have a feeling I did something wrong with either porting over these structs, or porting over the function prototype. A Marshaling issue of somesort.
The function all the way at the top of this post gets called twice in my code. Once with pMapping set to null (this puts a value in ‘size’). Memory is then allocated for a new struct using this size parameter and the function is called again now using a pointer to this allocated memory space for pMapping. (pMapping also has a pointer for the other struct which also gets some space allocated during this time).
Here is the old c++ code that accomplished this:
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);
I initially thought I wasn’t allocating the correct amount of space so I tried the old C++ code above and found out that:
sizeof(MAPPING) = 272 and sizeof(PMAPPINGSECTOR) = 40
I did the same check in my C# code and found the following:
Marshal.SizeOf(new Mapping()) = 16 and Marshal.SizeOF(new MappingSector()) = 40
We got a problem here. The Mapping struct should be of size 272, but its only 16. Thinking I could just do a quick fix, I manually allocated 272 instead of 16 here, but it still errored out with an AccessViolationException.
Any idea on how to fix this? Or what might still be going wrong?
‘prototype’ was not the correct word, I like ‘DLLImport declaration’ better.
And I’ve just got it working.
so in C++:
to C#:
A character Array is NOT a string, and should be treated as an array of characters…. Who would have guessed 😛