winapi - ¿Cómo puedo determinar de forma fiable el identificador de ventana de una ventana de inspector de Outlook dada con WordMail activado desde dentro de un COM-Addin(Outlook<= 2003)?
add-in hwnd (2)
[Se llama a este código desde el Inspector.Activate
Active el controlador de eventos (primera llamada), es decir, justo antes de que se muestre la ventana del inspector.]
Para inspectores de correo "nativos", simplemente puedo QI la interfaz de Inspector
a IOleWindow
y llamar a su método GetWindow
. Sin embargo, esto no funcionará para los inspectores de Word que son, de hecho, instancias de Word con una barra de herramientas especial y no implementan IOleWindow
.
(Temporalmente) establecer Inspector.Caption
en algún valor único y luego buscar una ventana con ese título tampoco funciona, ya que acceder a la mayoría de las propiedades del Inspector
simplemente no tiene un efecto (inmediato) en la ventana del inspector real cuando se utiliza la opción WordMail. Tampoco la llamada Activate
y la consulta inmediata de GetForegroundWindow
funcionan de manera confiable: cuando hay múltiples inspectores abiertos o cuando hay presentes ventanas de Word, esto a menudo solo devuelve la instancia "más antigua" en lugar de la más reciente.
He intentado una serie de otros enfoques en los últimos años, pero finalmente todos resultaron ser defectuosos de una manera u otra. ¿Hay alguna solución moderadamente simple para esto o tendré que recurrir a un enfoque mucho más elaborado, como mantener mi propia lista de identificadores de ventanas conocidos a través de un gancho de sistema e intentar compararlos con los inspectores conocidos de alguna manera? (punta de sombrero para P Daddy por la pista sobre el uso de ganchos CBT)
Ahora he encontrado algo nuevo que todavía no he podido romper, pero todavía se siente mucho como vudú. Por observación, descubrí que la ventana que quiero siempre parece ser la primera devuelta por EnumWindows
que no está (todavía) visible, es decir, IsWindowVisible
devuelve False
(recuerde que estoy llamando a este código desde la primera aparición del evento Inspector.Activate
justo antes de que el inspector se muestre por primera vez).
Si alguien conoce una solución mejor o tiene una explicación bien fundamentada de por qué funciona (preferiblemente con enlaces a documentos autorizados), envíe una respuesta.
Actualización: Entonces, a pedido, aquí hay un código real (Delphi). Tenga en cuenta que este no es mi código de trabajo, que contiene un par de otras cosas, no relevantes para esta pregunta, que se han recortado aquí.
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;
Nota: Solo uso esta función desde el evento Activate
del inspector y cuando la versión principal de Outlook es <12 y la IsWordMail
IsWordMail del inspector es True
.
Encontré que en el Constructor del Inspector personalizado, puede usar el siguiente método para encontrar el inspector recién construido.
DO#
inspectorWindow = Win32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "OpusApp", "Microsoft Word");
Tienes que hacer esto en el constructor, luego el título se convierte en el título del mensaje ("Mensaje sin título" en los mensajes nuevos). Supongo que si tiene un mensaje llamado Microsoft Word ya abierto, podría haber un error debido a la ambigüedad, pero las posibilidades de que suceda son algo bajas.