3

[此代码从Inspector.Activate事件处理程序(第一次调用)中调用,即在实际显示检查器窗口之前。]

对于“本地”邮件检查员,我可以简单地 QIInspector接口IOleWindow并调用其GetWindow方法。但是,这不适用于 Word 检查器,它们实际上是带有特殊工具栏的 Word 实例并且不实现IOleWindow.

(临时)设置Inspector.Caption为某个唯一值,然后查找具有该标题的窗口也不起作用,因为Inspector在使用 WordMail 选项时,访问大多数属性对实际检查器窗口没有(立即)影响。调用Activate然后立即查询也不能GetForegroundWindow可靠地工作:当已经打开了多个检查器或存在实际的 Word 窗口时,这通常只会返回“最旧”的实例而不是最新的实例。

多年来,我尝试了许多其他方法,但最终都证明它们在某种程度上存在缺陷。是否有一个相对简单的解决方案,或者我是否必须采用更复杂的方法,例如通过系统挂钩保留我自己的已知窗口句柄列表并尝试以某种方式将它们与已知检查员匹配?(向P Daddy提示有关使用 CBT 钩子的提示)

4

2 回答 2

1

我现在想出了一些我还不能打破的新东西,但它仍然感觉很像伏都教。通过观察,我发现我想要的窗口总是似乎是第一个返回的窗口,EnumWindows但它不(尚未)可见,即IsWindowVisible返回False(请记住,我是Inspector.Activate在检查器显示之前从事件的第一次发生内部调用此代码首次)。

如果有人知道更好的解决方案或有充分理由解释为什么这样做(最好带有权威文档的链接),请发表回复。

更新:所以,根据要求,这里有一些实际的(Delphi)代码。请注意,这不是我的工作代码,其中包含与此问题无关的其他一些内容,这些内容已在此处删除。

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;

注意:我只在检查员的 -event 中使用此功能,Activate并且当 Outlook 主要版本 < 12 并且检查员的IsWordMail-property 为True.

于 2011-03-03T13:25:02.337 回答
0

我发现在自定义Inspector的Constructor上,可以使用下面的方法找到新建的Inspector。

C#

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

您必须在构造函数上执行此操作,然后标题成为消息的标题(新消息上的“无标题消息”)。我假设如果您已经打开了一条名为 Microsoft Word 的消息,则可能会因为歧义而出现错误,但发生这种情况的可能性有点低。

于 2011-03-14T12:53:03.317 回答