/* Module: win32_browsewnd.c Purpose: Displays a window with an embedded browser in order to display the Voicechat flash from imo.im This example is bsaed on the work of Jeff Glatt (http://www.codeproject.com/KB/COM/cwebpage.aspx?msg=2852721) Author: leecher, credits go to Jeff Glatt for his excellent work. Date: 18.10.2009 */ #include #include #include #include #include #include "memlist.h" #include "w32browser.h" #ifndef _WIN64 #if WINVER<0x0500 #define SetWindowLongPtr SetWindowLong #define GetWindowLongPtr GetWindowLong #endif #ifndef LONG_PTR #define LONG_PTR LONG #endif #ifndef GWLP_USERDATA #define GWLP_USERDATA GWL_USERDATA #endif #endif static const SAFEARRAYBOUND ArrayBound = {1, 0}; static TYP_LIST *m_hWindows = NULL; static DWORD m_dwThread = 0; static HANDLE m_hThread = NULL, m_hEvent = NULL; HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj); HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This); HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This); HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd); HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode); HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder); HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths); HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths); HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName); HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject); HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared); HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText); HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable); HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID); IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {Frame_QueryInterface, Frame_AddRef, Frame_Release, Frame_GetWindow, Frame_ContextSensitiveHelp, Frame_GetBorder, Frame_RequestBorderSpace, Frame_SetBorderSpace, Frame_SetActiveObject, Frame_InsertMenus, Frame_SetMenu, Frame_RemoveMenus, Frame_SetStatusText, Frame_EnableModeless, Frame_TranslateAccelerator}; typedef struct { IOleInPlaceFrame frame; HWND window; } _IOleInPlaceFrameEx; HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject); HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This); HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This); HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This); HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk); HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer); HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This); HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow); HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This); IOleClientSiteVtbl MyIOleClientSiteTable = {Site_QueryInterface, Site_AddRef, Site_Release, Site_SaveObject, Site_GetMoniker, Site_GetContainer, Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout}; HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR* This, REFIID riid, void ** ppvObject); HRESULT STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR* This); HRESULT STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR* This); HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(IDocHostUIHandler FAR* This, DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved); HRESULT STDMETHODCALLTYPE UI_GetHostInfo(IDocHostUIHandler FAR* This, DOCHOSTUIINFO __RPC_FAR *pInfo); HRESULT STDMETHODCALLTYPE UI_ShowUI(IDocHostUIHandler FAR* This, DWORD dwID, IOleInPlaceActiveObject __RPC_FAR *pActiveObject, IOleCommandTarget __RPC_FAR *pCommandTarget, IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc); HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR* This); HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR* This); HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR* This, BOOL fEnable); HRESULT STDMETHODCALLTYPE UI_OnDocWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate); HRESULT STDMETHODCALLTYPE UI_OnFrameWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate); HRESULT STDMETHODCALLTYPE UI_ResizeBorder(IDocHostUIHandler FAR* This, LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow); HRESULT STDMETHODCALLTYPE UI_TranslateAccelerator(IDocHostUIHandler FAR* This, LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID); HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(IDocHostUIHandler FAR* This, LPOLESTR __RPC_FAR *pchKey, DWORD dw); HRESULT STDMETHODCALLTYPE UI_GetDropTarget(IDocHostUIHandler FAR* This, IDropTarget __RPC_FAR *pDropTarget, IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget); HRESULT STDMETHODCALLTYPE UI_GetExternal(IDocHostUIHandler FAR* This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch); HRESULT STDMETHODCALLTYPE UI_TranslateUrl(IDocHostUIHandler FAR* This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut); HRESULT STDMETHODCALLTYPE UI_FilterDataObject(IDocHostUIHandler FAR* This, IDataObject __RPC_FAR *pDO, IDataObject __RPC_FAR *__RPC_FAR *ppDORet); IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = {UI_QueryInterface, UI_AddRef, UI_Release, UI_ShowContextMenu, UI_GetHostInfo, UI_ShowUI, UI_HideUI, UI_UpdateUI, UI_EnableModeless, UI_OnDocWindowActivate, UI_OnFrameWindowActivate, UI_ResizeBorder, UI_TranslateAccelerator, UI_GetOptionKeyPath, UI_GetDropTarget, UI_GetExternal, UI_TranslateUrl, UI_FilterDataObject}; HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(IOleInPlaceSite FAR* This, REFIID riid, void ** ppvObject); HRESULT STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd); HRESULT STDMETHODCALLTYPE InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode); HRESULT STDMETHODCALLTYPE InPlace_CanInPlaceActivate(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceActivate(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_OnUIActivate(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame,LPOLEINPLACEUIWINDOW FAR* lplpDoc,LPRECT lprcPosRect,LPRECT lprcClipRect,LPOLEINPLACEFRAMEINFO lpFrameInfo); HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent); HRESULT STDMETHODCALLTYPE InPlace_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable); HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_DiscardUndoState(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_DeactivateAndUndo(IOleInPlaceSite FAR* This); HRESULT STDMETHODCALLTYPE InPlace_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect); IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = {InPlace_QueryInterface, InPlace_AddRef, InPlace_Release, InPlace_GetWindow, InPlace_ContextSensitiveHelp, InPlace_CanInPlaceActivate, InPlace_OnInPlaceActivate, InPlace_OnUIActivate, InPlace_GetWindowContext, InPlace_Scroll, InPlace_OnUIDeactivate, InPlace_OnInPlaceDeactivate, InPlace_DiscardUndoState, InPlace_DeactivateAndUndo, InPlace_OnPosRectChange}; typedef struct { IOleInPlaceSite inplace; _IOleInPlaceFrameEx frame; } _IOleInPlaceSiteEx; typedef struct { IDocHostUIHandler ui; } _IDocHostUIHandlerEx; typedef struct { IOleClientSite client; _IOleInPlaceSiteEx inplace; _IDocHostUIHandlerEx ui; } _IOleClientSiteEx; #define NOTIMPLEMENTED return(E_NOTIMPL) typedef struct { char *pszHTML; char *pszTitle; int width; int height; HWND hWnd; // out } ShowIEWndParam; //////////////////////////////////// My IDocHostUIHandler functions ////////////////////////////////////// // HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR* This, REFIID riid, LPVOID FAR* ppvObj) { return(Site_QueryInterface((IOleClientSite *)((char *)This - sizeof(IOleClientSite) - sizeof(_IOleInPlaceSiteEx)), riid, ppvObj)); } HRESULT STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(IDocHostUIHandler FAR* This, DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_GetHostInfo(IDocHostUIHandler FAR* This, DOCHOSTUIINFO __RPC_FAR *pInfo) { pInfo->cbSize = sizeof(DOCHOSTUIINFO); pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER; pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; return(S_OK); } HRESULT STDMETHODCALLTYPE UI_ShowUI(IDocHostUIHandler FAR* This, DWORD dwID, IOleInPlaceActiveObject __RPC_FAR *pActiveObject, IOleCommandTarget __RPC_FAR *pCommandTarget, IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR* This, BOOL fEnable) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_OnDocWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_OnFrameWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_ResizeBorder(IDocHostUIHandler FAR* This, LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) { return(S_OK); } HRESULT STDMETHODCALLTYPE UI_TranslateAccelerator(IDocHostUIHandler FAR* This, LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) { return(S_FALSE); } HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(IDocHostUIHandler FAR* This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) { return(S_FALSE); } HRESULT STDMETHODCALLTYPE UI_GetDropTarget(IDocHostUIHandler FAR* This, IDropTarget __RPC_FAR *pDropTarget, IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) { return(S_FALSE); } HRESULT STDMETHODCALLTYPE UI_GetExternal(IDocHostUIHandler FAR* This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) { *ppDispatch = 0; return(S_FALSE); } HRESULT STDMETHODCALLTYPE UI_TranslateUrl(IDocHostUIHandler FAR* This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) { *ppchURLOut = 0; return(S_FALSE); } HRESULT STDMETHODCALLTYPE UI_FilterDataObject(IDocHostUIHandler FAR* This, IDataObject __RPC_FAR *pDO, IDataObject __RPC_FAR *__RPC_FAR *ppDORet) { *ppDORet = 0; return(S_FALSE); } ////////////////////////////////////// My IOleClientSite functions ///////////////////////////////////// // HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject) { if (!memcmp(riid, &IID_IUnknown, sizeof(GUID)) || !memcmp(riid, &IID_IOleClientSite, sizeof(GUID))) *ppvObject = &((_IOleClientSiteEx *)This)->client; else if (!memcmp(riid, &IID_IOleInPlaceSite, sizeof(GUID))) *ppvObject = &((_IOleClientSiteEx *)This)->inplace; else if (!memcmp(riid, &IID_IDocHostUIHandler, sizeof(GUID))) *ppvObject = &((_IOleClientSiteEx *)This)->ui; else { *ppvObject = 0; return(E_NOINTERFACE); } return(S_OK); } HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer) { *ppContainer = 0; return(E_NOINTERFACE); } HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This) { return(NOERROR); } HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This) { NOTIMPLEMENTED; } ////////////////////////////////////// My IOleInPlaceSite functions ///////////////////////////////////// // HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(IOleInPlaceSite FAR* This, REFIID riid, LPVOID FAR* ppvObj) { return(Site_QueryInterface((IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj)); } HRESULT STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd) { *lphwnd = ((_IOleInPlaceSiteEx FAR*)This)->frame.window; return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE InPlace_CanInPlaceActivate(IOleInPlaceSite FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceActivate(IOleInPlaceSite FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_OnUIActivate(IOleInPlaceSite FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) { *lplpFrame = (LPOLEINPLACEFRAME)&((_IOleInPlaceSiteEx *)This)->frame; *lplpDoc = 0; lpFrameInfo->fMDIApp = FALSE; lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window; lpFrameInfo->haccel = 0; lpFrameInfo->cAccelEntries = 0; return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE InPlace_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable) { return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR* This) { return(S_OK); } HRESULT STDMETHODCALLTYPE InPlace_DiscardUndoState(IOleInPlaceSite FAR* This) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE InPlace_DeactivateAndUndo(IOleInPlaceSite FAR* This) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE InPlace_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect) { IOleObject *browserObject; IOleInPlaceObject *inplace; browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) - sizeof(IOleClientSite))); if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IOleInPlaceObject, (void**)&inplace)) { inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect); inplace->lpVtbl->Release(inplace); } return(S_OK); } ////////////////////////////////////// My IOleInPlaceFrame functions ///////////////////////////////////////// // HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This) { return(1); } HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd) { *lphwnd = ((_IOleInPlaceFrameEx *)This)->window; return(S_OK); } HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) { return(S_OK); } HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) { return(S_OK); } HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared) { NOTIMPLEMENTED; } HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText) { return(S_OK); } HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable) { return(S_OK); } HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID) { NOTIMPLEMENTED; } /*************************** UnEmbedBrowserObject() ************************ * Called to detach the browser object from our host window, and free its * resources, right before we destroy our window. * * hwnd = Handle to the window hosting the browser object. * * NOTE: The pointer to the browser object must have been stored in the * window's USERDATA field. In other words, don't call UnEmbedBrowserObject(). * with a HWND that wasn't successfully passed to EmbedBrowserObject(). */ void UnEmbedBrowserObject(HWND hwnd) { IOleObject **browserHandle; IOleObject *browserObject; // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when // we initially attached the browser object to this window. if ((browserHandle = (IOleObject **)GetWindowLongPtr(hwnd, GWLP_USERDATA))) { // Unembed the browser object, and release its resources. browserObject = *browserHandle; browserObject->lpVtbl->Close(browserObject, OLECLOSE_NOSAVE); browserObject->lpVtbl->Release(browserObject); GlobalFree(browserHandle); return; } } /******************************* DisplayHTMLStr() **************************** * Takes a string containing some HTML BODY, and displays it in the specified * window. For example, perhaps you want to display the HTML text of... * *

This is a picture.

* * hwnd = Handle to the window hosting the browser object. * string = Pointer to nul-terminated string containing the HTML BODY. * (NOTE: No tags are required in the string). * * RETURNS: 0 if success, or non-zero if an error. * * NOTE: EmbedBrowserObject() must have been successfully called once with the * specified window, prior to calling this function. You need call * EmbedBrowserObject() once only, and then you can make multiple calls to * this function to display numerous pages in the specified window. */ long DisplayHTMLStr(HWND hwnd, LPCTSTR string) { IWebBrowser2 *webBrowser2; LPDISPATCH lpDispatch; IHTMLDocument2 *htmlDoc2; IOleObject *browserObject; SAFEARRAY *sfArray; VARIANT myURL; VARIANT *pVar; BSTR bstr; // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when // we initially attached the browser object to this window. browserObject = *((IOleObject **)GetWindowLongPtr(hwnd, GWLP_USERDATA)); // Assume an error. bstr = 0; // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser // object, so we can call some of the functions in the former's table. if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2)) { // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is // webBrowser2->lpVtbl. // Before we can get_Document(), we actually need to have some HTML page loaded in the browser. So, // let's load an empty HTML page. Then, once we have that empty page, we can get_Document() and // write() to stuff our HTML string into it. VariantInit(&myURL); myURL.vt = VT_BSTR; myURL.bstrVal = SysAllocString(L"about:blank"); // Call the Navigate2() function to actually display the page. webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0); // Free any resources (including the BSTR). VariantClear(&myURL); // Call the IWebBrowser2 object's get_Document so we can get its DISPATCH object. I don't know why you // don't get the DISPATCH object via the browser object's QueryInterface(), but you don't. if (!webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch)) { // We want to get a pointer to the IHTMLDocument2 object embedded within the DISPATCH // object, so we can call some of the functions in the former's table. if (!lpDispatch->lpVtbl->QueryInterface(lpDispatch, &IID_IHTMLDocument2, (void**)&htmlDoc2)) { // Ok, now the pointer to our IHTMLDocument2 object is in 'htmlDoc2', and so its VTable is // htmlDoc2->lpVtbl. // Our HTML must be in the form of a BSTR. And it must be passed to write() in an // array of "VARIENT" structs. So let's create all that. if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, (SAFEARRAYBOUND *)&ArrayBound))) { if (!SafeArrayAccessData(sfArray, (void**)&pVar)) { pVar->vt = VT_BSTR; #ifndef UNICODE { wchar_t *buffer; DWORD size; size = MultiByteToWideChar(CP_ACP, 0, string, -1, 0, 0); if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) goto bad; MultiByteToWideChar(CP_ACP, 0, string, -1, buffer, size); bstr = SysAllocString(buffer); GlobalFree(buffer); } #else bstr = SysAllocString(string); #endif // Store our BSTR pointer in the VARIENT. if ((pVar->bstrVal = bstr)) { htmlDoc2->lpVtbl->clear(htmlDoc2); // Pass the VARIENT with its BSTR to write() in order to shove our desired HTML string // into the body of that empty page we created above. htmlDoc2->lpVtbl->write(htmlDoc2, sfArray); // Close the document. If we don't do this, subsequent calls to DisplayHTMLStr // would append to the current contents of the page htmlDoc2->lpVtbl->close(htmlDoc2); // Normally, we'd need to free our BSTR, but SafeArrayDestroy() does it for us // SysFreeString(bstr); } } // Free the array. This also frees the VARIENT that SafeArrayAccessData created for us, // and even frees the BSTR we allocated with SysAllocString SafeArrayDestroy(sfArray); } // Release the IHTMLDocument2 object. bad: htmlDoc2->lpVtbl->Release(htmlDoc2); } // Release the DISPATCH object. lpDispatch->lpVtbl->Release(lpDispatch); } // Release the IWebBrowser2 object. webBrowser2->lpVtbl->Release(webBrowser2); } // No error? if (bstr) return(0); // An error return(-1); } /******************************* ResizeBrowser() **************************** * Resizes the browser object for the specified window to the specified * width and height. * * hwnd = Handle to the window hosting the browser object. * width = Width. * height = Height. * * NOTE: EmbedBrowserObject() must have been successfully called once with the * specified window, prior to calling this function. You need call * EmbedBrowserObject() once only, and then you can make multiple calls to * this function to resize the browser object. */ void ResizeBrowser(HWND hwnd, DWORD width, DWORD height) { IWebBrowser2 *webBrowser2; IOleObject *browserObject; // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when // we initially attached the browser object to this window. browserObject = *((IOleObject **)GetWindowLongPtr(hwnd, GWLP_USERDATA)); // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser // object, so we can call some of the functions in the former's table. if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2)) { // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is // webBrowser2->lpVtbl. // Call are put_Width() and put_Height() to set the new width/height. webBrowser2->lpVtbl->put_Width(webBrowser2, width); webBrowser2->lpVtbl->put_Height(webBrowser2, height); // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it, // so we can release our hold on it). Note that we'll still maintain our hold on the browser // object. webBrowser2->lpVtbl->Release(webBrowser2); } } /***************************** EmbedBrowserObject() ************************** * Puts the browser object inside our host window, and save a pointer to this * window's browser object in the window's GWL_USERDATA field. * * hwnd = Handle of our window into which we embed the browser object. * * RETURNS: 0 if success, or non-zero if an error. * * NOTE: We tell the browser object to occupy the entire client area of the * window. * * NOTE: No HTML page will be displayed here. We can do that with a subsequent * call to either DisplayHTMLPage() or DisplayHTMLStr(). This is merely once-only * initialization for using the browser object. In a nutshell, what we do * here is get a pointer to the browser object in our window's GWL_USERDATA * so we can access that object's functions whenever we want, and we also pass * the browser a pointer to our IOleClientSite struct so that the browser can * call our functions in our struct's VTable. */ long EmbedBrowserObject(HWND hwnd) { LPCLASSFACTORY pClassFactory; IOleObject *browserObject; IWebBrowser2 *webBrowser2; RECT rect; char *ptr; _IOleClientSiteEx *_iOleClientSiteEx; // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to get our window handle. We // could store that in some global. But then, that would mean that our functions would work with only that // one window. If we want to create multiple windows, each hosting its own browser object (to display its // own web page), then we need to create unique IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame // structs for each window. And we'll put an extra field at the end of those structs to store our extra // data such as a window handle. So, our functions won't have to touch global data, and can therefore be // re-entrant and work with multiple objects/windows. // // Remember that a pointer to our IOleClientSite we create here will be passed as the first arg to every // one of our IOleClientSite functions. Ditto with the IOleInPlaceFrame object we create here, and the // IOleInPlaceFrame functions. So, our functions are able to retrieve the window handle we'll store here, // and then, they'll work with all such windows containing a browser control. // // Furthermore, since the browser will be calling our IOleClientSite's QueryInterface to get a pointer to // our IOleInPlaceSite and IDocHostUIHandler objects, that means that our IOleClientSite QueryInterface // must have an easy way to grab those pointers. Probably the easiest thing to do is just embed our // IOleInPlaceSite and IDocHostUIHandler objects inside of an extended IOleClientSite which we'll call // a _IOleClientSiteEx. As long as they come after the pointer to the IOleClientSite VTable, then we're // ok. // // Of course, we need to GlobalAlloc the above structs now. We'll just get all 4 with a single call to // GlobalAlloc, especially since 3 of them are all contained inside of our _IOleClientSiteEx anyway. // // So, we're not actually allocating separate IOleClientSite, IOleInPlaceSite, IOleInPlaceFrame and // IDocHostUIHandler structs. // // One final thing. We're going to allocate extra room to store the pointer to the browser object. if (!(ptr = (char *)GlobalAlloc(GMEM_FIXED, sizeof(_IOleClientSiteEx) + sizeof(IOleObject *)))) return(-1); // Initialize our IOleClientSite object with a pointer to our IOleClientSite VTable. _iOleClientSiteEx = (_IOleClientSiteEx *)(ptr + sizeof(IOleObject *)); _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable; // Initialize our IOleInPlaceSite object with a pointer to our IOleInPlaceSite VTable. _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable; // Initialize our IOleInPlaceFrame object with a pointer to our IOleInPlaceFrame VTable. _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable; // Save our HWND (in the IOleInPlaceFrame object) so our IOleInPlaceFrame functions can retrieve it. _iOleClientSiteEx->inplace.frame.window = hwnd; // Initialize our IDocHostUIHandler object with a pointer to our IDocHostUIHandler VTable. _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable; // Get a pointer to the browser object and lock it down (so it doesn't "disappear" while we're using // it in this program). We do this by calling the OS function CoGetClassObject(). // // NOTE: We need this pointer to interact with and control the browser. With normal WIN32 controls such as a // Static, Edit, Combobox, etc, you obtain an HWND and send messages to it with SendMessage(). Not so with // the browser object. You need to get a pointer to its "base structure" (as returned by CoGetClassObject()). This // structure contains an array of pointers to functions you can call within the browser object. Actually, the // base structure contains a 'lpVtbl' field that is a pointer to that array. We'll call the array a 'VTable'. // // For example, the browser object happens to have a SetHostNames() function we want to call. So, after we // retrieve the pointer to the browser object (in a local we'll name 'browserObject'), then we can call that // function, and pass it args, as so: // // browserObject->lpVtbl->SetHostNames(browserObject, SomeString, SomeString); // // There's our pointer to the browser object in 'browserObject'. And there's the pointer to the browser object's // VTable in 'browserObject->lpVtbl'. And the pointer to the SetHostNames function happens to be stored in an // field named 'SetHostNames' within the VTable. So we are actually indirectly calling SetHostNames by using // a pointer to it. That's how you use a VTable. // // NOTE: We pass our _IOleClientSiteEx struct and lie -- saying that it's a IOleClientSite. It's ok. A // _IOleClientSiteEx struct starts with an embedded IOleClientSite. So the browser won't care, and we want // this extended struct passed to our IOleClientSite functions. // Get a pointer to the browser object's IClassFactory object via CoGetClassObject() pClassFactory = 0; if (!CoGetClassObject(&CLSID_WebBrowser, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL, &IID_IClassFactory, (void **)&pClassFactory) && pClassFactory) { // Call the IClassFactory's CreateInstance() to create a browser object if (!pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0, &IID_IOleObject, &browserObject)) { // Free the IClassFactory. We need it only to create a browser object instance pClassFactory->lpVtbl->Release(pClassFactory); // Ok, we now have the pointer to the browser object in 'browserObject'. Let's save this in the // memory block we allocated above, and then save the pointer to that whole thing in our window's // USERDATA field. That way, if we need multiple windows each hosting its own browser object, we can // call EmbedBrowserObject() for each one, and easily associate the appropriate browser object with // its matching window and its own objects containing per-window data. *((IOleObject **)ptr) = browserObject; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)ptr); // Give the browser a pointer to my IOleClientSite object if (!browserObject->lpVtbl->SetClientSite(browserObject, (IOleClientSite *)_iOleClientSiteEx)) { // We can now call the browser object's SetHostNames function. SetHostNames lets the browser object know our // application's name and the name of the document in which we're embedding the browser. (Since we have no // document name, we'll pass a 0 for the latter). When the browser object is opened for editing, it displays // these names in its titlebar. // // We are passing 3 args to SetHostNames. You'll note that the first arg to SetHostNames is the base // address of our browser control. This is something that you always have to remember when working in C // (as opposed to C++). When calling a VTable function, the first arg to that function must always be the // structure which contains the VTable. (In this case, that's the browser control itself). Why? That's // because that function is always assumed to be written in C++. And the first argument to any C++ function // must be its 'this' pointer (ie, the base address of its class, which in this case is our browser object // pointer). In C++, you don't have to pass this first arg, because the C++ compiler is smart enough to // produce an executable that always adds this first arg. In fact, the C++ compiler is smart enough to // know to fetch the function pointer from the VTable, so you don't even need to reference that. In other // words, the C++ equivalent code would be: // // browserObject->SetHostNames(L"My Host Name", 0); // // So, when you're trying to convert C++ code to C, always remember to add this first arg whenever you're // dealing with a VTable (ie, the field is usually named 'lpVtbl') in the standard objects, and also add // the reference to the VTable itself. // // Oh yeah, the L is because we need UNICODE strings. And BTW, the host and document names can be anything // you want. browserObject->lpVtbl->SetHostNames(browserObject, L"My Host Name", 0); GetClientRect(hwnd, &rect); // Let browser object know that it is embedded in an OLE container. if (!OleSetContainedObject((struct IUnknown *)browserObject, TRUE) && // Set the display area of our browser control the same as our window's size // and actually put the browser object into our window. !browserObject->lpVtbl->DoVerb(browserObject, OLEIVERB_SHOW, NULL, (IOleClientSite *)_iOleClientSiteEx, -1, hwnd, &rect) && // Ok, now things may seem to get even trickier, One of those function pointers in the browser's VTable is // to the QueryInterface() function. What does this function do? It lets us grab the base address of any // other object that may be embedded within the browser object. And this other object has its own VTable // containing pointers to more functions we can call for that object. // // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser // object, so we can call some of the functions in the former's table. For example, one IWebBrowser2 function // we intend to call below will be Navigate2(). So we call the browser object's QueryInterface to get our // pointer to the IWebBrowser2 object. !browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2)) { // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is // webBrowser2->lpVtbl. // Let's call several functions in the IWebBrowser2 object to position the browser display area // in our window. The functions we call are put_Left(), put_Top(), put_Width(), and put_Height(). // Note that we reference the IWebBrowser2 object's VTable to get pointers to those functions. And // also note that the first arg we pass to each is the pointer to the IWebBrowser2 object. webBrowser2->lpVtbl->put_Left(webBrowser2, 0); webBrowser2->lpVtbl->put_Top(webBrowser2, 0); webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right); webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom); // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it // right now, so we can release our hold on it). Note that we'll still maintain our hold on the // browser object until we're done with that object. webBrowser2->lpVtbl->Release(webBrowser2); // Success return(0); } } // Something went wrong setting up the browser! UnEmbedBrowserObject(hwnd); return(-4); } pClassFactory->lpVtbl->Release(pClassFactory); GlobalFree(ptr); // Can't create an instance of the browser! return(-3); } GlobalFree(ptr); // Can't get the web browser's IClassFactory! return(-2); } /****************************** WindowProc() *************************** * Our message handler for our window to host the browser. */ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SIZE: { // Resize the browser object to fit the window ResizeBrowser(hwnd, LOWORD(lParam), HIWORD(lParam)); return(0); } case WM_CREATE: { // Embed the browser object into our host window. We need do this only // once. Note that the browser object will start calling some of our // IOleInPlaceFrame and IOleClientSite functions as soon as we start // calling browser object functions in EmbedBrowserObject(). if (EmbedBrowserObject(hwnd)) return(-1); // Success return(0); } case WM_DESTROY: { int i, nCount; // Detach the browser object from this window, and free resources. UnEmbedBrowserObject(hwnd); // If all the windows are now closed, quit this app if (m_hWindows) { for (i=0, nCount=List_Count(m_hWindows); ihWnd = CreateWindowEx(0, wc.lpszClassName, Param->pszTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Param->width, Param->height, HWND_DESKTOP, NULL, wc.hInstance, 0))) { List_Push (m_hWindows, Param->hWnd); DisplayHTMLStr(Param->hWnd, Param->pszHTML); ShowWindow(Param->hWnd, SW_SHOWNORMAL); SetForegroundWindow (Param->hWnd); UpdateWindow(Param->hWnd); } SetEvent (m_hEvent); break; } case WM_USER+1: { DestroyWindow ((HWND)msg.lParam); break; } } TranslateMessage(&msg); DispatchMessage(&msg); } UnregisterClass (wc.lpszClassName, wc.hInstance); CoUninitialize(); if (m_hWindows) List_Exit (m_hWindows); ExitThread (0); return 0; } // ----------------------------------------------------------------------------- // Interface // ----------------------------------------------------------------------------- // bInitBrowser - Tries to initialize a dummy window on start so that subsequent // calls are faster as all libraries are already present in // memory. Drawback: Higher memory consumption int W32Browser_Init(BOOL bInitBrowser) { if (m_hThread) W32Browser_Exit(); m_hThread = (HANDLE)_beginthreadex(NULL, 0, ShowIEWndFunc, (LPVOID)bInitBrowser, 0, &m_dwThread); if (!m_hThread) return -1; if (!(m_hEvent = CreateEvent (NULL, FALSE, FALSE, NULL))) { TerminateThread (m_hThread, -1); CloseHandle (m_hThread); return -1; } return 0; } // ----------------------------------------------------------------------------- void W32Browser_Exit(void) { if (m_hWindows) { HWND hWnd; while (hWnd = List_Pop(m_hWindows)) W32Browser_CloseWindow (hWnd); m_hWindows = NULL; } if (m_hThread) { PostThreadMessage (m_dwThread, WM_QUIT, 0, 0); if (WaitForSingleObject (m_hThread, 2000) == WAIT_TIMEOUT) TerminateThread (m_hThread, -1); CloseHandle (m_hThread); m_hThread = NULL; } if (m_hEvent) { CloseHandle (m_hEvent); m_hEvent = NULL; } } // ----------------------------------------------------------------------------- void *W32Browser_ShowHTMLStr(char *pszHTMLStr, int width, int height, char *pszTitle) { // Window gets its own thread to not block the Mainthread static ShowIEWndParam Param; Param.width = width; Param.height = height; Param.pszHTML = pszHTMLStr; Param.pszTitle = pszTitle; Param.hWnd = 0; PostThreadMessage (m_dwThread, WM_USER, 0, (LPARAM)&Param); WaitForSingleObject (m_hEvent, INFINITE); return (void*)Param.hWnd; } // ----------------------------------------------------------------------------- void W32Browser_CloseWindow (void *pWnd) { PostThreadMessage (m_dwThread, WM_USER+1, 0, (LPARAM)pWnd); }