3

[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)

Community
  • 1
  • 1
Oliver Giesen
  • 9,129
  • 6
  • 46
  • 82

2 Answers2

1

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.

Oliver Giesen
  • 9,129
  • 6
  • 46
  • 82
  • I tried this approach, but the EnumWindows didn't return the wordmail window at all (OpusApp). Did you ever find a better solution? If not, how did you implement the code to get the window? – Moox Mar 10 '11 at 17:46
  • @Moox: When do you call `EnumWindows`? I'm not doing anything special there. I'll post some snippets later. – Oliver Giesen Mar 11 '11 at 10:27
  • @Moox: I've added a code snippet to my answer, now. Please take special note of the Note below the snippet regarding the very restricted circumstances under which I make use of this. – Oliver Giesen Mar 11 '11 at 10:52
0

I found that on the Constructor of the custom Inspector, you can use the following method to find the newly constructed inspector.

C#

inspectorWindow = Win32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "OpusApp", "Microsoft Word");

You have to do this on the constructor, afterwards the caption becomes the title of the message ("Untitled Message" on new messages). I'm assuming that if you have a message named Microsoft Word already opened, there could be an error because of ambiguity, but the chances that it happens are somewhat low.

Moox
  • 1,122
  • 9
  • 23
  • I'm also pretty sure that this would also find actual Word windows which also have a class name of "OpusApp". Apart from that, I don't have a custom inspector: I'm hooking into the existing ones via event handlers. – Oliver Giesen Mar 14 '11 at 14:32