views:

147

answers:

2

We have a c++ legacy application and have been extending it with c# applets that are invoked using COM from the parent c++ app. They bring up windows that are not modal. Moreover, I think these .NET windows are not proper children of the c++ application, since EnumChildWindows misses them, and EnumWindows finds them. One child-like behavior remains, however, in that if you close the parent c++ app, the c# window will close as well.

My basic problem with all this is that if the user invokes one of these c# applets, then inadvertently clicks the parent (c++) app window, the c# window drops to the background. If the user wants to bring this back to the top, they should be able to just click its icon in the TaskBar. Unfortunately, for some strange reason, it is often necessary to click the TaskBar icon three times! The first time should bring a hidden window to the top, but it doesn't. The second click minimizes the hidden window, and the third restores it successfully.

Has anyone else run across this bug/feature when bridging the legacy->.NET divide? I'm wondering if I can intercept the first click on the taskbar icon for my C# applet, and somehow force it to claw its way back to the top. :-)

I've been experimenting with the following:

  [DllImport("User32.dll")]
  private static extern int ShowWindow(IntPtr hwnd, IntPtr nCmdShow);

but even if I get this working I'll still need to intercept that first mouseclick. Thanks for your help!

+1  A: 

Would it work if the C# windows actually were child windows? It might be possible to accomplish that by passing the parent HWND as an argument to the C# COM object, and then using PInvoke to call SetParent on the C# windows. (I've never done this, but it sounds at least as safe as fighting with ShowWindow and the task bar?)

(Note from the comments in the documetation for SetParent that you might also need to fiddle with the child window's window flags?)

(Depending on the C# window type, it might already have a Handle property you can use; otherwise you could kludge a PInvoke call to FindWindow to get its handle.)

Eric
That sounds promising. I'm traveling tomorrow but will give it a try over the weekend!
SteveL
So I've tried this and it really does turn the C# window into a child of the legacy C++ window. It now sits inside the window area of the assigned parent, and can no longer be minimized to the task bar. Most likely I will now have to manage it within the C++ app. Thanks for the suggestion!
SteveL
// code... [DllImport("User32.dll")] static extern int GetForegroundWindow(); [DllImport("User32.dll")] private static extern int SetParent(int hwndChild, int hwndParent); public void ShowMyFormAsChildOf ( int hwndParent ) { MyForm form = new MyForm(); form.Show(); // immediately call... SetWindowParent( hwndParent ); } private void SetWindowParent(int parenthwnd) { if (0 != parenthwnd) { int handle = GetForegroundWindow(); SetParent(handle, parenthwnd); } }
SteveL
sorry, fmt of code is not preserved, i'll post as an answer, below...
SteveL
A: 
 // Here's the code... 
 [DllImport("User32.dll")]
  static extern int GetForegroundWindow();
  [DllImport("User32.dll")]
  private static extern int SetParent(int hwndChild, int hwndParent);


  public void ShowMyFormAsChildOf ( int hwndParent )
  {
    MyForm form = new MyForm();
    form.Show(); // immediately after .Show(), it is the foreground window!
    SetWindowParent( hwndParent );
  }

  private void SetWindowParent(int parenthwnd)
  {
     if (0 != parenthwnd)
     {
        int handle = GetForegroundWindow();
        SetParent(handle, parenthwnd);
     }
  }
SteveL
Wouldn't IntPtr be safer? HWND is a pointer/handle type, so you'd want it to expand on 64-bit platforms.
ChrisV