C# P/仅在Vista/Windows Server 2008上调用错误

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

我的代码通过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
{
    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是调用它的方式。