我正在尝试这个新功能,并决定使用
dbghelp.dll
的 SymGetModuleInfo64
作为示例。我编写了自定义编组器并且能够运行它(下面是生成的代码),但是当 ConvertToManaged
的结果分配回引用时,它会抛出 AccessViolationException。 ref 参数是否需要特殊处理?目前我只是实例化一个 IMAGEHELP_MODULE64
并设置它的 SizeOfStruct
,然后将其传递给 SymGetModuleInfo64
。
public unsafe partial class Test
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Interop.LibraryImportGenerator", "7.0.10.26716")]
[System.Runtime.CompilerServices.SkipLocalsInitAttribute]
private static partial bool SymGetModuleInfo64(nint hProcess, long ModuleBase64, ref global::Test.Test.IMAGEHELP_MODULE64 imgHelpModule)
{
int __lastError;
global::Test.Test.IMAGEHELP_MODULE64_Marshaller.Unmanaged __imgHelpModule_native;
bool __retVal;
int __retVal_native;
// Marshal - Convert managed data to native data.
__imgHelpModule_native = global::Test.Test.IMAGEHELP_MODULE64_Marshaller.ConvertToUnmanaged(imgHelpModule);
{
System.Runtime.InteropServices.Marshal.SetLastSystemError(0);
__retVal_native = __PInvoke(hProcess, ModuleBase64, &__imgHelpModule_native);
__lastError = System.Runtime.InteropServices.Marshal.GetLastSystemError();
}
// Unmarshal - Convert native data to managed data.
__retVal = __retVal_native != 0;
-----> imgHelpModule = global::Test.Test.IMAGEHELP_MODULE64_Marshaller.ConvertToManaged(__imgHelpModule_native);
System.Runtime.InteropServices.Marshal.SetLastPInvokeError(__lastError);
return __retVal;
// Local P/Invoke
[System.Runtime.InteropServices.DllImportAttribute("dbghelp.dll", EntryPoint = "SymGetModuleInfo64", ExactSpelling = true)]
static extern unsafe int __PInvoke(nint hProcess, long ModuleBase64, global::Test.Test.IMAGEHELP_MODULE64_Marshaller.Unmanaged* imgHelpModule);
}
}
我尝试为参数分配内存,以确保我拥有它,但无论我做什么,我仍然得到
AccessViolationException
。
这是生成上面代码的
Test
类的样子(注意:我只对 LoadedPdbName
感兴趣,所以我没有为整个结构实现编组,但这应该不重要,PInvoke 调用成功):
public unsafe partial class Test
{
[StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(IMAGEHELP_MODULE64_Marshaller))]
private struct IMAGEHELP_MODULE64
{
public int SizeOfStruct;
public long BaseOfImage;
public int ImageSize;
public int TimeDateStamp;
public int CheckSum;
public int NumSyms;
public SymType SymType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string ModuleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ImageName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string LoadedImageName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string LoadedPdbName;
public int CVSig;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 780)]
public string CVData;
public int PdbSig;
public GUID PdbSig70;
public int PdbAge;
public bool PdbUnmatched;
public bool DbgUnmatched;
public bool LineNumbers;
public bool GlobalSymbols;
public bool TypeInfo;
public bool SourceIndexed;
public bool Publics;
public int MachineType;
public int Reserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct GUID
{
public int Data1;
public ushort Data2;
public ushort Data3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] data4;
}
[Flags]
private enum SymType : uint
{
SymNone,
SymCoff,
SymCv,
SymPdb,
SymExport,
SymDeferred,
SymSym,
SymDia,
SymVirtual,
}
[CustomMarshaller(typeof(IMAGEHELP_MODULE64), MarshalMode.Default, typeof(IMAGEHELP_MODULE64_Marshaller))]
private static unsafe class IMAGEHELP_MODULE64_Marshaller
{
[StructLayout(LayoutKind.Explicit)]
public ref struct Unmanaged
{
[FieldOffset(0)] public int SizeOfStruct;
[FieldOffset(580)] public fixed byte LoadedPdbName[256];
}
public static Unmanaged ConvertToUnmanaged(IMAGEHELP_MODULE64 managed)
{
return new Unmanaged
{
SizeOfStruct = managed.SizeOfStruct
};
}
public static IMAGEHELP_MODULE64 ConvertToManaged(Unmanaged unmanaged)
{
return new IMAGEHELP_MODULE64
{
LoadedPdbName = AnsiStringMarshaller.ConvertToManaged(unmanaged.LoadedPdbName)
};
}
}
[LibraryImport("dbghelp.dll", StringMarshalling = StringMarshalling.Utf8, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SymGetModuleInfo64(nint hProcess, long ModuleBase64,
ref IMAGEHELP_MODULE64 imgHelpModule);
}
其使用方式如下:
var moduleInfo = new IMAGEHELP_MODULE64();
moduleInfo.SizeOfStruct = Marshal.SizeOf(moduleInfo);
if (!SymGetModuleInfo64(_processPtr, _baseOfDll, ref moduleInfo))
throw new Win32Exception(Marshal.GetLastWin32Error());
您不能忽略结构中的其余数据。您告诉本机函数有 1680(?) 个字节可供写入,但实际上要少得多。因此,C# 没有分配足够的空间,这意味着缓冲区溢出,清除了堆栈的其余部分,可能还清除了返回指针和参数。
注意结构体的大小实际上应该是 912 字节,因为
CVData
实际上是一个指针。
至少在末尾添加一个保留字段:
[StructLayout(LayoutKind.Explicit)]
public ref struct Unmanaged
{
[FieldOffset(0)] public int SizeOfStruct;
[FieldOffset(580)] public fixed byte LoadedPdbName[256];
[FieldOffSet(836)] private fixed byte Reserved[76];
}
并且:
[MarshalAs(UnmanagedType.LPStr, SizeConst = 780)]
public string CVData;