RSS 2.0 Feed
RSS 2.0


Atom 1.0 Feed
Atom 1.0

  Creating a IWin32Window from a Win32 Handle 


There are times when you are integrating your .NET applications with other existing applications that you cannot modify and is possibly even non-.NET application. This can often result in problems integrating your .NET application's windows with the other application. However, this can be accomplished. You can easily obtain the handle (HWND) of the other application and convert it to a System.Windows.Forms.IWin32Window which can be used in your .NET application.


Discovering the handle of the running application

There are many ways to discover the running application's handle. The most common way is via p/invoke using the FindWindow Win32API. This is not a bad route, but it does require a DllImport.

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr FindWindow(string ClassName, string WindowText);
//...

IntPtr hwnd = FindWindow("Notepad", null);
if (hwnd != IntPtr.Zero)
{
    // do something with the handle
    //...
}
else
    MessageBox.Show("Notepad is not running.");

This returns the window handle, as an IntPtr, or an IntPtr.Zero if the window is not found. You can specify either a class name or the window text - you don't have to specify both (by setting the other one to null) or you can also specify both if you want. Like I said, there is nothing wrong with this method, I've used it many times.

Another way to discover the handle of the running application is by looking for it's process which you can then obtain it's handle from. This way does not require the use of p/invoke as you can do this completely from within the framework classes. The Process class in the System.Diagnostics namespace includes the methods to find a running process, such as the static GetProcessesByName method. This method returns an array of Processes that match the given name (my example will only use the first one).

using System.Diagnostics;
//...

Process[] procs = Process.GetProcessesByName("Notepad");
if (procs.Length != 0)
{
    IntPtr hwnd = procs[0].MainWindowHandle;
    // do something with the handle
    //...
}
else
    MessageBox.Show("Notepad is not running.");

Now with all of that, the handle itself is of little value to you in your .NET application. Many classes take a IWin32Window as the parameter when specifying the parent or owner of something. You need to wrap the handle in a class that implements IWin32Window to use it within your application and to be able to integrate with the other.


Creating the IWin32Window wrapper class

Creating the wrapper class that implements IWin32Window is simple. The IWin32Window interface contains only a single property that must be implemented to simply expose the underlying handle.

public class WindowWrapper : System.Windows.Forms.IWin32Window
{
    public WindowWrapper(IntPtr handle)
    {
        _hwnd = handle;
    }

    public IntPtr Handle
    {
        get { return _hwnd; }
    }

    private IntPtr _hwnd;
}

Now to use it you just pass the handle of the external window to the constructor and then you can use it where ever you can use an IWin32Window, such as specifying the owner of a MessageBox or a Form shown using ShowDialog, etc. This example uses the IWin32Window wrapper class to display a MessageBox in front of Notepad.

Process[] procs = Process.GetProcessesByName("Notepad");
if (procs.Length != 0)
{
    IntPtr hwnd = procs[0].MainWindowHandle;
    MessageBox.Show(new WindowWrapper(hwnd), "Hello World!");
}
else
    MessageBox.Show("Notepad is not running.");

I do this all the time when integrating with other applications that do not allow this type of integration normally. Add your own custom windows to your accounting software or to some other non-customizable application. Easy enough. Where you take this from here is up to you.




                   



Leave a comment below.

Comments

  1. RoudyBob.NET 3/26/2004 9:28 PM
    Gravatar
  2. AA 5/3/2004 9:17 PM
    Gravatar
    Thanks for the tips,

    Instead of popping up MessagBox, I am using

    myForm.ShowDialog(IntPtr_Other_Application)

    This does not make my form modal on other application.. Pl write..


  3. WindowsCE 6/18/2004 4:01 AM
    Gravatar
    How to get Handle of Form within Windows CE?
  4. Mark Smith 12/17/2004 6:13 AM
    Gravatar
    Very useful - answered the questionI had completely - thanks for sharing the info!
  5. Ravi 3/1/2005 9:41 PM
    Gravatar
    The problem, I am facing is while switching between windows using {alt + tab}. While switching when focus comes to "my application" only dialogbox gets show up. The owner doesn't unless i close the dialog.

    Pls help.
  6. Stefan Frutiger 4/11/2005 1:05 AM
    Gravatar
    Thanks for the WindowWrapper idea! Now my WinForm is owned by a VB6 MDI parent form. Great!
  7. Robert D. 4/11/2005 8:05 PM
    Gravatar
    Thanks for the help. It is exactly what I needed. The Internet is GREAT !!
  8. Shararti 5/7/2005 10:16 PM
    Gravatar
    Hi, it is nice. But please tell me that how could i create a Child Process of any other created process.
    I need to know something like "childProcess.Parent = parentProcess.Handle"

    something like this.
  9. CMDev 5/13/2005 8:40 AM
    Gravatar
    Can this be donw in an asp.net web application.
  10. Aln.Cool 7/19/2005 10:19 PM
    Gravatar
    It's amazing.. I've passed a lot of time searching out for a solution and... THIS IS THE SOLUTION to my problem.
    It's great Thank'you (you've just removed a thorn from my feet [french expression] ).
  11. Prince 12/18/2005 7:17 AM
    Gravatar
    Hi ,

    I want c# code, to save all opened windows applications. when i click a button in my application.And code to set the saving path also.
  12. tez 2/14/2006 4:10 PM
    Gravatar
    I am creating a C# form and I am trying to get it's handle in it's class. Is there a way?

    Thanks!
  13. Neel Tiwari 2/24/2006 6:51 PM
    Gravatar
    Hi,

    I'm sorry if this request is a little off-topic. I'm creating an application for windows CE that gets the text in the URL field (which is actually a combo box) in Internet Explorer.

    I created a similar application in the Win32 platform. I basically used a call to FindWindow to look for an instance of "IEFrame" (its the window class of Internet Explorer); once I found it, the FindWindow API would get a handle to it. I would pass this handle as the "parent window" argument in a FindWindowEx call, and look for the toolbar window. Once I got this, I'd use FindWindowEx again to obtain the address bar's handle, and finally one more time to get the combo box (phew! thanks for bearing with me).

    I used SendMessage to send a WM_GETTEXT message to the combo box. It worked fine, I passed the string into a message box to see if I got it right. So far , so good.

    And then I find out FindWindowEx is NOT supported on Windows CE. Bummer! I can only use FindWindow to get a handle to Internet Explorer on my PDA (the window class in this case is "IExplore"), but I can't search within its child windows, coz there's no API to do it!

    Would anyone be able to help me out? Right now, I'm using a workaround, I used the RemoteSpy tool in VS2005 to get the handle to the combo box in Internet Explorer, and I've hardcoded it into my app, and used it to send messages. I know, it sucks.

    Thanks in advance,
    Neel.
  14. Dave S 3/31/2006 9:40 AM
    Gravatar
    Excellent work. This is totally awesome. I had a little trouble porting the C# code to VB2005 so I'll post in case somebody else needs it.

    Public Class WindowWrapper
    Implements System.Windows.Forms.IWin32Window
    Public Sub New(ByVal handle As IntPtr)
    _hwnd = handle
    End Sub
    Public ReadOnly Property Handle() As IntPtr Implements IWin32Window.Handle
    Get
    Return _hwnd
    End Get
    End Property
    Private _hwnd As IntPtr
    End Class
  15. dark 5/31/2006 7:08 AM
    Gravatar
    ok I have a question with this.

    How can I understand that another application s button is clicked?

    hunterofdarkangel@yahoo.com
  16. dunc 7/28/2006 8:26 AM
    Gravatar
    Gee, all that made sense! Wonders will never cease :)
  17. chmj 8/13/2006 6:35 AM
    Gravatar
    //How I can get the form object from handle ?

    using System;
    using System.Management;
    using System.Diagnostics;
    using System.Windows.Forms;

    public class RemoteConnect
    {
    public static void Main()
    {
    Process[] procs = Process.GetProcessesByName("Notepad");
    if (procs.Length != 0)
    {
    IntPtr hwnd = procs[0].MainWindowHandle;
    }
    else
    Console.WriteLine("Notepad is not running.");

    if (procs.Length != 0)
    {
    IntPtr hwnd = procs[0].MainWindowHandle;
    Control c = Control.FromHandle(hwnd);
    if (c != null) //c is null here
    {
    Console.WriteLine((c as Form).Text);
    }
    else
    {
    Console.WriteLine("Null");
    }
    }

    }
    }
  18. SalesLogixBlog.com 8/31/2006 10:42 AM
    Gravatar
    Something that I do quite often, and have done since early versions of SalesLogix is embed my own applications into the running Sales Client. I recently posted to my main blog about some tips to get started doing this from C#. It really is easy to do (Update: Added sample code in VB.NET).
  19. David Byrne 10/27/2006 8:58 AM
    Gravatar
    Is there a way to get the scrollbar length and the scrollbar position? I'm trying to calculate only the visible size of a page in an external IE window, not including the file menu height and toolbar height. If the page height is smaller then the max resolution I can do, (window height - page size) but is the page is a very long page, 5000px then the calculation get messed up. When I use doc.clientHeight() I get the length of the entire page. If I use doc.scrollHeight() I get the height of the entire page. Once again, I need to get only the viewable height of the window. (without the toolbars and the file menus)
  20. Reny 2/8/2007 6:14 AM
    Gravatar
    That was a very useful blog, thanks a lot
  21. wskanaan 2/20/2007 11:06 PM
    Gravatar
    Question...

    If I used this method to integrate with a running program... would I be able to control text boxes and buttons that exist on the external form programmatically?
  22. Toast 3/13/2007 2:39 AM
    Gravatar
    Hi Guys, I'm trying to do something fairly similar... i have a VBA macro that calls my c# COM object which displays a dialog box. I'm using the WindowWrapper so that the dialog boxes appear as modal to word.

    However, what i'm finding is that AFTER the COM object returns control to word (via button press), the application is active, however the title bar of the applicaiton is not highlighted, so it doesn't APPEAR to be active. However if you type on the keyboard, it appears in word. Clicking and dragging the window still doesn't highlight it.

    If the form is closed by clicking the "x" on the form, control is passed back to word and the title highlighted properly.

    I've also noticed that in the VBA calling code, if i display a message box, then word will highlight properly after the messagebox is gone.

    Any ideas?

    I've put together a proof of concept and in a nutshell, i'm using :

    namespace TestCom
    {
    [Guid("D39E4EC3-2137-4c2e-A8DE-41F962047D14")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IDisplayWindow
    {
    [DispId(1)]
    void ShowWindow();

    }

    [Guid("9AA8E181-6372-4743-869B-0120014D673C")]
    //[ClassInterface(ClassInterfaceType.None)]
    //[ProgId("TestCom.Test")]
    public class DisplayWindow : IDisplayWindow
    {
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr FindWindow(string ClassName, string WindowText);

    public void ShowWindow()
    {
    IntPtr _hwndWord;
    TestWindow myForm;
    myForm = new TestWindow();
    // Use word as the parent window
    _hwndWord = FindWindow("Opusapp", null);

    WindowWrapper myWrapper = new WindowWrapper(_hwndWord);
    myForm.ShowDialog(myWrapper);
    myForm.Dispose();
    myForm = null;
    myWrapper = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
    }
    }
    }

    All the TestWindow form has is 1 button

    private void button1_Click(object sender, EventArgs e)
    {
    this.Hide();
    }
  23. Craig Simpson 4/17/2007 10:08 PM
    Gravatar
    Thanks Ryan. This is EXACTLY what I needed, and I have been thinking about this for the last 4 hours....

    Brilliant!

    Thanks mate,
    Craig
  24. Kumar 7/25/2007 12:57 PM
    Gravatar
    Thanks Ryan, This is what I was looking.
  25. Sonia 10/10/2007 7:43 AM
    Gravatar
    Thanks A LOT Ryan.. Saved my afternoon
  26. Khomsan Ph. 12/17/2007 5:21 AM
    Gravatar
    Thanks for the WindowWrapper, Ryan. It is very simple and easy to use :)
  27. dmihailescu 1/9/2008 3:04 PM
    Gravatar
    don't we already have a wrapper in .net?
    just check System.Windows.Forms.NativeWindow
  28. kawin 6/17/2008 8:17 PM
    Gravatar
    Hi friends,
    i need to retrieve the controls of a running applications(Not the application done by us...Application like Notepad etc) and change the names of individual controls of that running applications..For ex: Changing the Menu item name of a notepad...Any known friends help me...Thanks in advance kawin...My iD is
    kawinhere2001@yahoo.com
  29. Hugh Brown 9/25/2008 11:59 AM
    Gravatar
    I think this works in C# 3.0+:

    public class WindowWrapper : System.Windows.Forms.IWin32Window
    {
    public WindowWrapper(IntPtr ip)
    {
    Handle = ip;
    }

    public IntPtr Handle
    {
    get; private set;
    }
    }
  30. 1/20/2009 12:34 PM
    Gravatar
    handle de programas | hilpers
  31. Arun 2/5/2009 2:21 AM
    Gravatar
    Hi Ryan,

    Thanks for the code. Helped me in what I had to do.
    I would also like to ask you for assistance. When I use the above code and call a form , assigning it's IWin32Owner, the behavior is as expected the first time. When the calling method is called thereafter. the form is not displayed.
    While debugging it I see no reasons for the behavior to change. The called forms OnLoad even is handled and then the control moves back to the next statement of the calling function.
    Any ideas on what could be the reason?

    padmanabhan.arun@gmail dot com

    Thanks.
  32. Fabrizio 3/20/2009 3:02 AM
    Gravatar
    Great!
    Thank you Ryan!
    Finally a grat tip from a non-indian! just kidding: I love tips from... say... Rama Krishna Vavilala (keep writing Rama ;) )
    anyway: be sure to use MainWindowHandle and not symply Handle
    thanks a lot again, really!
  33. Richard 7/16/2009 11:18 AM
    Gravatar
    Great work but... I need something different... the million dollar question is....

    I have one non-managed window's wHnd, what can I do if I need that non-managed window as Form's parent ? something like:

    Form myForm = new Form();
    myForm.Parent = whnd ??? // I need some kind of cast here...

    could you help me please ?
    Thanks in advance.
  34. Ryan Farley 7/16/2009 11:27 AM
    Gravatar
    @Richard - for that you'll need to use the Win32API SetParent. See http://pinvoke.net/default.aspx/user32/SetParent.html

    -Ryan
  35. Richard 7/16/2009 11:50 AM
    Gravatar
    Hey thanks... I had a mistake, sorry.. I need to change the Owner not the Parent, something like:

    Form myForm = new Form();
    myForm.Show( IWin32Window Owner ); //whnd? some kind of cast here...

    Thanks in advance.
  36. Ryan Farley 7/16/2009 12:36 PM
    Gravatar
    @Richard,

    That is what the WindowWrapper class is for in this post. You take it and wrap the other window's handle. Then use that for the owner as you call ShowDialog for your .NET app. Then your form will be modal to the other app.

    -Ryan
  37. Narsi 11/3/2009 12:05 PM
    Gravatar
    Ryan,
    Thanks for sharing a nice piece of code. I had used it to expose MessageBox Method to VB6 via Interop.
    Problem -
    I have a VB6 form which calls this method to display the Message box on a different window say "Windows Explorer" window OR for that matter any other window that my application could show.
    Now the Message box behaves "Modal" on both my VB6 forms from where it is called and the Window whose handle I had specified when showing the Message box.
    Could not figure whats going on?

    Thanks
  38. JAY 11/13/2009 9:43 AM
    Gravatar
    nice blog..the gave gave me a good insight in IntPtr.
    but i have a doubt.

    i have created a MDI container and i am trying to open a MS Word with-in the MDI container. i mean the word document should be the child window within my MDI parent.

    will i be able to do this using the above concept which u had explained.

    Process[] proc = Process.GetProcessesByName("MDIform");
    Process[] procs = Process.GetProcessesByName("Word");
    if (procs.Length != 0)
    {
    IntPtr hWndChild = procs[0].MainWindowHandle;
    IntPtr hWndNewParent = proc[0].MainWindowHandle;
    MDIform.Child = SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    }

  39. Hiren Gujarati 4/10/2010 7:18 AM
    Gravatar
    This is great post.
    As i need to display my form to only Excel application in Excel addin.
    It's working. And also can modify or change in excel sheet.
Comments have been closed on this topic.



 

News


Also see my CRM Developer blog

Connect:              


Sponsor

Sections