[This code is called from within the Inspector.Activate
event handler (first call), i.e. right before the inspector window is actually shown.]
For "native" mail inspectors I can simply QI the Inspector
interface to IOleWindow
and call its GetWindow
method. However, this will not work for Word inspectors which are in fact instances of Word with a special toolbar and do not implement IOleWindow
.
(Temporarily) setting Inspector.Caption
to some unique value and then looking for a window with that caption also does not work as accessing most properties of the Inspector
simply has no (immediate) effect on the actual inspector window when using the WordMail option. Neither does calling Activate
and then immediately querying GetForegroundWindow
work reliably: when there are multiple inspectors already open or when actual Word windows are present this will often just return the "oldest" instance instead of the most recent one.
I have tried a number of other approaches over the years but they all eventually turned out to be flawed in some way or another. Is there a moderately simple solution to this at all or will I have to go for a much more elaborate approach like keeping my own list of known window handles via a system hook and trying to match them up against the known inspectors somehow? (hat tip to P Daddy for the hint about using CBT hooks)
I have now come up with something new that I haven't yet been able to break but it still feels a lot like voodoo. By observation I found that the window I want always appears to be the first one returned by EnumWindows
that is not (yet) visible, i.e. IsWindowVisible
returns False
(remember I'm calling this code from inside the first occurrence of the Inspector.Activate
event right before the inspector gets displayed for the first time).
If anyone knows of a better solution or has a well-founded explanation of why this works (preferably with links to authoritative docs), please post a reply.
Update: So, by request, here's some actual (Delphi) code. Note that this is not my working code, which contains a couple of other things, not relevant to this question, that have been trimmed out here.
function GetWindowClassName(const AHandle: HWND): String;
var
lClass: array[0..255] of Char;
begin
if GetClassName(AHandle, lClass, SizeOf(lClass)) > 0 then
Result := lClass
else
Result := '';
end;
type
TWordSearchInfo = record
Result: HWND;
end;
PWordSearchInfo = ^TWordSearchInfo;
function CheckWnd(AWnd: HWND; ASearchInfo: PWordSearchInfo): Boolean; stdcall;
begin
Result := True;
try
if GetWindowClassName(AWnd) = 'OpusApp' then
if not IsWindowVisible(AWnd) then
begin
ASearchInfo.Result := AWnd;
Exit(False);
end;
except
//plop!
end;
end;
function GetNewestWordHandle: Cardinal;
var
lSearchInfo: TWordSearchInfo;
begin
lSearchInfo.Result := 0;
EnumWindows(@CheckWnd, Integer(@lSearchInfo));
Result := lSearchInfo.Result;
end;
Note: I only use this function from within the inspector's Activate
-event and when the Outlook major version is < 12 and the inspector's IsWordMail
-property is True
.