title: Using Windows API commands to close child windows
body: <p>--Update 2/29/12 Thanks all for the help. I have gone ahead with calling BringWindowToTop() before using SendMessage() to get the desired behavior. If you have a better method please feel free to post here but otherwise I consider the issue closed. Thanks again!</p>
  <p>--Update 12/9/11 Last night I wrote a crummy little C# project to demonstrate.</p>
  <pre><code>    private void button1_Click(object sender, EventArgs e)
      {    
          //kill the windows which have our documents open, namely EXCEL!
          Process[] processes = Process.GetProcessesByName(&quot;Excel&quot;);
          //find excel
          foreach (Process p in processes)
          {
              //hunt down its children
          U     List&lt;IntPtr&gt; Children = new List&lt;IntPtr&gt;();
              Children = GetChildWindows(p.MainWindowHandle);                
              foreach (IntPtr child in Children)
              {
                  //see if the child has our document
                  foreach (string xo in is_opened_files)
                  {                        
                      if (GetText(child).Contains(xo))
                      {
                          //kill excel's children (oh noes!)
                          SendMessage((uint)child, WM_CLOSE, 0, 0);
                      }
                  }
              }
          }
          //clean up the list of files we opened
          is_opened_files.Clear();
      }
  </code></pre>
  <p>The behavior changes depending on the order of the list object Children&lt;&gt;. If the order of the list matches the Z Order of the child window, meaning the first Child to be evaluated is also the topmost childwindow, then the child accepts and processes the SendMessage() command to close as expected. If you change the order of Children&lt;&gt; so that the items are processed in a different order, only the topmost childwindow closes.</p>
  <p>The point being, I guess, that it seems like only the topmost child will accept and process this command but I cannot find any documentation as to why or even that we should be expecting this behavior at all.</p>
  <p>--end update 12/9/11</p>
  <p>I'm just going to break into the details. I'm new to using the Windows API, but I think I understand at least how to make the calls correctly.</p>
  <p>I am working with an application built in Powerbuilder 11.5. I am reading some blobs from a database and writing them to files in the temp directory, then using ShellExecuteExW to launch the file. The user may launch multiple files or no files. The files may be a mix of .xls(x), .doc(x), .pdf, and various text or image formats (.txt, .jpg...etc)</p>
  <p>So the user can open the documents in their respective application, but then when they close my application I need to tell all the documents I've opened for them to close as well.</p>
  <p>For now, I'm enumerating all the window handles, classes and titles on the system, then searching the titles for the name of a document I have opened for them. I may also verify that the ClassName is something I'm interested in. I'm using FindWindowEx, GetWindowText and GetClassName for this.</p>
  <p>Once I find my file name I grab the associated handle for the window and then use SendMessage with the WM_CLOSE parameter value to tell the window to close.</p>
  <p>This works great when dealing with SDI applications like acrobat reader, MS Word, MS Paint, etc. This fails miserably when working with Excel.</p>
  <p>The issue seems to be that if a user has multiple documents open in Excel, the child will only close if it is the topmost child window.</p>
  <p>I have searched and searched and cannot find where this behavior is coming from. If I call BringWindowToTop immediately before SendMessage then the windows close as expected. Otherwise they just remain. Microsoft documentation seems to imply that sending wm_close to a window is the proper way to close it, regardless of its status as a child/parent or Z order.</p>
  <p>I have also tried using GetAncestor with the GA_PARENT parameter value to get the Child's Parent window, then use SendMessage to notify the Parent window that it should perform WM_MDIDESTROY on the child window in question. Same results as if I SendMessage WM_CLOSE directly to the child. The topmost child will close, but that's it.</p>
  <p>What am I missing?</p>
  <p>Here is some sample code:</p>
  <pre><code>//assume I have already executed the code to
  //get the window handle by searching the title for my file name
  
  //define some constants
  CONSTANT long WM_MDIDESTROY = 545
  CONSTANT long WM_MDIACTIVATE = 546
  CONSTANT long WM_CLOSE = 16
  
  //lul_hWnd = handle to child window, assume we have it already
  //lul_parenthWnd = handle to immediate ancestor of childWindow
  
  uLong lul_hWnd, lul_parenthWnd
  long ll_null
  
  setnull(ll_null)
  
  //Example 1
  //this works when the window is an SDI app or an MDI with maximized children
  if IsWindow(lul_hWnd) then
      SendMessage(lul_hWnd,WM_CLOSE,ll_null, ll_null) 
  end if
  
  //Example 2
  //this seems to work with most instances, including for an MDI with multiple children
  if IsWindow(lul_hWnd) then
      BringWindowToTop(lul_hWnd)
      SendMessage(lul_hWnd,WM_CLOSE,ll_null,ll_null)
  end if
  
  //Example 3
  //The result of this code seems to be the same as the first example
  if IsChild(lul_parenthWnd,lul_hWnd) then
      SendMessage(lul_parenthWnd, WM_MDIDESTROY, lul_hWnd, ll_null)
  end if
  
  //Example 4
  //Adding a preceeding MDIACTIVATE message seems to have no effect
  if IsChild(lul_parenthWnd,lul_hWnd) then
      SendMessage(lul_parenthWnd, WM_MDIACTIVATE, lul_hWnd, ll_null)
      SendMessage(lul_parenthWnd, WM_MDIDESTROY, lul_hWnd, ll_null)
  end if
  </code></pre>
  <p>Also, if you have any ideas on how to better do this I'm all ears. I just really don't want to get into managing OLE servers for all the different applications the users may launch with these files.</p>
  <p>Thanks for your consideration and happy coding :)</p>
  <p>*edit - I originally had links to all the MSDN library entries for the functions and parameters I listed here, but I was forced to remove them because I'm new here.</p>
  <p>Hers's a root link: <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ff657751%28v=VS.85%29.aspx" rel="nofollow noreferrer">MSDN WinAPI documentation</a></p>