从外部DLL调用以下内容时,我一直收到AccessViolationException:
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#中。上面的第五个参数是一个指向结构的指针,该结构还包含指向另一个结构的指针。以下是我如何设置这些结构:
[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;
我感觉我在移植这些结构或移植函数原型时做错了。一些Marshaling问题。
这篇文章顶部的函数在我的代码中被调用两次。将pMapping设置为null(这会将值设置为“size”)。然后使用此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错误。
有关如何解决此问题的任何想法?或者可能还会出现什么问题?
答案 0 :(得分:1)
'prototype'不是正确的单词,我更喜欢“DLLImport声明”。
我刚刚开始工作。
所以在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
答案 1 :(得分: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')
}
}
答案 2 :(得分:0)
我还没有完成所有这些工作,我很害怕,但是如果你有'char *'的结构并且你将它们编组为'string',那么你应该小心装饰具有适当CharSet = CharSet.Ansi属性的东西。
添加到您的帖子中有用的一件事是函数的C ++原型(我不会将您的DLLImport声明称为'原型',但这可能只是我。)