Dmitry Streblechenko \(MVP\) said:
This is a Windows feature as of Windows 2000 - background applications
cannot activate their windows by calling SetForegroundWindow(). Your code
needs to attach itself to the currently active window (even if it is in
another process), call SetForegroundWindow (you will now be allowed to set
the foreground window), then detach itself. To get the window handle of an
Outlook explorer, you need to use IOleWindow interface, then call
IOleWindow::GetWindow().
In Delphi:
Explorer.Display;
if S_OK = IUnknown(Explorer).QueryInterface(IOLEWindow, OW) then begin
if S_OK = OW.GetWindow(wnd) then begin
ForceForegroundWindow(wnd);
end;
OW := nil;
end;
function ForceForegroundWindow(hWnd: THandle): BOOL;
var hCurWnd: THandle;
begin
hCurWnd := GetForegroundWindow;
AttachThreadInput(
GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, True);
Result := SetForegroundWindow(hWnd);
AttachThreadInput(
GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, False);
end;
Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
Dmitry,
Thank you very much for your code example. It was just what I needed
to get started. I don't speak Delphi, but equipped with your
explanation and sample code I was able to search for similar VB source
and I have my code working now.
I was unsure of what to do with IOLEWindow/etc., but based on another
post of yours elsewhere I seized on using the variable Outlook caption
to help FindWindow locate the Outlook window, so I don't need a VB
equivalent of the Delphi IOLEWindow code.
Your code led me to the ForceFore VB source at:
http://www.mvps.org/vb/index2.html?samples.htm
That code was very helpful, and clearly mapped onto your Delphi code.
I did run into a problem where Outlook would still not necessarily be
the top window when my new code ran, depending on the order in which
other applications were launched. But I added a call to Win32
function BringWindowToTop() and that was the last piece needed to make
it all work.
I have included my code below for future readers. It works on my
bench with Outlook 2000 running under Windows 98. I still need to
test it on other Windows versions running other Outlook versions.
Thanks.
Jim
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function AttachThreadInput Lib "user32" _
(ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As
Long) _
As Long
Private Declare Function GetForegroundWindow Lib "user32" _
() As Long
Private Declare Function SetForegroundWindow Lib "user32" _
(ByVal hWnd As Long) As Long
Private Declare Function BringWindowToTop Lib "user32" _
(ByVal hWnd As Long) As Long
Private Declare Function IsIconic Lib "user32" _
(ByVal hWnd As Long) As Long
Private Declare Function ShowWindow Lib "user32" _
(ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Const SW_SHOW = 5
Private Const SW_RESTORE = 9
Public Sub MakeOutlookForeground(objOutlook As Outlook.Application)
On Error Resume Next
'MS Office Class Names for Outlook
'---------------------------------
'Outlook 97 rctrl_renwnd32
'Outlook 98 rctrl_renwnd32
'Outlook 2000 rctrl_renwnd32
'Outlook XP rctrl_renwnd32
Dim lngHwnd As Long
'Find window by caption since Outlook title changes with current
folder.
lngHwnd = FindWindow("rctrl_renwnd32",
objOutlook.ActiveExplorer.Caption)
If lngHwnd = 0 Or lngHwnd = GetForegroundWindow() Then
'Could not find Outlook window, or Outlook is already foreground.
Exit Sub
End If
Dim lngThreadForegnd As Long
Dim lngThreadOutlook As Long
'Get thread pid for current foreground window.
lngThreadForegnd = GetWindowThreadProcessId(GetForegroundWindow,
ByVal 0&)
'Get thread pid for Outlook.
lngThreadOutlook = GetWindowThreadProcessId(lngHwnd, ByVal 0&)
If lngThreadForegnd <> lngThreadOutlook Then
'Attach threads to share input states so can control focus.
AttachThreadInput lngThreadForegnd, lngThreadOutlook, True
'Put Outlook in foreground and activate window.
SetForegroundWindow lngHwnd
'Uncover Outlook window by bringing it to top of Z Order.
BringWindowToTop lngHwnd
'Detach threads.
AttachThreadInput lngThreadForegnd, lngThreadOutlook, False
Else
SetForegroundWindow lngHwnd
BringWindowToTop lngHwnd
End If
If IsIconic(lngHwnd) Then
'Outlook is minimized -- restore, activate, and display window.
ShowWindow lngHwnd, SW_RESTORE
Else
'Outlook is not minimized -- activate and display window.
ShowWindow lngHwnd, SW_SHOW
End If
End Sub