为什么从应用程序的 32 位编译版本调用本机代码时会出现 AccessViolationException,而不是从 6

本文关键字:AccessViolationException 本机代码 应用程序 编译 为什么 调用 版本 | 更新日期: 2023-09-27 18:31:00

我正在从我的 C# 托管代码调用一些C++本机代码。当从 64 位或 AnyCPU 编译的应用程序加载此 dll 时,一切都完美运行。当它从 32 位应用程序加载时,我在调用 InitializeSecurityContextW 方法时收到 AccessViolationException。本机方法的定义如下:

[DllImport(SECUR32DLL, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
private static extern StatusEnum InitializeSecurityContextW(
    [In] ref HandleStruct handle1,
    [In] IntPtr handle2,
    [In] String str,
    [In] uint flags1,
    [In] uint reserved1,
    [In] uint flags2,
    [In] IntPtr bufferDesc,
    [In] uint reserved2,
    [In, Out] ref HandleStruct handleOut,
    [In, Out] BufferDescriptor bufferDescOut,
    [Out] out uint flagsOut,
    [Out] out long expiryOut);

使用以下结构和枚举:

public struct HandleStruct
{
    private IntPtr Low;
    private IntPtr High;
    public bool IsZero
    {
        return Low == IntPtr.Zero && High == IntPtr.Zero;
    }
}
private enum StatusEnum {
     // Values here.
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
private struct BufferDescriptor
{
    public uint Version;
    public uint Count;
    public IntPtr BufferArray;
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
private struct Buffer
{
    public uint Size;
    public uint Type;
    public IntPtr Data;
}

(简化的)调用代码是:

Buffer[] bufferOut = new Buffer[1];
bufferOut[0].Size = 0;
bufferOut[0].Type = 2; // Token type
bufferOut[0].Data = IntPtr.Zero; // I'm asking the server to allocate this memory (unmanaged).
GCHandle bufferOutPtr = GCHandle.Alloc(bufferOut, GCHandleType.Pinned);
BufferDescriptor bufferDescOut = new BufferDescriptor();
bufferDescOut.Count = 1;
bufferDescOut.Version = 0; // Version number
bufferDescOut.BufferArray = bufferOutPtr.AddrOfPinnedObject();
uint flags1 = // Some flags here including asking the server to allocate memory;
uint flags2 = 0; //data representation
uint flagsOut;
long expiry;
StatusEnum status = InitializeSecurityContextW(
    ref handle1, // From calling method
    IntPtr.Zero, // Null for this call
    str, // From calling method
    flags1,
    0,
    flags2,
    IntPtr.Zero, // Null for this call
    0,
    ref handleOut, // From calling method, currently handleOut.IsZero == true
    bufferDescOut,
    out flagsOut,
    out expiry);
// Clean up code, never reached.
为什么

会发生这种情况,为什么只有 32 位?

为什么从应用程序的 32 位编译版本调用本机代码时会出现 AccessViolationException,而不是从 6

我需要固定我的输出缓冲区描述符并传递地址而不是整个结构。