tags:

views:

60

answers:

2

I need to enumerate all open windows and get their title, but the problem is that some windows belong to the same process but to a different thread, which is blocked (waiting for a mutex). Therefore I cannot use GetWindowText for windows that belong in my own process as this will result to a SendMessage call which will block my code's execution (as it will be waiting a relpy for the blocked thread).

Btw here is an interesting article on how the GetWindowText works internally: http://blogs.msdn.com/b/oldnewthing/archive/2003/08/21/54675.aspx

As a solution decided to use SendMessageTimeout to the window in order to retrieve its title but I can't make it work. What I am doing is:

[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);

but I always get 0 meaning that the function failed, and sb is always null. Any ideas? Thanks a lot.

+1  A: 

You need to pass string bufer in lParam, and not in lpdwResult. lpdwResult may be NULL or out Int32, it contains result of the message handling. Note that SendMessageTimeout doesn't help to get title of non-responsive window, but prevents caller blocking.

Edit: Interesting point here that PInvoke declaration of SendMessageTimeout depends on the message you want to send. In the case it is necessary to send different messages in the same program, I think it is possible to make several PInvoke declarations calling the same API.

Alex Farber
Thanks mate this did the trick!
mario
+2  A: 

@Alex has given you the correct answer. But since I typed the code already, here is a P/Invoke declaration you can use.

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

Pass your StringBuilder in for the lParam, since WM_GETTEXT fills the buffer specified by the lParam and you can just pass IntPtr.Zero for teh lpdwResult.

Chris Taylor
worked like a charm...
mario