【问题标题】:PInvoke CreateDesktopPInvoke CreateDesktop
【发布时间】:2009-09-17 01:43:09
【问题描述】:

我正在尝试 PInvoke CreateDesktop 以传递标志以由子进程继承桌面的方式。声明如下:

[DllImport("user32", EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags,
                                                  int dwDesiredAccess, [MarshalAs(UnmanagedType.LPStruct)] SECURITY_ATTRIBUTES lpsa);

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }

我使用它如下:

Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
            sa.nLength = Marshal.SizeOf(sa);
            sa.bInheritHandle = 1;
            testDesktopHandle = Win32.CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, Win32.GENERIC_ALL, sa);

不幸的是它不起作用,我收到以下错误:

System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'parameter #6': Invalid managed/unmanaged type combination (this value type must be paired with Struct).

任何想法我做错了什么?

【问题讨论】:

  • 这类问题总是值得检查pinvoke.net
  • 除非你在这里的原因是因为你使用从 pinvoke.net 获得的声明而得到了这个例外...... (举手)
  • @IanRingrose pinvoke.net CreateDesktop 函数的声明仍然存在问题。仅当使用类声明 SECURITY_ATTRIBUTES 并将 null 作为其值传递时,它才有效。

标签: c# .net interop pinvoke


【解决方案1】:

尝试将参数 #6 更改为

static extern IntPtr CreateDesktop(..., [In] ref SECURITY_ATTRIBUTES lpsa);

(编译后不会在运行时抛出异常,但我只使用虚假参数对其进行了测试。)

CreateDesktop的C++声明比较:

HDESK WINAPI CreateDesktop(..., __in_opt LPSECURITY_ATTRIBUTES lpsa);
                                  ↑      ↑ ↑
                                  [In] ref SECURITY_ATTRIBUTES lpsa

LP 代表“长指针”,即LPSECURITY_ATTRIBUTES 是指向SECURITY_ATTRIBUTES 结构的指针。所以在 C# 中你需要通过引用传递你的结构实例(值类型)。

【讨论】:

    【解决方案2】:

    考虑改用以下原型:

        [DllImport("user32", EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags,
                                                  int dwDesiredAccess, IntPtr lpsa);
    

    然后调用它只需创建一个固定句柄:

            GCHandle handle = GCHandle.Alloc(myStruct);
            try {
                IntPtr pinnedAddress = handle.AddrOfPinnedObject();
            }
            finally {
                handle.Free();
            }
    

    这对于调用带有结构的 PInvoke 方法非常有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多