C# P/仅在Vista/Windows Server 2008上调用错误
我的代码通过p/Invoke使用SSPI dll(security.dll)中的方法,该方法在每个测试平台(Windows XP、Windows Server 2003 x86和x64)上都运行良好,但是我们正在迁移到Windows Server 2008的过程中,发现p/Invoke调用正在使过程崩溃 我将以下代码放在一起:C# P/仅在Vista/Windows Server 2008上调用错误,c#,windows-server-2008,pinvoke,C#,Windows Server 2008,Pinvoke,我的代码通过p/Invoke使用SSPI dll(security.dll)中的方法,该方法在每个测试平台(Windows XP、Windows Server 2003 x86和x64)上都运行良好,但是我们正在迁移到Windows Server 2008的过程中,发现p/Invoke调用正在使过程崩溃 我将以下代码放在一起: using System; using System.Runtime.InteropServices; namespace TestPInvoke { clas
using System;
using System.Runtime.InteropServices;
namespace TestPInvoke
{
class Program
{
static void Main(string[] args)
{
try
{
// The following code works on all platforms tested (Windows Server 2003 x86/x64, Windows Server 2008 x64, Windows XP, Windows Vista)
var table1 = (SecurityFunctionTable)Marshal.PtrToStructure(InitReturningPtr(), typeof(SecurityFunctionTable));
Console.WriteLine(table1.dwVersion);
Console.WriteLine(table1.EnumerateSecurityPackages.ToInt64().ToString("x16"));
Console.ReadLine();
// This call crashes only on Windows Server 2008 and Windows Vista (but works fine on XP and 2K3)
var table2 = InitReturningClass();
Console.WriteLine(table2.dwVersion);
Console.WriteLine(table2.EnumerateSecurityPackages.ToInt64().ToString("x16"));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
Console.ReadLine();
}
[DllImport("security.dll", EntryPoint = "InitSecurityInterfaceW")]
public static extern IntPtr InitReturningPtr();
[DllImport("security.dll", EntryPoint = "InitSecurityInterfaceW")]
public static extern SecurityFunctionTable InitReturningClass();
[StructLayout(LayoutKind.Sequential)]
public class SecurityFunctionTable
{
public uint dwVersion;
public IntPtr EnumerateSecurityPackages;
public IntPtr QueryCredentialsAttributes;
// ...omitted for brevity
}
}
}
这个问题也不是孤立于这个特定的DLL或函数,但我尝试过的任何p/Invoke调用,其中本机函数的返回值是指向隐式封送到类中的结构的指针,都会显示出这个问题
由于我有一个功能解决方案(使用Marshal.PtrToStructure),这不是一个主要问题,但我很好奇为什么它在XP和2k3上没有(明显的)问题,而在Vista和2k8上没有,以及是否有任何方法修复类返回方法以避免更丑陋的显式封送。使用
封送。PtrToStructure
是正确的做法。事实上,这在XP/Server2003上运行完全是巧合,因为代码总是有缺陷。编辑:我没有意识到它是一个API函数。不能声明返回结构的函数。P/Invoke封送拆收器将使用CoTaskMemFree()取消分配结构的内存。不起作用,未使用CoTaskMemAlloc()分配它
XP和2003中的堆管理器是宽容的,它只是忽略了错误的发布请求。但不是Vista和2008中的版本,它轰炸了这个程序,因为它显然不正确地使用了内存。重要的是,这些记忆骗局是安全问题
是的,通过将返回类型声明为IntPtr,可以避免p/Invoke封送器释放内存。这是适当的,API函数确实返回指针,而不是结构。需要Marshal.PtrToStructure将指向的结构封送到托管结构
安全API通常像这样麻烦。安全API将指针返回到内部内核安全结构的概念确实有点让人困惑…鉴于WinAPI函数的实现,我不确定上面给出的解决方案是否有效。(我还是试过了,返回时“table”总是空的)。我遗漏了什么吗?啊,我不知道那是API。是的,IntPtr+Marshal.PtrToStructure是调用它的方式。