|
I am creating a console application,in which I create an instance on IE and hook an event sink to it.The main code is as follows:
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IWebBrowser2* disp;
HRESULT hr;
hr=CoCreateInstance(CLSID_InternetExplorer,NULL,CLSCTX_LOCAL_SERVER,IID_IWebBrowser2,(void**)&disp);
if(SUCCEEDED(hr))
{
disp->put_Visible(TRUE);
LPSTREAM pStream = NULL;
//marshalling the broser interface
hr = CoMarshalInterThreadInterfaceInStream(IID_IWebBrowser2, disp, &pStream);
.......
HANDLE hThread = CreateThread(NULL, 0, ThreadProc1,pStream, 0, &dwThreadID);
WaitWithMessageLoop(hThread);
......
}
}
...........
disp->Navigate2(&vurl, &ve, &ve, &ve, &ve); */
CoUninitialize();
In threadprocfunction,i create an instance of teh sick and hook it to IE
CoInitialize(NULL);
........
// get proxy to interface and release IStream
HRESULT hr = CoGetInterfaceAndReleaseStream(pStream, IID_IWebBrowser2, (LPVOID*)&psIE);
HRESULT hr=CoCreateInstance(CLSID_InternetExplorer,NULL,CLSCTX_LOCAL_SERVER,IID_IWebBrowser2,(void**)&psIE);
....... //Create the listener instance
hr = CoCreateInstance(CLSID_emplaybacksink,NULL,CLSCTX_INPROC_SERVER,IID_Iemplaybacksink,(void**)&tsink);
....... {
AtlAdvise( psIE,pUnk,DIID_DWebBrowserEvents2,&m_dwCookie);
........ }
The Atladvise action causes IE to hang during navigation.It proceeds only after the application has exitted.It seems there is a deadlock when IE calls back into the event sink.How can i avoid it?
|
|
|
|
|
1. You shouldn't call CoInitialize in the thread-proc (don't know if that affects you problem, though).
2. You CoCreateInstance Internet Explorer in your thread-proc, replacing the interface pointer passed (by marshalling) to the thread.
I think the main thing is that your thread doesn't have a message loop, so it's unlikely that connection points will work, as they rely (IIRC) on Windows messages.
Why use multiple threads, anyway? Connection points & IE work fine in a single-threaded app...
|
|
|
|
|
Stuart Dootson wrote: 1. You shouldn't call CoInitialize in the thread-proc (don't know if that affects you problem, though).
Yes, you should. Every thread that uses COM must initialise COM; these calls are also how you inform COM of your thread's threading model.
Stuart Dootson wrote: that connection points will work, as they rely (IIRC) on Windows messages.
No they don't. They are simply interface method calls, typically calls to IDispatch::Invoke . STA threads are required to have message pumps but MTAs do not need them. The only time when not having a message pump will affect calling a connection point is if the sink is in a STA and it is called from another apartment. This issue is not related to connection points; it's a general issue.
Steve
|
|
|
|
|
Actually i had initalized my new thread within an MTA too;but the results did not change .
When i try this with a GUI based application - firing the IE on the click of a button ;everything is fine - and the component receives the call-back on navigatecomplte/documentcomplte etc.
Is tehre any suggestion no how to make the console application implement a message handling framework as a ATL GUI based application?
|
|
|
|
|
Here's a complete example. It handles the new window and quit events from IE. It's a console app using no libraries (apart from the standard library) and uses two MTA threads like your code:
---------------------------------------
// Console.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <objbase.h>
#include <Exdisp.h>
#include <ocidl.h>
#include <EXDISPID.H>
#include <iostream>
HANDLE g_hThread = NULL;
HANDLE g_hBail = NULL;
class CMyDispatch : public IDispatch
{
public:
/* IUnknown methods */
STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
{
if (!ppvObject)
{
return E_POINTER;
}
*ppvObject = NULL;
if ( IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDispatch) )
{
*ppvObject = this;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)(void)
{
return 0;
}
STDMETHOD_(ULONG, Release)(void)
{
return 0;
}
/* IDispatch methods */
STDMETHOD(GetTypeInfoCount)(UINT * pctinfo)
{
if (!pctinfo)
{
return E_POINTER;
}
*pctinfo = 0;
return S_OK;
}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
{
if (!pptinfo)
{
return E_POINTER;
}
*pptinfo = NULL;
return E_NOTIMPL;
}
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
{
return E_NOTIMPL;
}
STDMETHOD(Invoke)(
DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pdispparams,
VARIANT *pvarResult,
EXCEPINFO *pexcepinfo,
UINT *puArgErr)
{
if (wFlags & DISPATCH_METHOD)
{
switch (dispidMember)
{
case DISPID_NEWWINDOW2:
std::cout << "DISPID_NEWWINDOW2" << std::endl;
return S_OK;
case DISPID_ONQUIT:
std::cout << "DISPID_ONQUIT" << std::endl;
SetEvent(g_hBail);
return S_OK;
}
}
return DISP_E_MEMBERNOTFOUND;
}
};
CMyDispatch g_EventHandler;
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
IWebBrowser2 *pWB = NULL;
IStream *pMarshalData = static_cast<IStream*>(lpParameter);
HRESULT hr = CoGetInterfaceAndReleaseStream(
pMarshalData,
__uuidof(pWB),
reinterpret_cast<void**>(&pWB)
);
if ( SUCCEEDED(hr) )
{
hr = pWB->put_Visible(VARIANT_TRUE);
IConnectionPointContainer *pCPC;
hr = pWB->QueryInterface(&pCPC);
if ( SUCCEEDED(hr) )
{
IConnectionPoint *pCP = NULL;
hr = pCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &pCP);
if ( SUCCEEDED(hr) )
{
DWORD Cookie;
hr = pCP->Advise(&g_EventHandler, &Cookie);
WaitForSingleObject(g_hBail, INFINITE);
pCP->Unadvise(Cookie);
pCP->Release();
}
pCPC->Release();
}
pWB->Release();
}
CoUninitialize();
return 0;
}
void DoStuff()
{
g_hBail = CreateEvent(NULL, TRUE, FALSE, NULL);
IWebBrowser2 *pWB = NULL;
HRESULT hr;
hr = CoCreateInstance(
CLSID_InternetExplorer,
NULL,
CLSCTX_LOCAL_SERVER,
IID_IWebBrowser2,
reinterpret_cast<void**>(&pWB)
);
if ( SUCCEEDED(hr) )
{
IStream *pMarshalData;
hr = CoMarshalInterThreadInterfaceInStream(__uuidof(pWB), pWB, &pMarshalData);
if ( SUCCEEDED(hr) )
{
DWORD ThreadId;
g_hThread = CreateThread(
NULL, // lpThreadAttributes
0, // dwStackSize
&ThreadProc, // lpStartAddress
pMarshalData, // lpParameter
0, // dwCreationFlags
&ThreadId // lpThreadId
);
if (g_hThread)
{
WaitForSingleObject(g_hThread, INFINITE);
CloseHandle(g_hThread);
g_hThread = NULL;
}
else
{
pMarshalData->Release();
}
}
pWB->Release();
}
CloseHandle(g_hBail);
}
int main(int argc, char* argv[])
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
DoStuff();
CoUninitialize();
return 0;
}
Steve
|
|
|
|
|
So did you solve your problem? If so how? The people that contributed are generally interested in knowing the outcome. This is a small price to pay for free technical support.
Steve
|
|
|
|
|
Sorry for the delay in reply steve.Still workign out how to trap the documentcomplete event - the problem is if we set the event to signalled state(setevent) from documentcomplete;the browser continues to hang -doing setevent in the quit event is not an option for me ,as the app would play all the html events without any manual intervention.
Just trying to figure out if its a behaviour of documentcomplete stage,or some mistake on my part.
Thanks a lot for the help - will keep posted about my findings
|
|
|
|
|
I am using multiple threads because i am facing the same problem in a single-threaded app too.In that case too , the browsers just fires the beforenavigate and hangs.It proceeds forward with the navigation( and fires the navigatecomplete/documentcomplete events) only when i exit out of the application.
Is it essential for the client application to be a GUI based ?
|
|
|
|
|
Hi. I believe WTL is a library built to enhance the ATL windowing features. Just like we can statically link ATL's functions into our application by using the _ATL_STATIC_REGISTRY Macro, is there any way in which we can statically link the WTL library to our applications.
Thanks.
---
With best regards,
A Manchester United Fan
The Genius of a true fool is that he can mess up a foolproof plan!
|
|
|
|
|
I think there is no such thing as linking to WTL. WTL should become a part of the application code. You can check with the Dependency Walker utility that comes with VS6.
this is this.
|
|
|
|
|
WTL is made up entirely of header files, so there's no WTL library to link with, either statically or dynamically.
|
|
|
|
|
But WTL is built on top of ATL. Although lots of ATL is header files there are parts of it that can be either statically of dynamically linked. WTL will inherit this from ATL.
Steve
|
|
|
|
|
So what you mean is, there is no wtl.dll like atl.dll for WTL? WTL is just header files which wrap aound ATL! And if I use the _ATL_STATIC_REGISTRY macro then the ATL.DLL gets statically linked to my applications along with WTL?
Thanks so much for your answers!
---
With best regards,
A Manchester United Fan
The Genius of a true fool is that he can mess up a foolproof plan!
|
|
|
|
|
TechyMaila wrote: So what you mean is, there is no wtl.dll like atl.dll for WTL? WTL is just header files which wrap aound ATL! And if I use the _ATL_STATIC_REGISTRY macro then the ATL.DLL gets statically linked to my applications along with WTL?
I believe so: but _ATL_STATIC_REGISTRY only controls the registration code.
Steve
|
|
|
|
|
TechyMaila wrote: And if I use the _ATL_STATIC_REGISTRY macro then the ATL.DLL gets statically linked to my applications along with WTL?
That's only needed *IF* you use the COM registration bit of ATL. I have several WTL Win32 applications. They don't link against WTL *OR* ATL libraries, as all of teh ATL and WTL code is compiled into the executable.
|
|
|
|
|
You're after the _ATL_DLL define (for the rest of ATL apart from the registration code). Also if you use ATL's ActiveX containment code it uses the type library which is in "ATL.dll" with of without _ATL_DLL defined.
Steve
|
|
|
|
|
I asked a question on the VC++ message boards about when's the best time to use a dialog based app, and when's the best time to use a normal window frame (eg. SDI, MDI etc.), and didn't receive many responses. Can anyone shed some light on this matter ?
Can someone also explain what the main differences between a dialog based app and normal frame based app (as I understand it, the main difference is that with dialog based apps one of the controls will always have the focus) ?
I'm asking because I currently have a CDialogResize based app which I wanted to add a splitter window to. Since Michael Dunn's article on WTL splitters (http://www.codeproject.com/wtl/wtl4mfc7.asp) explains using the splitter window with a normal framed window, I was wondering if it's OK to use a splitter in a dialog based app ?
|
|
|
|
|
I'm new to WTL and am using WTL 8.0 with VS 2005. I have created a new modeless dialog based app with AppWizard and then made the relevant modifications to get it to resize, according to Michael Dunn's CP article "Using WTL's Built-in Dialog Resizing Class" http://www.codeproject.com/wtl/wtldlgresize.asp
It builds OK, and my dialog gets the gripper size box in the bottom right hand corner, but when I grab it the dialog does not resize. Only the grabber size box itself moves.
I've tried comparing to other projects which work, but cannot identify any differences.
|
|
|
|
|
|
|
Hi Mike,
Thanks for taking the time to reply.
I've already got that macro in "class CMainDlg" in MainDlg.h. Does it need to be defined elsewhere ?
Have you managed to successfully compile and run the sample project I uploaded without any changes ?
BEGIN_MSG_MAP(CMainDlg)<br />
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)<br />
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)<br />
COMMAND_ID_HANDLER(IDOK, OnOK)<br />
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)<br />
CHAIN_MSG_MAP(CDialogResize<CMainDlg> )<br />
END_MSG_MAP()
-- modified at 21:53 Tuesday 2nd May, 2006
|
|
|
|
|
Go to resource view and change the border of IDD_MAINDLG to Resizing.
|
|
|
|
|
Thanks hfry! It's working now.
You've saved me from insanity!
|
|
|
|
|
Thank you! I have tried several times over the last 15 years to get this to work and today I know why!
|
|
|
|
|
Thank you! I have tried several times over the last 15 years to get this to work and today I know why!
|
|
|
|
|