C# 为什么从32位comiled版本的应用程序调用本机代码而不是从64位版本调用本机代码时,会出现AccessViolationException < >我从我的C托管代码中调用了一些C++本地代码。当从64位或任何CPU编译的应用程序加载此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);
使用以下结构和枚举:C# 为什么从32位comiled版本的应用程序调用本机代码而不是从64位版本调用本机代码时,会出现AccessViolationException < >我从我的C托管代码中调用了一些C++本地代码。当从64位或任何CPU编译的应用程序加载此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);,c#,clr,pinvoke,C#,Clr,Pinvoke,使用以下结构和枚举: public struct HandleStruct { private IntPtr Low; private IntPtr High; public bool IsZero { return Low == IntPtr.Zero && High == IntPtr.Zero; } } private enum StatusEnum { // Values here. } [Struc
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位?我需要固定输出缓冲区描述符并传递地址,而不是整个结构。就我个人而言,我不会考虑64位版本似乎没有显示错误这一事实。如果32位与AccessViolationException一起失败,则说明本机代码中存在错误,或者一个或多个对象未正确固定。如果我不得不冒险猜一猜(即,我可能错了很多),64位可能不会显示符号,因为地址空间太大(按大小),代码中的错误可能不会轻易触发访问冲突错误。@VikasGupta我一直认为是这样的。垃圾收集器在32位压缩方面更具攻击性,因为它的内存更少,而且它正在移动未固定的东西,但恰好在64位中没有移动。但是我看不出有什么没有被锁定的东西需要被锁定,可以吗?@VikasGupta也不可能在本机代码中有错误,因为我也有一个本机实现,它直接调用相同的方法(使用非常相似的逻辑),在任何情况下都不会像这样失败。我从来没有处理过很多互操作,因此,我并不声称自己是这里的专家(只有基本知识-希望我可以调试自己的代码,如果需要的话),但您可以将调用InitializeSecurityContextW的代码与pinvoke.net(著名的pinvoke签名网站)上提供的签名和示例代码进行比较-我可以看到的一个区别是您有
[In]ref IntPtr bufferDesc,
vs pinvoke.netIntPtr pInput,
。。i、 e.您通过引用传递IntPtr。。是吗?你的意思是声明ref BufferDescriptor bufferDescOut
vs实际调用bufferDescOut,
编译器没有抱怨你没有通过ref吗?@VikasGupta没有,看起来无效的ref是打字错误。我修正了这个问题以反映真实情况。很抱歉。