Come trovare il puntatore IWebBrowser2 per una finestra IE8 con un PID?
-
22-07-2019 - |
Domanda
finora, ho usato con successo la seguente funzione per recuperare il puntatore IWebBrowser2 su un'istanza di Internet Explorer in esecuzione, dato il suo PID.
static SHDocVw::IWebBrowser2Ptr findBrowserByPID( DWORD pid )
{
SHDocVw::IShellWindowsPtr ptr;
ptr.CreateInstance(__uuidof(SHDocVw::ShellWindows));
if ( ptr == NULL ) {
return 0;
}
// number of shell windows
const long nCount = ptr->GetCount();
// iterate over all shell windows
for (long i = 0; i < nCount; ++i) {
// get interface to item no i
_variant_t va(i, VT_I4);
IDispatchPtr spDisp = ptr->Item(va);
SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
if (spBrowser != NULL) {
// if there's a document we know this is an IE object
// rather than a Windows Explorer instance
HWND browserWindow;
try {
browserWindow = (HWND)spBrowser->GetHWND();
} catch ( const _com_error &e ) {
// in case ->GetHWND() fails
continue;
}
DWORD browserPID;
GetWindowThreadProcessId( browserWindow, &browserPID );
if ( browserPID == pid ) {
return spBrowser;
}
}
}
return 0;
}
Quello che faccio è avviare un processo explorer.exe
tramite CreateProcess
e quindi utilizzare la funzione sopra per recuperare IWebBrowser2Ptr (in modo da poter giocherellare con il browser).
Sfortunatamente, questo non sembra più funzionare con Internet Explorer 8, poiché IE8 sembra riutilizzare i processi - almeno in una certa misura. Per due sequenze di codici come:
PROCESS_INFORMATION pi;
// ...
if ( CreateProcess( ..., &pi ) ) {
// Wait a bit to give the browser a change to show its window
// ...
IWebBrowser2 *pWebBrowser = findBrowserByPID( pi.dwProcessId );
}
La prima esecuzione di questo codice funziona correttamente, la seconda non riesce mai a recuperare la finestra di pWebBrowser.
Dopo un po 'di debug, è stato rivelato che la funzione findBrowserByPID
trova molte finestre del browser (e ne trova altre dopo aver avviato una seconda istanza del browser), ma nessuna di queste appartiene alla nuova processo avviato. Sembra che tutte le finestre appartengano al primo processo di IE avviato.
Qualcuno conosce un modo alternativo per ottenere il puntatore IWebBrowser2 in qualche istanza di IE8? O c'è forse un modo per disabilitare questo apparente "riutilizzo" dei processi con IE8?
Soluzione
Se stai avviando tu stesso il processo IE, non usare CreateProcess, invece usa CoCreateInstance. Ciò restituirà un oggetto per il quale è possibile eseguire una query per IWebBrowser2, che è possibile utilizzare a piacimento. L'unica complessità è che se la navigazione attraversa i livelli di integrità (Vista +) il puntatore diventa non valido. Per risolvere il problema, sincronizza l'evento NewProcess, che ti permetterà di rilevare questa condizione.
Altre informazioni qui: http: / /msdn.microsoft.com/en-us/library/aa752084%28VS.85%29.aspx
Altri suggerimenti
Un paio di approcci alternativi potrebbero essere:
-
Utilizza una libreria come WatiN che potrebbe aiutarti a fare qualunque sia il tuo vero obiettivo finale se stai cercando di automatizzare IE.