Close inspector window immediately when user sends message OUT-538
authorThomas
Tue, 29 Jan 2019 13:42:44 +0100
branchOUT-538
changeset 2557 f586944e61be
parent 2555 6334e58eb55e
child 2559 07557d959c09
Close inspector window immediately when user sends message
Extensions/MailItemExtensions.cs
NativeMethods.cs
ThisAddIn.cs
Wrappers/WatchedWindow.cs
--- a/Extensions/MailItemExtensions.cs	Fri Jan 25 10:31:34 2019 +0100
+++ b/Extensions/MailItemExtensions.cs	Tue Jan 29 13:42:44 2019 +0100
@@ -14,8 +14,9 @@
     /// Contains extensions for the MailItem as well as utility methods specific for pEp.
     /// </summary>
     internal static class MailItemExtensions
-    {
+    {        
         public const string                     USER_PROPERTY_KEY_ORIG_ENTRY_ID         = "origEntryID";
+        public const string                     USER_PROPERTY_KEY_INSPECTOR_CLOSED      = "inspectorClosed";
         public const string                     USER_PROPERTY_KEY_IS_INCOMING           = "isIncoming";
         public const string                     USER_PROPERTY_KEY_IS_MIRROR             = "isMirror";
         public const string                     USER_PROPERTY_KEY_REPLY_ACTION          = "replyAction";
--- a/NativeMethods.cs	Fri Jan 25 10:31:34 2019 +0100
+++ b/NativeMethods.cs	Tue Jan 29 13:42:44 2019 +0100
@@ -13,6 +13,13 @@
         /// </summary>
         internal const int FMFD_RETURNUPDATEDIMGMIMES = 0x00000020;
 
+        /// <summary>
+        /// Defines the Z order of a window in the SetWindowPos method. Places the window at the bottom of the Z order. 
+        /// If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the 
+        /// bottom of all other windows. 
+        /// </summary>
+        internal static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
+
         #region Enumerations
         /// <summary>
         /// Specifies the type of the input event.
@@ -47,6 +54,68 @@
             MouseEventFXDown = 0x0080,
             MouseEventFXUp = 0x0100
         }
+
+        [Flags]
+        internal enum SetWindowPosFlags : uint
+        {
+            /// <summary>If the calling thread and the thread that owns the window are attached to different input queues,
+            /// the system posts the request to the thread that owns the window. This prevents the calling thread from
+            /// blocking its execution while other threads process the request.</summary>
+            /// <remarks>SWP_ASYNCWINDOWPOS</remarks>
+            AsynchronousWindowPosition = 0x4000,
+            /// <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
+            /// <remarks>SWP_DEFERERASE</remarks>
+            DeferErase = 0x2000,
+            /// <summary>Draws a frame (defined in the window's class description) around the window.</summary>
+            /// <remarks>SWP_DRAWFRAME</remarks>
+            DrawFrame = 0x0020,
+            /// <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
+            /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
+            /// is sent only when the window's size is being changed.</summary>
+            /// <remarks>SWP_FRAMECHANGED</remarks>
+            FrameChanged = 0x0020,
+            /// <summary>Hides the window.</summary>
+            /// <remarks>SWP_HIDEWINDOW</remarks>
+            HideWindow = 0x0080,
+            /// <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
+            /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
+            /// parameter).</summary>
+            /// <remarks>SWP_NOACTIVATE</remarks>
+            DoNotActivate = 0x0010,
+            /// <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
+            /// contents of the client area are saved and copied back into the client area after the window is sized or
+            /// repositioned.</summary>
+            /// <remarks>SWP_NOCOPYBITS</remarks>
+            DoNotCopyBits = 0x0100,
+            /// <summary>Retains the current position (ignores X and Y parameters).</summary>
+            /// <remarks>SWP_NOMOVE</remarks>
+            IgnoreMove = 0x0002,
+            /// <summary>Does not change the owner window's position in the Z order.</summary>
+            /// <remarks>SWP_NOOWNERZORDER</remarks>
+            DoNotChangeOwnerZOrder = 0x0200,
+            /// <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
+            /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
+            /// window uncovered as a result of the window being moved. When this flag is set, the application must
+            /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
+            /// <remarks>SWP_NOREDRAW</remarks>
+            DoNotRedraw = 0x0008,
+            /// <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
+            /// <remarks>SWP_NOREPOSITION</remarks>
+            DoNotReposition = 0x0200,
+            /// <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
+            /// <remarks>SWP_NOSENDCHANGING</remarks>
+            DoNotSendChangingEvent = 0x0400,
+            /// <summary>Retains the current size (ignores the cx and cy parameters).</summary>
+            /// <remarks>SWP_NOSIZE</remarks>
+            IgnoreResize = 0x0001,
+            /// <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
+            /// <remarks>SWP_NOZORDER</remarks>
+            IgnoreZOrder = 0x0004,
+            /// <summary>Displays the window.</summary>
+            /// <remarks>SWP_SHOWWINDOW</remarks>
+            ShowWindow = 0x0040,
+        }
+
         #endregion
 
         #region Structures
@@ -186,6 +255,13 @@
                                                     int reserved);
 
         /// <summary>
+        /// Retrieves the window handle to the active window attached to the calling thread's message queue.
+        /// </summary>
+        /// <returns>The handle to the active window attached to the calling thread's message queue or null.</returns>
+        [DllImport("user32.dll")]
+        internal static extern IntPtr GetActiveWindow();
+
+        /// <summary>
         /// Copies the caret's position to the specified Point structure.
         /// </summary>
         /// <param name="point">A Point structure that is to receive the client coordinates of the caret.</param>
@@ -236,6 +312,195 @@
         [DllImport("user32.dll", SetLastError = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         internal static extern bool SetCursorPos(int x, int y);
+
+        /// <summary>
+        ///     Changes the size, position, and Z order of a child, pop-up, or top-level window. These windows are ordered
+        ///     according to their appearance on the screen. The topmost window receives the highest rank and is the first window
+        ///     in the Z order.
+        ///     <para>See https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx for more information.</para>
+        /// </summary>
+        /// <param name="hWnd">C++ ( hWnd [in]. Type: HWND )<br />A handle to the window.</param>
+        /// <param name="hWndInsertAfter">
+        ///     C++ ( hWndInsertAfter [in, optional]. Type: HWND )<br />A handle to the window to precede the positioned window in
+        ///     the Z order. This parameter must be a window handle or one of the following values.
+        ///     <list type="table">
+        ///     <itemheader>
+        ///         <term>HWND placement</term><description>Window to precede placement</description>
+        ///     </itemheader>
+        ///     <item>
+        ///         <term>HWND_BOTTOM ((HWND)1)</term>
+        ///         <description>
+        ///         Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost
+        ///         window, the window loses its topmost status and is placed at the bottom of all other windows.
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>HWND_NOTOPMOST ((HWND)-2)</term>
+        ///         <description>
+        ///         Places the window above all non-topmost windows (that is, behind all topmost windows). This
+        ///         flag has no effect if the window is already a non-topmost window.
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>HWND_TOP ((HWND)0)</term><description>Places the window at the top of the Z order.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>HWND_TOPMOST ((HWND)-1)</term>
+        ///         <description>
+        ///         Places the window above all non-topmost windows. The window maintains its topmost position
+        ///         even when it is deactivated.
+        ///         </description>
+        ///     </item>
+        ///     </list>
+        ///     <para>For more information about how this parameter is used, see the following Remarks section.</para>
+        /// </param>
+        /// <param name="x">C++ ( X [in]. Type: int )<br />The new position of the left side of the window, in client coordinates.</param>
+        /// <param name="y">C++ ( Y [in]. Type: int )<br />The new position of the top of the window, in client coordinates.</param>
+        /// <param name="cx">C++ ( cx [in]. Type: int )<br />The new width of the window, in pixels.</param>
+        /// <param name="cy">C++ ( cy [in]. Type: int )<br />The new height of the window, in pixels.</param>
+        /// <param name="uFlags">
+        ///     C++ ( uFlags [in]. Type: UINT )<br />The window sizing and positioning flags. This parameter can be a combination
+        ///     of the following values.
+        ///     <list type="table">
+        ///     <itemheader>
+        ///         <term>HWND sizing and positioning flags</term>
+        ///         <description>Where to place and size window. Can be a combination of any</description>
+        ///     </itemheader>
+        ///     <item>
+        ///         <term>SWP_ASYNCWINDOWPOS (0x4000)</term>
+        ///         <description>
+        ///         If the calling thread and the thread that owns the window are attached to different input
+        ///         queues, the system posts the request to the thread that owns the window. This prevents the calling
+        ///         thread from blocking its execution while other threads process the request.
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_DEFERERASE (0x2000)</term>
+        ///         <description>Prevents generation of the WM_SYNCPAINT message. </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_DRAWFRAME (0x0020)</term>
+        ///         <description>Draws a frame (defined in the window's class description) around the window.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_FRAMECHANGED (0x0020)</term>
+        ///         <description>
+        ///         Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message
+        ///         to the window, even if the window's size is not being changed. If this flag is not specified,
+        ///         WM_NCCALCSIZE is sent only when the window's size is being changed
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_HIDEWINDOW (0x0080)</term><description>Hides the window.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOACTIVATE (0x0010)</term>
+        ///         <description>
+        ///         Does not activate the window. If this flag is not set, the window is activated and moved to
+        ///         the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
+        ///         parameter).
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOCOPYBITS (0x0100)</term>
+        ///         <description>
+        ///         Discards the entire contents of the client area. If this flag is not specified, the valid
+        ///         contents of the client area are saved and copied back into the client area after the window is sized or
+        ///         repositioned.
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOMOVE (0x0002)</term>
+        ///         <description>Retains the current position (ignores X and Y parameters).</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOOWNERZORDER (0x0200)</term>
+        ///         <description>Does not change the owner window's position in the Z order.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOREDRAW (0x0008)</term>
+        ///         <description>
+        ///         Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies
+        ///         to the client area, the nonclient area (including the title bar and scroll bars), and any part of the
+        ///         parent window uncovered as a result of the window being moved. When this flag is set, the application
+        ///         must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
+        ///         </description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOREPOSITION (0x0200)</term><description>Same as the SWP_NOOWNERZORDER flag.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOSENDCHANGING (0x0400)</term>
+        ///         <description>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOSIZE (0x0001)</term>
+        ///         <description>Retains the current size (ignores the cx and cy parameters).</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_NOZORDER (0x0004)</term>
+        ///         <description>Retains the current Z order (ignores the hWndInsertAfter parameter).</description>
+        ///     </item>
+        ///     <item>
+        ///         <term>SWP_SHOWWINDOW (0x0040)</term><description>Displays the window.</description>
+        ///     </item>
+        ///     </list>
+        /// </param>
+        /// <returns><c>true</c> or nonzero if the function succeeds, <c>false</c> or zero otherwise or if function fails.</returns>
+        /// <remarks>
+        ///     <para>
+        ///     As part of the Vista re-architecture, all services were moved off the interactive desktop into Session 0.
+        ///     hwnd and window manager operations are only effective inside a session and cross-session attempts to manipulate
+        ///     the hwnd will fail. For more information, see The Windows Vista Developer Story: Application Compatibility
+        ///     Cookbook.
+        ///     </para>
+        ///     <para>
+        ///     If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to
+        ///     take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+        ///     SWP_FRAMECHANGED.
+        ///     </para>
+        ///     <para>
+        ///     A window can be made a topmost window either by setting the hWndInsertAfter parameter to HWND_TOPMOST and
+        ///     ensuring that the SWP_NOZORDER flag is not set, or by setting a window's position in the Z order so that it is
+        ///     above any existing topmost windows. When a non-topmost window is made topmost, its owned windows are also made
+        ///     topmost. Its owners, however, are not changed.
+        ///     </para>
+        ///     <para>
+        ///     If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that
+        ///     a window be simultaneously activated and its position in the Z order changed), the value specified in
+        ///     hWndInsertAfter is used only in the following circumstances.
+        ///     </para>
+        ///     <list type="bullet">
+        ///     <item>Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hWndInsertAfter. </item>
+        ///     <item>The window identified by hWnd is not the active window. </item>
+        ///     </list>
+        ///     <para>
+        ///     An application cannot activate an inactive window without also bringing it to the top of the Z order.
+        ///     Applications can change an activated window's position in the Z order without restrictions, or it can activate
+        ///     a window and then move it to the top of the topmost or non-topmost windows.
+        ///     </para>
+        ///     <para>
+        ///     If a topmost window is repositioned to the bottom (HWND_BOTTOM) of the Z order or after any non-topmost
+        ///     window, it is no longer topmost. When a topmost window is made non-topmost, its owners and its owned windows
+        ///     are also made non-topmost windows.
+        ///     </para>
+        ///     <para>
+        ///     A non-topmost window can own a topmost window, but the reverse cannot occur. Any window (for example, a
+        ///     dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay
+        ///     above their owner.
+        ///     </para>
+        ///     <para>
+        ///     If an application is not in the foreground, and should be in the foreground, it must call the
+        ///     SetForegroundWindow function.
+        ///     </para>
+        ///     <para>
+        ///     To use SetWindowPos to bring a window to the top, the process that owns the window must have
+        ///     SetForegroundWindow permission.
+        ///     </para>
+        /// </remarks>
+
+        [DllImport("user32.dll", SetLastError = true)]
+        internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags uFlags);
         #endregion
 
         #region MAPI DLL Imports
--- a/ThisAddIn.cs	Fri Jan 25 10:31:34 2019 +0100
+++ b/ThisAddIn.cs	Tue Jan 29 13:42:44 2019 +0100
@@ -3328,6 +3328,7 @@
                 if (omi?.GetIsSendProcessingEnabled() == true)
                 {
                     bool processMessage = true;
+                    bool closedInspector = (omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_INSPECTOR_CLOSED) != null);
 
                     // If S/MIME is enabled, add pEp header and do not process
                     if (omi.GetIsSMIMEEnabled())
@@ -3460,6 +3461,11 @@
                         {
                             Log.Error("Application_ItemSend: Send failure, " + ex.ToString());
 
+                            if (closedInspector)
+                            {
+                                omi.Display();
+                            }
+
                             // Ask the user to continue (not for automatic messages)
                             bool continueSending = false;
                             if (omi?.GetIsAutoConsume() != true)
--- a/Wrappers/WatchedWindow.cs	Fri Jan 25 10:31:34 2019 +0100
+++ b/Wrappers/WatchedWindow.cs	Tue Jan 29 13:42:44 2019 +0100
@@ -1332,7 +1332,6 @@
                     }
                 }
 
-
                 // Show warning message if needed
                 if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
                     (this.Rating < pEpRating.pEpRatingUnreliable) &&
@@ -1364,6 +1363,18 @@
 
                 if (cancel == false)
                 {
+                    if ((this.Type == WindowType.Inspector) &&
+                        (this.cryptableMailItem.IsInlineResponse == false))
+                    {                        
+                        IntPtr hWnd = NativeMethods.GetActiveWindow();    
+                        NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_BOTTOM, 0, 0, 0, 0, NativeMethods.SetWindowPosFlags.DoNotActivate |
+                                                                                                NativeMethods.SetWindowPosFlags.IgnoreMove |
+                                                                                                NativeMethods.SetWindowPosFlags.DoNotReposition |
+                                                                                                NativeMethods.SetWindowPosFlags.IgnoreResize |
+                                                                                                NativeMethods.SetWindowPosFlags.HideWindow);                        
+                        this.CurrentMailItem.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_INSPECTOR_CLOSED, true, Outlook.OlUserPropertyType.olText);
+                    }
+
                     // Set pEp options if needed
                     if ((this.ForceProtection) &&
                         (this.DisableForceProtection == false))