Getting Outlook Window from VSTO Addin

3.3k views Asked by At

I have an Outlook 2013 VSTO addin. I want to center my saveFileDialog that I create. To do this you need to pass it a Window object of the parent. I'm not sure if IWin32Window and Window are the same, but here's what I have.

public IWin32Window getWindowHandle()
{
    dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
    IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
    IWin32Window win = Control.FromHandle(outlookHwnd);

    return win;
}

The SaveFileDialog.ShowDialog(Window) method takes a window. Can I pass it the IWin32Window? Is there a way to get the Window object from the handler other than Control.FromHandle?

Any criticisms would be welcome.

Thanks

EDIT:

Oh and the helper class for that function:

public class OfficeWin32Window : IWin32Window
{
   [DllImport("user32")]
   public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

   IntPtr _windowHandle = IntPtr.Zero;

   public IntPtr Handle
   {
      get { return _windowHandle; }
   }

   public OfficeWin32Window(object windowObject)
   {
      string caption = windowObject.GetType().InvokeMember("Caption", System.Reflection.BindingFlags.GetProperty, null, windowObject, null).ToString();

   // try to get the HWND ptr from the windowObject / could be an Inspector window or an explorer window
   _windowHandle = FindWindow("rctrl_renwnd32\0", caption);
   }
}

I was given this code, so I do have a side question about it:
What does FindWindow("rctrl_renwnd32\0", caption) do? I don't get it at all. Especially the "rctrl_renwnd32\0" part.

EDIT:

New function with IOleWindow class:

    public IOleWindow getWindowHandle()
    {
        dynamic activeWindow = Globals.ThisAddIn.Application.ActiveWindow();
        IOleWindow win = activeWindow as IOleWindow;
        window = win.GetWindow();
        //IntPtr outlookHwnd = new OfficeWin32Window(activeWindow).Handle;
        //IWin32Window wind = Control.FromHandle(outlookHwnd);

        return window;
    }

EDIT2:

My updated logic, I removed the function and added this in the place I need tthe handle:

Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win = winh.GetWindow();

EDIT3:

Restructured:

Inspector currentObject = Globals.ThisAddIn.Application.ActiveInspector();
var winh = currentObject as IOleWindow;
IntPtr win;
winh.GetWindow(out win);
1

There are 1 answers

3
Eugene Astafiev On BEST ANSWER

The FindWindow method retrieves a handle to the top-level window whose class name and window name match the specified strings. The first parameter specifies the window class name. The second parameter is the window name (the window's title). If this parameter is NULL, all window names match.

Instead of using the FindWindow function you need to cast the Explorer or Inspector window to the IOleWindow interface and use the GetWindow method to get the window handle.

 /// <summary>
 /// Implemented and used by containers and objects to obtain window handles 
 /// and manage context-sensitive help.
 /// </summary>
 /// <remarks>
 /// The IOleWindow interface provides methods that allow an application to obtain  
 /// the handle to the various windows that participate in in-place activation, 
 /// and also to enter and exit context-sensitive help mode.
 /// </remarks>
 [ComImport]
 [Guid("00000114-0000-0000-C000-000000000046")]
 [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
 public interface IOleWindow
 {
     /// <summary>
     /// Returns the window handle to one of the windows participating in in-place activation 
     /// (frame, document, parent, or in-place object window).
     /// </summary>
     /// <param name="phwnd">Pointer to where to return the window handle.</param>
     void GetWindow (out IntPtr phwnd) ;

     /// <summary>
     /// Determines whether context-sensitive help mode should be entered during an 
     /// in-place activation session.
     /// </summary>
     /// <param name="fEnterMode"><c>true</c> if help mode should be entered; 
     /// <c>false</c> if it should be exited.</param>
     void ContextSensitiveHelp ([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode) ;
 }

An instance of the IWin32Window interface is used to specify the parent window handle for the Show or ShowDialog methods.