Winapi 在从COM加载项(Outlook<;=2003)内部打开WordMail的情况下,如何可靠地确定给定Outlook inspector窗口的窗口句柄?
[此代码从Winapi 在从COM加载项(Outlook<;=2003)内部打开WordMail的情况下,如何可靠地确定给定Outlook inspector窗口的窗口句柄?,winapi,outlook,add-in,hwnd,Winapi,Outlook,Add In,Hwnd,[此代码从检查器内调用。激活事件处理程序(第一次调用),即在实际显示检查器窗口之前。] 对于“本机”邮件检查器,我可以简单地将Inspector接口调到IOleWindow并调用其GetWindow方法。但是,这不适用于Word检查器,因为它们实际上是带有特殊工具栏的Word实例,并且不实现IOleWindow (暂时)将Inspector.Caption设置为某个唯一值,然后查找带有该标题的窗口也不起作用,因为在使用WordMail选项时,访问Inspector的大多数属性对实际的Inspec
检查器内调用。激活事件处理程序(第一次调用),即在实际显示检查器窗口之前。]
对于“本机”邮件检查器,我可以简单地将Inspector
接口调到IOleWindow
并调用其GetWindow
方法。但是,这不适用于Word检查器,因为它们实际上是带有特殊工具栏的Word实例,并且不实现IOleWindow
(暂时)将Inspector.Caption
设置为某个唯一值,然后查找带有该标题的窗口也不起作用,因为在使用WordMail选项时,访问Inspector
的大多数属性对实际的Inspector窗口没有(直接)影响。调用激活
,然后立即查询GetForegroundWindow
也不能可靠地工作:当有多个检查器已打开或存在实际的Word窗口时,通常只返回“最旧”的实例,而不是最近的实例
多年来,我尝试了许多其他方法,但最终都证明它们在某些方面存在缺陷。到底有没有一个比较简单的解决方案,或者我必须采用一种更为复杂的方法,比如通过一个系统钩子保存我自己的已知窗口句柄列表,并试图以某种方式将它们与已知的检查器相匹配?(关于使用CBT挂钩的提示,请参见帽子提示)我现在想出了一些我还没能打破的新东西,但它仍然感觉很像巫毒。通过观察,我发现我想要的窗口始终是由返回的第一个不可见的窗口,即返回False
(请记住,我是在检查器第一次出现时调用此代码的。在检查器第一次显示之前激活事件)
如果有人知道更好的解决方案,或者有充分的理由解释为什么这样做(最好有权威文档的链接),请发布回复
更新:根据请求,这里是一些实际的(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;
注意:我只在inspector的激活事件中使用此函数,并且当Outlook主版本为<12且inspector的IsWordMail
-属性为True
时,我发现在自定义inspector的构造函数中,可以使用以下方法查找新构造的检查器
C#
inspectorWindow=Win32.FindWindowEx(IntPtr.Zero、IntPtr.Zero、“OpusApp”、“Microsoft Word”);
您必须在构造函数上执行此操作,之后标题将成为消息的标题(“新消息中的“无标题消息”)。我假设,如果您已经打开了一封名为Microsoft Word的邮件,可能会因为歧义而出错,但发生这种情况的可能性很低。我尝试了这种方法,但EnumWindows根本没有返回wordmail窗口(OpusApp)。你有没有找到更好的解决办法?如果没有,您是如何实现获取窗口的代码的?@Moox:您何时调用EnumWindows
?我在那里没有做什么特别的事。我稍后会发布一些代码片段。@Moox:我现在已经在我的答案中添加了一个代码片段。请特别注意片段下面的注释,关于我使用它的非常有限的情况。我也非常确定这也会找到实际的Word窗口,它也有一个类名“OpusApp”。除此之外,我没有自定义检查器:我通过事件处理程序连接到现有的检查器。