BHO and threads
Hello to all.
Let us imagine that we have some Browser Helper Object. On completing
downloading a page from some url (eg www.test2.com/index.htm) , BHO
creates new thread, passing a pointer to "www.test2.com/index2.htm"
as parameter :
unsigned WINAPI SomeThread(void *pParam){
char *szUrl=(char*)pParam;
USES_CONVERSION;
IWebBrowser2* pPopup = NULL;
HRESULT hr;
CoInitialize(NULL);
hr = CoCreateInstance (CLSID_InternetExplorer, NULL,
CLSCTX_SERVER,
IID_IWebBrowser2,
(LPVOID*)&pPopup);
if (SUCCEEDED (hr) && (pPopup != NULL))
{
VARIANT vAddress,vDummy;
vDummy.vt=VT_EMPTY;
vAddress.vt=VT_BSTR;
vAddress.bstrVal=SysAllocString(T2OLE(szUrl));
free(szUrl);
pPopup-
>Navigate2(&vAddress,&vDummy,&vDummy,&vDummy,&vDummy);
SysFreeString(vAddress.bstrVal);
}
if (pPopup!=NULL) pPopup->Release();
CoUninitialize();
return true;
}
As we see, this thread creates new instance of WebBrowser object and
navigates it to the url passed in the thread. All is good, new window
is created successfully.
Page test2.com/index.htm contains ONE input field with type=text. Page
test2.ru/index2.htm contains the same field and submit button. Now.
What I need. I need that after entering six digits into the text field
in index.htm page (after focus out from that field) BHO would take the
entered digits, put them in the text field of the page index2.htm and
submit the form on index2.htm.
First, I save IHTMLDocument2 pointer of the documentcomplete event for
index2.htm page(I test the url value to be sure it is the index2.htm
page).
Then,in focusout handler I test the length of entered text in the text
field on index.htm and if it is equal to 6, call some function
passing this text. That function takes the saved ITHMLDocument2
pointer of the document representing our test2.com/index2.htm page and
enumerates all text elements of the forms in that document and puts
the required value to the one of the some name , than search for the
input sumbit element and click on it:
void SubmitIndex2Page(IHTMLDocument2 *pDoc,char *szVal){
// pDoc - our saved pointer to
index2.htm!
// szVal - our value that we have to
enter in text field of the index2.htm
HRESULT hr;
CComPtr<IHTMLElementCollection> pCol;
hr=pDoc->get_all(&pCol);
if (FAILED(hr)) return;
long lLen;
CComVariant vName("INPUT");
CComPtr<IDispatch> pDisp;
pDisp=NULL;
hr=pCol->tags(vName,&pDisp);
CComQIPtr<IHTMLElementCollection> pCol2=pDisp;
hr=pCol2->get_length(&lLen);
CComVariant vIndex;
vIndex.vt=VT_I4;
for (int i=0;i<lLen;i++){
vIndex.intVal=i;
pDisp=NULL;
hr=pCol2->item(vIndex,vIndex,&pDisp);
if (SUCCEEDED(hr) && pDisp!=NULL){
//CComQIPtr<IHTMLElement> pElem=pDisp;
CComQIPtr<IHTMLInputElement> pIElem=pDisp;
if (pIElem!=NULL){
CComBSTR bName,bType;
pIElem->get_name(&bName);
pIElem->get_type(&bType);
CStdString s=bName,sType=bType;
if (s.Find("somename")!=-1){
CComBSTR bName(szVal);
pIElem->put_value(bName);
}
if (s.Find("gogo")!=-1 && sType=="submit"){
CComQIPtr<IHTMLElement> pElem=pIElem;
CComBSTR bHTML;
pElem->get_outerHTML(&bHTML);
if (pElem!=NULL){
pElem->click();
break;
}
}
}
}
}
}
After some time (half a second) in mshtml.dll an unhandled exception
is raised (pElem->click() passes, this func is exited, than some calls
in mshtml.dll take place and than it is).
My suggestion this all happens because of thread syncronization or
whatever.
The only way I found to handle this situation is to wait for some
event with WaitForSingleEvent function in DocumentComplete handler of
index2.htm page. The event is nonsignaled while we have not entered
six digits in index.htm, and after user enters those digits, we signal
the event with SetEvent call. And the waiting thread of the index2.htm
document continues execution (we enumerate text fields, then click
sumbit etc). All is good, but while we not entered six digits in
index.htm page, out IE window with index2.htm hangs. HOW? How can do
the other way? It seems that using IHTMLDocument2 pointer in another
thread causes exception ? How can I bypass this?
date: 13 Mar 2007 06:39:34 -0700
author: unknown