0

I am using below code to open an email item (with specific conditions).
I need after that to maximize the opened outlook email window and set focus for it to be foreground.

Option Explicit
Option Compare Text
Public WithEvents MyItem As Outlook.MailItem
Public EventsDisable As Boolean
Private Sub Application_ItemLoad(ByVal Item As Object)
    If EventsDisable = True Then Exit Sub
    If Item.Class = olMail Then
        Set MyItem = Item
    End If
End Sub
Private Sub myItem_Open(Cancel As Boolean)
    EventsDisable = True
        If MyItem.Subject = "Auto Plan" And Application.ActiveExplorer.CurrentFolder.Name = "MyTemplate" Then
   'Code to maximize the opened outlook email window and set focus for it to be foreground
        End If
    EventsDisable = False
End Sub

the following Windows API function

#If Win64 Then
    Private Declare PtrSafe Function SetForegroundWindow Lib "user32" _
               (ByVal hWnd As LongPtr) As LongPtr
#Else
    Private Declare Function SetForegroundWindow Lib "user32" _
               (ByVal hWnd As Long) As Long
#End If

Public Sub Bring_to_front()
    Dim setFocus As Long
    setFocus = SetForegroundWindow(xxxxxxx.hWnd)
End Sub

thanks for any useful comments and answer.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
Waleed
  • 847
  • 1
  • 4
  • 18

3 Answers3

0

You can use the SetForegroundWindow method which brings the thread that created the specified window into the foreground and activates the window. Keyboard input is directed to the window, and various visual cues are changed for the user. Alternatively you may consider using the Activate method of the Explorer or Inspector classes from the Outlook object model.

To maximize the window you could use the ShowWindow method from Windows API, here is a possible declaration in VBA:

Public Declare Function ShowWindow Lib "user32" _
  (ByVal hwnd As Long, ByVal nCmdSHow As Long) As Long

private SW_MAXIMIZE as Long = 3;
private SW_MINIMIZE as Long = 6;

So, you need to pass a window handle and the SW_MAXIMIZE value as the second parameter to maximize the window. See How to minimize/maximize opened Applications for more information.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • But the mentioned methods and links are C++ or C# – Waleed Apr 23 '22 at 17:27
  • Yes, Windows API is common for all programming languages. I've listed a possible declaration of the `ShowWindow` function in VBA – Eugene Astafiev Apr 23 '22 at 20:50
  • [Foreground activation permission is like love: You can’t steal it, it has to be given to you](https://devblogs.microsoft.com/oldnewthing/20090220-00/?p=19083). – IInspectable Apr 24 '22 at 09:08
0

Call MailItem.Display, then activate the Inspector object by calling Inspector.Activate. Inspector object can be retrieved from MailItem.GetInspector.

One thing to keep in mind is that Windows will not bring a window to the foreground if the parent process is not in the foreground. You would need to use AttachThreadInput function for that - see https://stackoverflow.com/a/17793132/332059

Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
  • `AttachThreadInput` [no longer](https://stackoverflow.com/questions/71437203/proper-way-of-activating-a-window-using-winapi/71448108#comment126297718_71448108) grants you foreground activation permission. – IInspectable Apr 24 '22 at 09:15
  • @IInspectable Hmmm... I just tried a standalone VBS script under Windows 10 (have not tried 11) - both `Inspector.Activate` in OOM and SafeInspector.Activate in Redemption (which uses the above mentioned trick) work properly when Outlook is in the background as long as the inspector is not minimized. – Dmitry Streblechenko Apr 24 '22 at 17:49
0

In order to activate "the opened outlook email message window" you need to "determine its handle". In order to do that you may use its caption.

  1. Please, use the next declarations on top of a standard module (in the declarations area):
 Public Const MyApp As String = "myOutlook", Sett As String = "Settings", wHwnd As String = "Wind_Hwnd" 'changed to be `Public` and keeping the handle

1.a Please copy the next API functions in the same standard module:

#If Win64 Then
    Public Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
                    (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Public Declare PtrSafe Function SetForegroundWindow Lib "user32" _
                                                 (ByVal hwnd As LongPtr) As LongPtr
    Public Declare PtrSafe Function ShowWindow Lib "user32" _
              (ByVal hwnd As LongPtr, ByVal nCmdSHow As Long) As Long
    
     
#Else
    Public Declare Function FindWindow Lib "User32" Alias "FindWindowA" _
        (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Public Declare Function SetForegroundWindow Lib "user32" _
                                             (ByVal hWnd As Long) As Long
    Public Declare Function ShowWindow Lib "user32" _
        (ByVal hwnd As Long, ByVal nCmdSHow As Long) As Long
#End If

The above variables are necessary to supply, save and use the necessary window handle (in/from Registry)

  1. Adapt myItem_Open in the next way:
Private Sub myItem_Open(Cancel As Boolean)
    EventsDisable = True
        If MyItem.Subject = "Auto Plan" And Application.ActiveExplorer.CurrentFolder.Name = "MyTemplate" Then
           'Code to maximize the opened outlook email window and set focus for it to be foreground
           #If Win64 Then
               Dim meHwnd As LongPtr
           #Else
               Dim meHwnd As Long
           #End If
           meHwnd = FindWindow(vbNullString, MyItem.GetInspector.Caption) 'find the necessary window handle
           SaveSetting MyApp, Sett, wHwnd, CStr(meHwnd) 'memorize it, converted to string
        End If
    EventsDisable = False
End Sub

3.1 If the mail window must be shown in foreground from VBA of another application, the declarations and API functions from above, must be also copied on top of the module keeping the necessary (following) sub.

3.2 Copy the next adapted Sub and run it (after showing the necessary mail window in Outlook, of course...):

Sub Bring_to_front()
  Dim winHwnd As String, i As Long
  winHwnd = GetSetting(MyApp, Sett, wHwnd, "No Value")
  If winHwnd <> "No Value" Then
        #If Win64 Then
            Dim mailWindHwnd As LongPtr
            mailWindHwnd = CLngPtr(winHwnd)
        #Else
            Dim mailWindHwnd As Long
            mailWindHwnd = CLng(winHwnd)
        #End If
        SetForegroundWindow mailWindHwnd
        ShowWindow mailWindHwnd, 3
  End If
End Sub

Please, try it and send some feedback.

FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • I am afraid as this question code will be run entirely inside Outlook (I think it can be optimized for this scenario). I adapted your code to be run on my 32Bit office (removed PtrSafe and replaced LongPtr by Long). yes {message window} are now set on top, but `it did not maximized`. and kindly,If I changed the subject of that email message, should I run this sub `Bring_to_front` again or not. – Waleed Apr 25 '22 at 00:32
  • 1
    @Waleed The code has been designed to work in both cases. The code placing the window in foreground may be eve simple (without constants decl.). Having the window handle, it is easy to maximize the window. I did not pay two much attention to this aspect. I will adapt the code to work for both cases related to 64/32 bit. The declaration part must also be conditioned for compiler. In the existing way, not, the handler is found according to the window caption. But I can design a different version, able to read in Registry the necessary handler (as string), but properly converted when to be used. – FaneDuru Apr 25 '22 at 07:40
  • 1
    @Waleed Adapted the code as I said above... But, as I said in a comment to your previous question, I know how to use that proposed version to automatically change the workbook attachment with the modified one, without using API or other not stable solutions. – FaneDuru Apr 25 '22 at 07:59
  • @Waleed 1. If you play (by using mouse cursor or by double clicking the window header) with the window dimensions and run the code, it will open it maximized. If you change its size dimensions **and close it**, it does not have any connection to the above code. It is strictly connected to the way Outlook works and you cannot change that in code. 2. Should I understand that **the above solution does not answer your question, as it is formulated**? – FaneDuru Apr 25 '22 at 15:18
  • I am afraid to say it is a partial answer. on excel I am using on Sub Workbook_Open `ActiveWindow.WindowState = xlMaximized` and that works perfectly with me , I thought `Outlook` has the same property. – Waleed Apr 25 '22 at 19:36
  • @Waleed Then, use it in the same way here... – FaneDuru Apr 25 '22 at 20:05