如何将Windows API LPTSTR输出作为形式参数输出处理

时间:2015-08-07 21:10:46

标签: c# marshalling user32

我尝试通过调用GetClassName() hWnd上的FindWindowByCaption()来确定窗口的类名。但它不起作用;我看到的所有类名都是垃圾字符(特别是四个问号,然后是一些奇怪的非字母数字字符)。 {I}据我所知,GetClassName()将数据写入调用者的缓冲区。

这是我的代码:

[DllImport("user32.dll", SetLastError = true)]
static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(System.IntPtr ZeroOnly, string lpWindowName);

[DllImport("user32.dll")]
static extern int GetClassName(System.IntPtr hWnd,
                               [param: MarshalAs(UnmanagedType.LPTStr)]
                               System.Text.StringBuilder lpClassName, int nMaxCount);

...

System.IntPtr hWndMyWindow = FindWindowByCaption(System.IntPtr.Zero, "My Window");
if (hWndMyWindow != null)
{
   System.Console.WriteLine("hWndMyWindow = {0}", hWndMyWindow);
   System.Text.StringBuilder lpClassName = new System.Text.StringBuilder(256);
   lpClassName.Length = lpClassName.Capacity - 2;
   int len = GetClassName(hWndMyWindow, lpClassName, lpClassName.Length - 2);
   lpClassName.Length = len; // set length to the actual length of the classname
   System.Console.WriteLine("hWndMyWindow = {0}, classname = {1}", hWndMyWindow, lpClassName.ToString());
}
else
{
   System.Console.WriteLine("No such window.");
}

我做错了什么? lpClassName的{​​{1}}参数是输出...我希望GetClassName()将类名写入GetClassName(),但它无法正常工作。

1 个答案:

答案 0 :(得分:1)

   [param: MarshalAs(UnmanagedType.LPTStr)]

LPTStr并不意味着你的想法。通过编写这些声明的方式,只有UnmanagedType.LPStr可以工作。或者更好的是,完全省略了这个属性,根本没有必要,pinvoke marshaller已经理解了StringBuilder。

您使用这些声明调用了20世纪90年代,您正在使用这些winapi函数的“Ansi”版本。不幸的是[DllImport]的默认值。使用它们没有意义,没有人再运行Windows 98了。 Windows是一个以Unicode操作系统为核心,编写声明以匹配:

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(System.IntPtr hWnd, 
                                   StringBuilder lpClassName, int nMaxCount);

FindWindowByCaption()有点太可爱,只是不要,将null作为第一个参数传递。请注意,您的错误处理存在错误,FindWindow使用IntPtr.Zero失败,而不是null。并且不要忽略GetClassName()的错误处理。只需通过抛出System.ComponentModel.Win32Exception来发出响亮的声音。