title: Do Windows API EnumWindows and EnumChildWindows functions behave differently in Windows XP and 7
body: <p>I am using 2 Windows API exported functions from c#.NET 4.0.</p>
  
  <pre><code>private const string WINDOW_EXCEL7 = "XLMAIN";
  private const string CHILDWINDOW_XLMAIN = "EXCEL7";
  </code></pre>
  
  <p>I am searching for windows titles of Excel main windows' child windows (Excel has an MDI window of class XLMAIN containing 0, 1 or more child windows with EXCEL7 window class).</p>
  
  <p>The goal is to find if a an excel workbook is being opened in any instances of Excel application. I did it by finding all XLMAIN IntPtr (pointers) and traversing children until I get a IntPtr with EXCEL7 window class at which point I can read child windows title and determine if a file is opened.</p>
  
  <p>Basically this works on Windows XP, but not on Windows 7. I didn't try in Windows Vista.
  What has changed? Can someone debug the issue since I don't have Windows 7.
  Thanks
  Rad</p>
  
  <pre><code>using System;
  using System.Text;
  using System.Runtime.InteropServices;
  using System.Diagnostics;
  
  namespace ExcelChildWindowsTitle
  {
      public static void Main(string[] args)
      {
          //XLMAIN/EXCELDESK/EXCEL7 as seen by Spy++ VS 2010 utility
          //IntPtr hWnd = WndSearcher.SearchForWindow("XLMAIN", "EXCEL7", "icui-20110331.xls", ref workbookTitle);
          //bool excelProofFound = WindowTitleSearcher.SearchForWindow("XLMAIN", "EXCEL7", "testfileopenedinEXCEL.xls", ref workbookTitle);
  
          bool excelProofFound = WindowTitleSearcher.SearchForWindow("icui-20110331.xls");
          if (excelProofFound)
              Console.Write(":)))))))) Proof File opened in an Excel process;");
          else
          {
              Console.Write(":|Proof File not found");
          }
      }
  
  public static class WindowTitleSearcher
  {
      private const string WINDOW_EXCEL7 = "XLMAIN";
      private const string CHILDWINDOW_XLMAIN = "EXCEL7";
  
      public static bool SearchForWindow(string title)
      {
          SearchData sd = new SearchData { Wndclass = WINDOW_EXCEL7, ChildWndclass = CHILDWINDOW_XLMAIN, ChildTitle = title, WorkbookTitle = String.Empty};
          EnumWindows(new EnumWindowsProc(EnumProc), ref sd);
          return (int)sd.hWnd &gt; 0;
      }
  
      private static bool EnumProc(IntPtr hWnd, ref SearchData data)
      {
          const bool directOnly = false;
          // Check classname and title 
          // This is different from FindWindow() in that the code below allows partial matches
          StringBuilder sb1 = new StringBuilder(1024);
          GetClassName(hWnd, sb1, sb1.Capacity);
          Debug.WriteLine(sb1.ToString());
          if (sb1.ToString().StartsWith(data.Wndclass))
          {
              RecursiveEnumChildWindows(hWnd, directOnly, ref data);
              if ((int)data.hWnd &gt; 0)
              {
                  // Found the wnd, halt enumeration
                  return false;
              }
          }
          return true;
      }
  
      private static void RecursiveEnumChildWindows(IntPtr parentHwnd, bool directOnly, ref SearchData data)
      {
          EnumChildWindows(parentHwnd, delegate(IntPtr hwnd, ref SearchData data1)
          {
              bool add = true;
              if (directOnly)
              {
                  add = GetParent(hwnd) == parentHwnd;
              }
  
              StringBuilder sb1 = new StringBuilder(1024);
              GetClassName(hwnd, sb1, sb1.Capacity);
              Debug.WriteLine("Child:" + sb1.ToString());
  
              if (add)
              {
  
                  if (sb1.ToString().StartsWith(data1.ChildWndclass))
                  {
                      sb1 = new StringBuilder(1024);
                      //Window Caption
                      GetWindowText(hwnd, sb1, sb1.Capacity);
                      if (sb1.ToString().Contains(data1.ChildTitle))
                      {
                          data1.hWnd = hwnd;
                          data1.WorkbookTitle = sb1.ToString();
                          return false; // Found the wnd, halt enumeration
                      }
                  }
              }
              return true;
          }, ref data);
      }
  
      private struct SearchData
      {
          // You can put any vars in here...
          public string Wndclass;
          public string ChildWndclass;
          public string ChildTitle;
          public IntPtr hWnd;
          public string WorkbookTitle;
      }
      # region Windows API declarations
      private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
  
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);
  
      //private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, [MarshalAsAttribute(UnmanagedType.Struct)] ref SearchData data);
  
      [DllImport("user32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
  
      [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
      public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
  
      [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
      private static extern IntPtr GetParent(IntPtr hWnd);
  
      [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
      public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
      # endregion
  }
  }
  </code></pre>