Tuesday, September 06, 2005

One of the developers has sent me an email asking on how to get the same list of programs that's shown in the "Running Program List" applet on Pocket PC's. I forwarded her to the EnumerateTopWindows function I'd implemented before. But she replied to me that this function enumerates all windows, including Desktop, SIP button etc... So I've added a few checks into this function such as calls to the IsWindow and IsWindowVisible API's. I've also put in a few helper functions:

private static bool CheckForDialogs(ArrayList windowList, string value)

{

      foreach(Window window in windowList)

      {

            if (window.Caption == value)

            {

                  return true;

            }

      }

      return false;

}

 

private static bool CheckExcludeList(string value)

{

      foreach(string name in excludeList)

      {

            if (name == value)

            {

                  return true;

            }

      }

      return false;

}

The first one checks if the window that has the same caption already exists and the second loops through the exclude list of some known system programs:

static string[]  excludeList = {"Desktop", "MS_SIPBUTTON", "Programs"};

So the new version of the EnumerateTopWindows looks like this:

public static Window[] EnumerateTopWindows()

{

      ArrayList windowList = new ArrayList();

      IntPtr hWnd = IntPtr.Zero;

      Window window = null;

      StringBuilder sb = null;

 

      // Get first window

      hWnd = GetActiveWindow();

      hWnd = GetWindow(hWnd, GW_HWNDFIRST);

   

      while(hWnd != IntPtr.Zero)

      {

            // Check if it is a windowm and it is visible

            if(IsWindow(hWnd) && IsWindowVisible(hWnd))

            {

                  IntPtr parentWin = GetParent(hWnd);

                  // Make sure that the window doesn't hav a parent

                  if ((parentWin == IntPtr.Zero))

                  {

                        int length = GetWindowTextLength(hWnd);

                        // Does it have the text caption

                        if (length > 0)

                        {

                              sb = new StringBuilder(length + 1);

                              GetWindowText(hWnd, sb, sb.Capacity);

                              string text = sb.ToString();

                              text = text.Substring(0, text.IndexOf('\0'));

                              // Exclude some known system programs

                              if(!CheckExcludeList(text) && !CheckForDialogs(windowList, text))

                              {

                                    window = new Window();

                                    window.Handle = hWnd;

                                    window.Caption = text;

                                    windowList.Add(window);

                              }

                        }

                  }

            }

            hWnd = GetWindow(hWnd, GW_HWNDNEXT);

      }

      return (Window[])windowList.ToArray(typeof(Window));

}

And the additional P/Invoke declarations:

[DllImport("coredll.dll")]

static extern bool IsWindow(IntPtr handle);

 

 

[DllImport("coredll.dll")]

static extern bool IsWindowVisible(IntPtr handle);

           

And as a bonus here's a way to close the program:

[DllImport("coredll.dll")]

private extern static int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

 

private static int WM_CLOSE  = 0x0010;

 

public static void CloseWindow(Window window)

{

      SendMessage(window.Handle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

}

Here's the updated project:

EnumerateWindowsProjNew.zip (6.51 KB)

9/6/2005 1:35:20 PM (GMT Daylight Time, UTC+01:00)  #     | 
 Thursday, August 18, 2005

The .NetCF doesn't provide implementation for the DropDownWidth property for the ComboBox control. Even though it is just a simple call to send either CB_SETDROPPEDWIDTH or CB_GETDROPPEDWIDTH messages. So, following the extender pattern that I aleady used to create the ListBoxExtender I've created the ComboBoxExtender class that implements the DropDownWidth property:

public class ComboBoxExtender

{

      private ComboBox comboBox;

      private IntPtr handle;

 

      public ComboBoxExtender(ComboBox comboBox)

      {

            this.comboBox = comboBox;

            // Get native handle

            this.comboBox.Capture = true;

            this.handle = GetCapture();

            this.comboBox.Capture = false;

      }

 

      public int DropDownWidth

      {

            get

            {

                  return GetDropDownWidth();

            }

            set

            {

                  SetDropDownWidth(value);

            }

      }

 

      private void SetDropDownWidth(int width)

      {

            SendMessage(handle, CB_SETDROPPEDWIDTH, width, 0);

      }

 

      private int GetDropDownWidth()

      {

            return SendMessage(handle, CB_GETDROPPEDWIDTH, 0, 0);

      }

 

      #region P/Invokes

 

      const int CB_GETDROPPEDWIDTH    =      0x015f;

      const int CB_SETDROPPEDWIDTH    =      0x0160;

      [DllImport("coredll.dll")]

      static extern IntPtr GetCapture();

  

      [DllImport("coredll.dll")]

      static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);

 

      #endregion

}

You would use this class:

private ComboBoxExtender comboExt;

 

comboExt = new ComboBoxExtender(comboBox1);

 

comboExt.DropDownWidth = 250;

 

8/18/2005 6:58:40 PM (GMT Daylight Time, UTC+01:00)  #     |