Reputation:
We have an application that may under some circumstances launch Outlook. It gets an Outlook.Explorer object (oWindow As Outlook.Explorer) and calls its .Activate() procedure.
Up to that point all is hunky dory, but then I want to bring the Explorer object to the foreground, and we call this procedure:
Public Shared Sub BringToFore(ByVal oWindow As Object)
Dim oFoo As IOleWindow
Dim hWnd As IntPtr
oFoo = TryCast(oWindow, IOleWindow)
If Not (oFoo Is Nothing) Then
Try
oFoo.GetWindow(hWnd)
Catch ex As Exception
End Try
End If
Try
If hWnd.ToInt32 <> IntPtr.Zero.ToInt32 Then
Try
If IsIconic(hWnd) Then
ShowWindow(hWnd, SW_RESTORE)
End If
SetForegroundWindow(hWnd)
Catch ex As System.Exception
End Try
Else
End If
Catch ex As Exception
End Try
End Sub
IOleWindow is defined as follows:
<ComImport(), Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Private 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>
Sub GetWindow(<System.Runtime.InteropServices.Out()> ByRef phwnd As IntPtr)
''' <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>
Sub ContextSensitiveHelp(<[In](), MarshalAs(UnmanagedType.Bool)> ByVal fEnterMode As Boolean)
End Interface
and the usual declarations
Private Const SW_RESTORE As Integer = 9
Private Declare Auto Function IsIconic Lib "user32" (ByVal hWnd As IntPtr) As Boolean
Private Declare Auto Function SetForegroundWindow Lib "user32" (ByVal hwnd As IntPtr) As Long
Private Declare Auto Function ShowWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As IntPtr
The BringToFore procedure works fine most of the time. And sometimes the calling application - a WPF application - just hangs. The Event Viewer records an AppHangB1 and the application crashes.
Is there anything I can do in the BringToFore procedure to prevent this happening? Any idea which of these are causing the problem? TryCast(oWindow, IOleWindow), oFoo.GetWindow(hWnd), IsIconic(hWnd), ShowWindow(hWnd, SW_RESTORE) or SetForegroundWindow(hWnd)? (I personally suspect it may be SetForegroundWindow, to be honest). If so, is there anything I can do in the code? Some condition to check? If this condition is true then don't try to do that ..... sort of thing? I'd rather not go as far as just abandoning the idea of setting the Explorer to the foreground; in that circumstance Outlook may appear "behind" my application and some users may just not realise that something has happened.... if you catch my drift.
Thanks
Pino
Upvotes: 0
Views: 592
Reputation: 66286
Windows would prevent you from using SetForegroundWindow
if the window belongs to a process other than the active one. You'd need to call AttachThreadInput
first. Here is the function (Delphi):
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;
Upvotes: 1