如何在C#中使用SendMessageTimeout获取窗口标题

时间:2010-09-07 13:20:17

标签: c# winapi

我需要枚举所有打开的窗口并获取它们的标题,但问题是某些窗口属于同一个进程但属于另一个被阻塞的线程(等待互斥锁)。因此,我不能将GetWindowText用于属于我自己进程的窗口,因为这将导致SendMessage调用,这将阻止我的代码执行(因为它将等待被阻塞线程的relpy)。

这是一篇关于GetWindowText如何在内部工作的有趣文章:http://blogs.msdn.com/b/oldnewthing/archive/2003/08/21/54675.aspx

作为一个解决方案决定使用SendMessageTimeout到窗口以检索其标题但我无法使其工作。我在做的是:

[DllImport("User32.dll")]
public static extern int SendMessageTimeout(
  IntPtr hWnd, 
  int uMsg, 
  int wParam, 
  int lParam, 
  int fuFlags, 
  int uTimeout, 
  out StringBuilder lpdwResult);

...

StringBuilder sb = new StringBuilder(256);
int result = Win32API.SendMessageTimeout(
  hWnd, 
  0x0D /*WM_GETTEXT*/, 
  256, 
  0, 
  10 /*SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG*/, 
  500, 
  out sb);

但是我总是得到0表示函数失败,而sb总是为null。 有任何想法吗? 非常感谢。

2 个答案:

答案 0 :(得分:6)

@Alex给了你正确的答案。但是因为我已经输入了代码,所以这里有一个你可以使用的P / Invoke声明。

[DllImport("User32.dll", SetLastError=true)] 
public static extern int SendMessageTimeout( 
  IntPtr hWnd,  
  uint uMsg,  
  uint wParam,
  StringBuilder lParam,  
  uint fuFlags,  
  uint uTimeout,  
  IntPtr lpdwResult);

将你的StringBuilder传递给lParam,因为WM_GETTEXT填充了lParam指定的缓冲区,你可以通过IntPtr.Zero来传递lpdwResult。

答案 1 :(得分:1)

您需要在lParam中传递字符串缓冲,而不是在lpdwResult中传递。 lpdwResult可以是NULL或Int32,它包含消息处理的结果。请注意,SendMessageTimeout无助于获取非响应窗口的标题,但会阻止调用者阻止。

编辑: 有趣的是,SendMessageTimeout的PInvoke声明取决于您要发送的消息。在必须在同一程序中发送不同消息的情况下,我认为可以使多个PInvoke声明调用相同的API。