comparison win/browser.c @ 584:420c6c94abc7

Added dw_html_* functionality for embedding HTML pages in Dynamic Windows applications.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sun, 22 May 2005 18:07:23 +0000
parents
children f253a7559a59
comparison
equal deleted inserted replaced
583:67dfd0cea50d 584:420c6c94abc7
1 /* Browser.c
2
3 This is a Win32 C application (ie, no MFC, WTL, nor even any C++ -- just plain C) that demonstrates
4 how to embed a browser "control" (actually, an OLE object) in your own window (in order to display a
5 web page, or an HTML file on disk).
6
7 The example opens a main window with a child window into which we embed the browser object. We also
8 put "Back", "Forward", and "Stop" buttons in the main window to control the browser navigation. We
9 size the child window containing the browser so that there is room at the top of the main window for
10 the buttons. We also disable the pop-up context menu.
11
12 This is very loosely based upon a C++ example written by Chris Becke. I used that to learn the minimum
13 of what I needed to know about hosting the browser object. Then I wrote this example from the ground up
14 in C.
15
16 This requires IE 5.0 (or better) -- due to the IDocHostUIHandler interface, or a browser that supports
17 the same level of OLE in-place activation.
18 */
19
20
21
22
23
24 #include <windows.h>
25 #include <exdisp.h> // Defines of stuff like IWebBrowser2. This is an include file with Visual C 6 and above
26 #include <mshtml.h> // Defines of stuff like IHTMLDocument2. This is an include file with Visual C 6 and above
27 #include <mshtmhst.h> // Defines of stuff like IDocHostUIHandler. This is an include file with Visual C 6 and above
28 #include <crtdbg.h> // for _ASSERT()
29 #include "dw.h"
30
31 // This is used by DisplayHTMLStr(). It can be global because we never change it.
32 static const SAFEARRAYBOUND ArrayBound = {1, 0};
33
34 // Our IStorage functions that the browser may call
35 HRESULT STDMETHODCALLTYPE Storage_QueryInterface(IStorage FAR* This, REFIID riid, LPVOID FAR* ppvObj);
36 HRESULT STDMETHODCALLTYPE Storage_AddRef(IStorage FAR* This);
37 HRESULT STDMETHODCALLTYPE Storage_Release(IStorage FAR* This);
38 HRESULT STDMETHODCALLTYPE Storage_CreateStream(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
39 HRESULT STDMETHODCALLTYPE Storage_OpenStream(IStorage FAR* This, const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
40 HRESULT STDMETHODCALLTYPE Storage_CreateStorage(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg);
41 HRESULT STDMETHODCALLTYPE Storage_OpenStorage(IStorage FAR* This, const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
42 HRESULT STDMETHODCALLTYPE Storage_CopyTo(IStorage FAR* This, DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest);
43 HRESULT STDMETHODCALLTYPE Storage_MoveElementTo(IStorage FAR* This, const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags);
44 HRESULT STDMETHODCALLTYPE Storage_Commit(IStorage FAR* This, DWORD grfCommitFlags);
45 HRESULT STDMETHODCALLTYPE Storage_Revert(IStorage FAR* This);
46 HRESULT STDMETHODCALLTYPE Storage_EnumElements(IStorage FAR* This, DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum);
47 HRESULT STDMETHODCALLTYPE Storage_DestroyElement(IStorage FAR* This, const OLECHAR *pwcsName);
48 HRESULT STDMETHODCALLTYPE Storage_RenameElement(IStorage FAR* This, const WCHAR *pwcsOldName, const WCHAR *pwcsNewName);
49 HRESULT STDMETHODCALLTYPE Storage_SetElementTimes(IStorage FAR* This, const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime);
50 HRESULT STDMETHODCALLTYPE Storage_SetClass(IStorage FAR* This, REFCLSID clsid);
51 HRESULT STDMETHODCALLTYPE Storage_SetStateBits(IStorage FAR* This, DWORD grfStateBits, DWORD grfMask);
52 HRESULT STDMETHODCALLTYPE Storage_Stat(IStorage FAR* This, STATSTG * pstatstg, DWORD grfStatFlag);
53
54 // Our IStorage VTable. This is the array of pointers to the above functions in our C
55 // program that someone may call in order to store some data to disk. We must define a
56 // particular set of functions that comprise the IStorage set of functions (see above),
57 // and then stuff pointers to those functions in their respective 'slots' in this table.
58 // We want the browser to use this VTable with our IStorage structure (object).
59 IStorageVtbl MyIStorageTable = {Storage_QueryInterface,
60 Storage_AddRef,
61 Storage_Release,
62 Storage_CreateStream,
63 Storage_OpenStream,
64 Storage_CreateStorage,
65 Storage_OpenStorage,
66 Storage_CopyTo,
67 Storage_MoveElementTo,
68 Storage_Commit,
69 Storage_Revert,
70 Storage_EnumElements,
71 Storage_DestroyElement,
72 Storage_RenameElement,
73 Storage_SetElementTimes,
74 Storage_SetClass,
75 Storage_SetStateBits,
76 Storage_Stat};
77
78 // Our IStorage structure. NOTE: All it contains is a pointer to our IStorageVtbl, so we can easily initialize it
79 // here instead of doing that programmably.
80 IStorage MyIStorage = { &MyIStorageTable };
81
82 // Our IOleInPlaceFrame functions that the browser may call
83 HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj);
84 HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This);
85 HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This);
86 HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd);
87 HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode);
88 HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder);
89 HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths);
90 HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths);
91 HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName);
92 HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
93 HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
94 HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared);
95 HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText);
96 HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable);
97 HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID);
98
99 // Our IOleInPlaceFrame VTable. This is the array of pointers to the above functions in our C
100 // program that the browser may call in order to interact with our frame window that contains
101 // the browser object. We must define a particular set of functions that comprise the
102 // IOleInPlaceFrame set of functions (see above), and then stuff pointers to those functions
103 // in their respective 'slots' in this table. We want the browser to use this VTable with our
104 // IOleInPlaceFrame structure.
105 IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {Frame_QueryInterface,
106 Frame_AddRef,
107 Frame_Release,
108 Frame_GetWindow,
109 Frame_ContextSensitiveHelp,
110 Frame_GetBorder,
111 Frame_RequestBorderSpace,
112 Frame_SetBorderSpace,
113 Frame_SetActiveObject,
114 Frame_InsertMenus,
115 Frame_SetMenu,
116 Frame_RemoveMenus,
117 Frame_SetStatusText,
118 Frame_EnableModeless,
119 Frame_TranslateAccelerator};
120
121 // We need to return an IOleInPlaceFrame struct to the browser object. And one of our IOleInPlaceFrame
122 // functions (Frame_GetWindow) is going to need to access our window handle. So let's create our own
123 // struct that starts off with an IOleInPlaceFrame struct (and that's important -- the IOleInPlaceFrame
124 // struct *must* be first), and then has an extra data field where we can store our own window's HWND.
125 //
126 // And because we may want to create multiple windows, each hosting its own browser object (to
127 // display its own web page), then we need to create a IOleInPlaceFrame struct for each window. So,
128 // we're not going to declare our IOleInPlaceFrame struct globally. We'll allocate it later using
129 // GlobalAlloc, and then stuff the appropriate HWND in it then, and also stuff a pointer to
130 // MyIOleInPlaceFrameTable in it. But let's just define it here.
131 typedef struct {
132 IOleInPlaceFrame frame; // The IOleInPlaceFrame must be first!
133
134 ///////////////////////////////////////////////////
135 // Here you add any extra variables that you need
136 // to access in your IOleInPlaceFrame functions.
137 // You don't want those functions to access global
138 // variables, because then you couldn't use more
139 // than one browser object. (ie, You couldn't have
140 // multiple windows, each with its own embedded
141 // browser object to display a different web page).
142 //
143 // So here is where I added my extra HWND that my
144 // IOleInPlaceFrame function Frame_GetWindow() needs
145 // to access.
146 ///////////////////////////////////////////////////
147 HWND window;
148 } _IOleInPlaceFrameEx;
149
150
151
152
153
154
155 // Our IOleClientSite functions that the browser may call
156 HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject);
157 HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This);
158 HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This);
159 HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This);
160 HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk);
161 HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer);
162 HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This);
163 HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow);
164 HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This);
165
166 // Our IOleClientSite VTable. This is the array of pointers to the above functions in our C
167 // program that the browser may call in order to interact with our frame window that contains
168 // the browser object. We must define a particular set of functions that comprise the
169 // IOleClientSite set of functions (see above), and then stuff pointers to those functions
170 // in their respective 'slots' in this table. We want the browser to use this VTable with our
171 // IOleClientSite structure.
172 IOleClientSiteVtbl MyIOleClientSiteTable = {Site_QueryInterface,
173 Site_AddRef,
174 Site_Release,
175 Site_SaveObject,
176 Site_GetMoniker,
177 Site_GetContainer,
178 Site_ShowObject,
179 Site_OnShowWindow,
180 Site_RequestNewObjectLayout};
181
182
183
184
185
186
187 // Our IDocHostUIHandler functions that the browser may call
188 HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR* This, REFIID riid, void ** ppvObject);
189 HRESULT STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR* This);
190 HRESULT STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR* This);
191 HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(IDocHostUIHandler FAR* This, DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved);
192 HRESULT STDMETHODCALLTYPE UI_GetHostInfo(IDocHostUIHandler FAR* This, DOCHOSTUIINFO __RPC_FAR *pInfo);
193 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);
194 HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR* This);
195 HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR* This);
196 HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR* This, BOOL fEnable);
197 HRESULT STDMETHODCALLTYPE UI_OnDocWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate);
198 HRESULT STDMETHODCALLTYPE UI_OnFrameWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate);
199 HRESULT STDMETHODCALLTYPE UI_ResizeBorder(IDocHostUIHandler FAR* This, LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow);
200 HRESULT STDMETHODCALLTYPE UI_TranslateAccelerator(IDocHostUIHandler FAR* This, LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID);
201 HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(IDocHostUIHandler FAR* This, LPOLESTR __RPC_FAR *pchKey, DWORD dw);
202 HRESULT STDMETHODCALLTYPE UI_GetDropTarget(IDocHostUIHandler FAR* This, IDropTarget __RPC_FAR *pDropTarget, IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget);
203 HRESULT STDMETHODCALLTYPE UI_GetExternal(IDocHostUIHandler FAR* This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
204 HRESULT STDMETHODCALLTYPE UI_TranslateUrl(IDocHostUIHandler FAR* This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut);
205 HRESULT STDMETHODCALLTYPE UI_FilterDataObject(IDocHostUIHandler FAR* This, IDataObject __RPC_FAR *pDO, IDataObject __RPC_FAR *__RPC_FAR *ppDORet);
206
207 // Our IDocHostUIHandler VTable. This is the array of pointers to the above functions in our C
208 // program that the browser may call in order to replace/set certain user interface considerations
209 // (such as whether to display a pop-up context menu when the user right-clicks on the embedded
210 // browser object). We must define a particular set of functions that comprise the
211 // IDocHostUIHandler set of functions (see above), and then stuff pointers to those functions
212 // in their respective 'slots' in this table. We want the browser to use this VTable with our
213 // IDocHostUIHandler structure.
214 IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = {UI_QueryInterface,
215 UI_AddRef,
216 UI_Release,
217 UI_ShowContextMenu,
218 UI_GetHostInfo,
219 UI_ShowUI,
220 UI_HideUI,
221 UI_UpdateUI,
222 UI_EnableModeless,
223 UI_OnDocWindowActivate,
224 UI_OnFrameWindowActivate,
225 UI_ResizeBorder,
226 UI_TranslateAccelerator,
227 UI_GetOptionKeyPath,
228 UI_GetDropTarget,
229 UI_GetExternal,
230 UI_TranslateUrl,
231 UI_FilterDataObject};
232
233 // We'll allocate our IDocHostUIHandler object dynamically with GlobalAlloc() for reasons outlined later.
234
235
236
237 // Our IOleInPlaceSite functions that the browser may call
238 HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(IOleInPlaceSite FAR* This, REFIID riid, void ** ppvObject);
239 HRESULT STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR* This);
240 HRESULT STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR* This);
241 HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd);
242 HRESULT STDMETHODCALLTYPE InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode);
243 HRESULT STDMETHODCALLTYPE InPlace_CanInPlaceActivate(IOleInPlaceSite FAR* This);
244 HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceActivate(IOleInPlaceSite FAR* This);
245 HRESULT STDMETHODCALLTYPE InPlace_OnUIActivate(IOleInPlaceSite FAR* This);
246 HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame,LPOLEINPLACEUIWINDOW FAR* lplpDoc,LPRECT lprcPosRect,LPRECT lprcClipRect,LPOLEINPLACEFRAMEINFO lpFrameInfo);
247 HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent);
248 HRESULT STDMETHODCALLTYPE InPlace_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable);
249 HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR* This);
250 HRESULT STDMETHODCALLTYPE InPlace_DiscardUndoState(IOleInPlaceSite FAR* This);
251 HRESULT STDMETHODCALLTYPE InPlace_DeactivateAndUndo(IOleInPlaceSite FAR* This);
252 HRESULT STDMETHODCALLTYPE InPlace_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect);
253
254 // Our IOleInPlaceSite VTable. This is the array of pointers to the above functions in our C
255 // program that the browser may call in order to interact with our frame window that contains
256 // the browser object. We must define a particular set of functions that comprise the
257 // IOleInPlaceSite set of functions (see above), and then stuff pointers to those functions
258 // in their respective 'slots' in this table. We want the browser to use this VTable with our
259 // IOleInPlaceSite structure.
260 IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = {InPlace_QueryInterface,
261 InPlace_AddRef,
262 InPlace_Release,
263 InPlace_GetWindow,
264 InPlace_ContextSensitiveHelp,
265 InPlace_CanInPlaceActivate,
266 InPlace_OnInPlaceActivate,
267 InPlace_OnUIActivate,
268 InPlace_GetWindowContext,
269 InPlace_Scroll,
270 InPlace_OnUIDeactivate,
271 InPlace_OnInPlaceDeactivate,
272 InPlace_DiscardUndoState,
273 InPlace_DeactivateAndUndo,
274 InPlace_OnPosRectChange};
275
276 // We need to pass our IOleClientSite structure to OleCreate (which in turn gives it to the browser).
277 // But the browser is also going to ask our IOleClientSite's QueryInterface() to return a pointer to
278 // our IOleInPlaceSite and/or IDocHostUIHandler structs. So we'll need to have those pointers handy.
279 // Plus, some of our IOleClientSite and IOleInPlaceSite functions will need to have the HWND to our
280 // window, and also a pointer to our IOleInPlaceFrame struct. So let's create a single struct that
281 // has the IOleClientSite, IOleInPlaceSite, IDocHostUIHandler, and IOleInPlaceFrame structs all inside
282 // it (so we can easily get a pointer to any one from any of those structs' functions). As long as the
283 // IOleClientSite struct is the very first thing in this custom struct, it's all ok. We can still pass
284 // it to OleCreate() and pretend that it's an ordinary IOleClientSite. We'll call this new struct a
285 // _IOleClientSiteEx.
286 //
287 // And because we may want to create multiple windows, each hosting its own browser object (to
288 // display its own web page), then we need to create a unique _IOleClientSiteEx struct for
289 // each window. So, we're not going to declare this struct globally. We'll allocate it later
290 // using GlobalAlloc, and then initialize the structs within it.
291
292 typedef struct {
293 IOleInPlaceSite inplace; // My IOleInPlaceSite object. Must be first with in _IOleInPlaceSiteEx.
294
295 ///////////////////////////////////////////////////
296 // Here you add any extra variables that you need
297 // to access in your IOleInPlaceSite functions.
298 //
299 // So here is where I added my IOleInPlaceFrame
300 // struct. If you need extra variables, add them
301 // at the end.
302 ///////////////////////////////////////////////////
303 _IOleInPlaceFrameEx frame; // My IOleInPlaceFrame object. Must be first within my _IOleInPlaceFrameEx
304 } _IOleInPlaceSiteEx;
305
306 typedef struct {
307 IDocHostUIHandler ui; // My IDocHostUIHandler object. Must be first.
308
309 ///////////////////////////////////////////////////
310 // Here you add any extra variables that you need
311 // to access in your IDocHostUIHandler functions.
312 ///////////////////////////////////////////////////
313 } _IDocHostUIHandlerEx;
314
315 typedef struct {
316 IOleClientSite client; // My IOleClientSite object. Must be first.
317 _IOleInPlaceSiteEx inplace; // My IOleInPlaceSite object. A convenient place to put it.
318 _IDocHostUIHandlerEx ui; // My IDocHostUIHandler object. Must be first within my _IDocHostUIHandlerEx.
319
320 ///////////////////////////////////////////////////
321 // Here you add any extra variables that you need
322 // to access in your IOleClientSite functions.
323 ///////////////////////////////////////////////////
324 } _IOleClientSiteEx;
325
326 // This is a simple C example. There are lots more things you can control about the browser object, but
327 // we don't do it in this example. _Many_ of the functions we provide below for the browser to call, will
328 // never actually be called by the browser in our example. Why? Because we don't do certain things
329 // with the browser that would require it to call those functions (even though we need to provide
330 // at least some stub for all of the functions).
331 //
332 // So, for these "dummy functions" that we don't expect the browser to call, we'll just stick in some
333 // assembly code that causes a debugger breakpoint and tells the browser object that we don't support
334 // the functionality. That way, if you try to do more things with the browser object, and it starts
335 // calling these "dummy functions", you'll know which ones you should add more meaningful code to.
336 #define NOTIMPLEMENTED _ASSERT(0); return(E_NOTIMPL)
337
338
339
340
341
342 //////////////////////////////////// My IDocHostUIHandler functions //////////////////////////////////////
343 // The browser object asks us for the pointer to our IDocHostUIHandler object by calling our IOleClientSite's
344 // QueryInterface (ie, Site_QueryInterface) and specifying a REFIID of IID_IDocHostUIHandler.
345 //
346 // NOTE: You need at least IE 4.0. Previous versions do not ask for, nor utilize, our IDocHostUIHandler functions.
347
348 HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR* This, REFIID riid, LPVOID FAR* ppvObj)
349 {
350 // The browser assumes that our IDocHostUIHandler object is associated with our IOleClientSite
351 // object. So it is possible that the browser may call our IDocHostUIHandler's QueryInterface()
352 // to ask us to return a pointer to our IOleClientSite, in the same way that the browser calls
353 // our IOleClientSite's QueryInterface() to ask for a pointer to our IDocHostUIHandler.
354 //
355 // Rather than duplicate much of the code in IOleClientSite's QueryInterface, let's just get
356 // a pointer to our _IOleClientSiteEx object, substitute it as the 'This' arg, and call our
357 // our IOleClientSite's QueryInterface. Note that since our _IDocHostUIHandlerEx is embedded right
358 // inside our _IOleClientSiteEx, and comes immediately after the _IOleInPlaceSiteEx, we can employ
359 // the following trickery to get the pointer to our _IOleClientSiteEx.
360 return(Site_QueryInterface((IOleClientSite *)((char *)This - sizeof(IOleClientSite) - sizeof(_IOleInPlaceSiteEx)), riid, ppvObj));
361 }
362
363 HRESULT STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR* This)
364 {
365 return(1);
366 }
367
368 HRESULT STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR* This)
369 {
370 return(1);
371 }
372
373 // Called when the browser object is about to display its context menu.
374 HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(IDocHostUIHandler FAR* This, DWORD dwID, POINT __RPC_FAR *ppt, IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved)
375 {
376 // If desired, we can pop up your own custom context menu here. Of course,
377 // we would need some way to get our window handle, so what we'd probably
378 // do is like what we did with our IOleInPlaceFrame object. We'd define and create
379 // our own IDocHostUIHandlerEx object with an embedded IDocHostUIHandler at the
380 // start of it. Then we'd add an extra HWND field to store our window handle.
381 // It could look like this:
382 //
383 // typedef struct _IDocHostUIHandlerEx {
384 // IDocHostUIHandler ui; // The IDocHostUIHandler must be first!
385 // HWND window;
386 // } IDocHostUIHandlerEx;
387 //
388 // Of course, we'd need a unique IDocHostUIHandlerEx object for each window, so
389 // EmbedBrowserObject() would have to allocate one of those too. And that's
390 // what we'd pass to our browser object (and it would in turn pass it to us
391 // here, instead of 'This' being a IDocHostUIHandler *).
392
393 // We will return S_OK to tell the browser not to display its default context menu,
394 // or return S_FALSE to let the browser show its default context menu. For this
395 // example, we wish to disable the browser's default context menu.
396 return(S_OK);
397 }
398
399 // Called at initialization of the browser object UI. We can set various features of the browser object here.
400 HRESULT STDMETHODCALLTYPE UI_GetHostInfo(IDocHostUIHandler FAR* This, DOCHOSTUIINFO __RPC_FAR *pInfo)
401 {
402 pInfo->cbSize = sizeof(DOCHOSTUIINFO);
403
404 // Set some flags. We don't want any 3D border. You can do other things like hide
405 // the scroll bar (DOCHOSTUIFLAG_SCROLL_NO), display picture display (DOCHOSTUIFLAG_NOPICS),
406 // disable any script running when the page is loaded (DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE),
407 // open a site in a new browser window when the user clicks on some link (DOCHOSTUIFLAG_OPENNEWWIN),
408 // and lots of other things. See the MSDN docs on the DOCHOSTUIINFO struct passed to us.
409 pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER;
410
411 // Set what happens when the user double-clicks on the object. Here we use the default.
412 pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
413
414 return(S_OK);
415 }
416
417 // Called when the browser object shows its UI. This allows us to replace its menus and toolbars by creating our
418 // own and displaying them here.
419 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)
420 {
421 // We've already got our own UI in place so just return S_OK to tell the browser
422 // not to display its menus/toolbars. Otherwise we'd return S_FALSE to let it do
423 // that.
424 return(S_OK);
425 }
426
427 // Called when browser object hides its UI. This allows us to hide any menus/toolbars we created in ShowUI.
428 HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR* This)
429 {
430 return(S_OK);
431 }
432
433 // Called when the browser object wants to notify us that the command state has changed. We should update any
434 // controls we have that are dependent upon our embedded object, such as "Back", "Forward", "Stop", or "Home"
435 // buttons.
436 HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR* This)
437 {
438 // We update our UI in our window message loop so we don't do anything here.
439 return(S_OK);
440 }
441
442 // Called from the browser object's IOleInPlaceActiveObject object's EnableModeless() function. Also
443 // called when the browser displays a modal dialog box.
444 HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR* This, BOOL fEnable)
445 {
446 return(S_OK);
447 }
448
449 // Called from the browser object's IOleInPlaceActiveObject object's OnDocWindowActivate() function.
450 // This informs off of when the object is getting/losing the focus.
451 HRESULT STDMETHODCALLTYPE UI_OnDocWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate)
452 {
453 return(S_OK);
454 }
455
456 // Called from the browser object's IOleInPlaceActiveObject object's OnFrameWindowActivate() function.
457 HRESULT STDMETHODCALLTYPE UI_OnFrameWindowActivate(IDocHostUIHandler FAR* This, BOOL fActivate)
458 {
459 return(S_OK);
460 }
461
462 // Called from the browser object's IOleInPlaceActiveObject object's ResizeBorder() function.
463 HRESULT STDMETHODCALLTYPE UI_ResizeBorder(IDocHostUIHandler FAR* This, LPCRECT prcBorder, IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow)
464 {
465 return(S_OK);
466 }
467
468 // Called from the browser object's TranslateAccelerator routines to translate key strokes to commands.
469 HRESULT STDMETHODCALLTYPE UI_TranslateAccelerator(IDocHostUIHandler FAR* This, LPMSG lpMsg, const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID)
470 {
471 // We don't intercept any keystrokes, so we do nothing here. But for example, if we wanted to
472 // override the TAB key, perhaps do something with it ourselves, and then tell the browser
473 // not to do anything with this keystroke, we'd do:
474 //
475 // if (pMsg && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB)
476 // {
477 // // Here we do something as a result of a TAB key press.
478 //
479 // // Tell the browser not to do anything with it.
480 // return(S_FALSE);
481 // }
482 //
483 // // Otherwise, let the browser do something with this message.
484 // return(S_OK);
485
486 // For our example, we want to make sure that the user can invoke some key to popup the context
487 // menu, so we'll tell it to ignore all messages.
488 return(S_FALSE);
489 }
490
491 // Called by the browser object to find where the host wishes the browser to get its options in the registry.
492 // We can use this to prevent the browser from using its default settings in the registry, by telling it to use
493 // some other registry key we've setup with the options we want.
494 HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(IDocHostUIHandler FAR* This, LPOLESTR __RPC_FAR *pchKey, DWORD dw)
495 {
496 // Let the browser use its default registry settings.
497 return(S_FALSE);
498 }
499
500 // Called by the browser object when it is used as a drop target. We can supply our own IDropTarget object,
501 // IDropTarget functions, and IDropTarget VTable if we want to determine what happens when someone drags and
502 // drops some object on our embedded browser object.
503 HRESULT STDMETHODCALLTYPE UI_GetDropTarget(IDocHostUIHandler FAR* This, IDropTarget __RPC_FAR *pDropTarget, IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget)
504 {
505 // Return our IDropTarget object associated with this IDocHostUIHandler object. I don't
506 // know why we don't do this via UI_QueryInterface(), but we don't.
507
508 // NOTE: If we want/need an IDropTarget interface, then we would have had to setup our own
509 // IDropTarget functions, IDropTarget VTable, and create an IDropTarget object. We'd want to put
510 // a pointer to the IDropTarget object in our own custom IDocHostUIHandlerEx object (like how
511 // we may add an HWND field for the use of UI_ShowContextMenu). So when we created our
512 // IDocHostUIHandlerEx object, maybe we'd add a 'idrop' field to the end of it, and
513 // store a pointer to our IDropTarget object there. Then we could return this pointer as so:
514 //
515 // *pDropTarget = ((IDocHostUIHandlerEx FAR *)This)->idrop;
516 // return(S_OK);
517
518 // But for our purposes, we don't need an IDropTarget object, so we'll tell whomever is calling
519 // us that we don't have one.
520 return(S_FALSE);
521 }
522
523 // Called by the browser when it wants a pointer to our IDispatch object. This object allows us to expose
524 // our own automation interface (ie, our own COM objects) to other entities that are running within the
525 // context of the browser so they can call our functions if they want. An example could be a javascript
526 // running in the URL we display could call our IDispatch functions. We'd write them so that any args passed
527 // to them would use the generic datatypes like a BSTR for utmost flexibility.
528 HRESULT STDMETHODCALLTYPE UI_GetExternal(IDocHostUIHandler FAR* This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
529 {
530 // Return our IDispatch object associated with this IDocHostUIHandler object. I don't
531 // know why we don't do this via UI_QueryInterface(), but we don't.
532
533 // NOTE: If we want/need an IDispatch interface, then we would have had to setup our own
534 // IDispatch functions, IDispatch VTable, and create an IDispatch object. We'd want to put
535 // a pointer to the IDispatch object in our custom _IDocHostUIHandlerEx object (like how
536 // we may add an HWND field for the use of UI_ShowContextMenu). So when we defined our
537 // _IDocHostUIHandlerEx object, maybe we'd add a 'idispatch' field to the end of it, and
538 // store a pointer to our IDispatch object there. Then we could return this pointer as so:
539 //
540 // *ppDispatch = ((_IDocHostUIHandlerEx FAR *)This)->idispatch;
541 // return(S_OK);
542
543 // But for our purposes, we don't need an IDispatch object, so we'll tell whomever is calling
544 // us that we don't have one. Note: We must set ppDispatch to 0 if we don't return our own
545 // IDispatch object.
546 *ppDispatch = 0;
547 return(S_FALSE);
548 }
549
550 // Called by the browser object to give us an opportunity to modify the URL to be loaded.
551 HRESULT STDMETHODCALLTYPE UI_TranslateUrl(IDocHostUIHandler FAR* This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn, OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut)
552 {
553 // We don't need to modify the URL. Note: We need to set ppchURLOut to 0 if we don't
554 // return an OLECHAR (buffer) containing a modified version of pchURLIn.
555 *ppchURLOut = 0;
556 return(S_FALSE);
557 }
558
559 // Called by the browser when it does cut/paste to the clipboard. This allows us to block certain clipboard
560 // formats or support additional clipboard formats.
561 HRESULT STDMETHODCALLTYPE UI_FilterDataObject(IDocHostUIHandler FAR* This, IDataObject __RPC_FAR *pDO, IDataObject __RPC_FAR *__RPC_FAR *ppDORet)
562 {
563 // Return our IDataObject object associated with this IDocHostUIHandler object. I don't
564 // know why we don't do this via UI_QueryInterface(), but we don't.
565
566 // NOTE: If we want/need an IDataObject interface, then we would have had to setup our own
567 // IDataObject functions, IDataObject VTable, and create an IDataObject object. We'd want to put
568 // a pointer to the IDataObject object in our custom _IDocHostUIHandlerEx object (like how
569 // we may add an HWND field for the use of UI_ShowContextMenu). So when we defined our
570 // _IDocHostUIHandlerEx object, maybe we'd add a 'idata' field to the end of it, and
571 // store a pointer to our IDataObject object there. Then we could return this pointer as so:
572 //
573 // *ppDORet = ((_IDocHostUIHandlerEx FAR *)This)->idata;
574 // return(S_OK);
575
576 // But for our purposes, we don't need an IDataObject object, so we'll tell whomever is calling
577 // us that we don't have one. Note: We must set ppDORet to 0 if we don't return our own
578 // IDataObject object.
579 *ppDORet = 0;
580 return(S_FALSE);
581 }
582
583
584
585
586
587 ////////////////////////////////////// My IStorage functions /////////////////////////////////////////
588 // NOTE: The browser object doesn't use the IStorage functions, so most of these are us just returning
589 // E_NOTIMPL so that anyone who *does* call these functions knows nothing is being done here.
590 //
591 // We give the browser object a pointer to our IStorage object when we call OleCreate().
592
593 HRESULT STDMETHODCALLTYPE Storage_QueryInterface(IStorage FAR* This, REFIID riid, LPVOID FAR* ppvObj)
594 {
595 NOTIMPLEMENTED;
596 }
597
598 HRESULT STDMETHODCALLTYPE Storage_AddRef(IStorage FAR* This)
599 {
600 return(1);
601 }
602
603 HRESULT STDMETHODCALLTYPE Storage_Release(IStorage FAR* This)
604 {
605 return(1);
606 }
607
608 HRESULT STDMETHODCALLTYPE Storage_CreateStream(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
609 {
610 NOTIMPLEMENTED;
611 }
612
613 HRESULT STDMETHODCALLTYPE Storage_OpenStream(IStorage FAR* This, const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
614 {
615 NOTIMPLEMENTED;
616 }
617
618 HRESULT STDMETHODCALLTYPE Storage_CreateStorage(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg)
619 {
620 NOTIMPLEMENTED;
621 }
622
623 HRESULT STDMETHODCALLTYPE Storage_OpenStorage(IStorage FAR* This, const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
624 {
625 NOTIMPLEMENTED;
626 }
627
628 HRESULT STDMETHODCALLTYPE Storage_CopyTo(IStorage FAR* This, DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest)
629 {
630 NOTIMPLEMENTED;
631 }
632
633 HRESULT STDMETHODCALLTYPE Storage_MoveElementTo(IStorage FAR* This, const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags)
634 {
635 NOTIMPLEMENTED;
636 }
637
638 HRESULT STDMETHODCALLTYPE Storage_Commit(IStorage FAR* This, DWORD grfCommitFlags)
639 {
640 NOTIMPLEMENTED;
641 }
642
643 HRESULT STDMETHODCALLTYPE Storage_Revert(IStorage FAR* This)
644 {
645 NOTIMPLEMENTED;
646 }
647
648 HRESULT STDMETHODCALLTYPE Storage_EnumElements(IStorage FAR* This, DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum)
649 {
650 NOTIMPLEMENTED;
651 }
652
653 HRESULT STDMETHODCALLTYPE Storage_DestroyElement(IStorage FAR* This, const OLECHAR *pwcsName)
654 {
655 NOTIMPLEMENTED;
656 }
657
658 HRESULT STDMETHODCALLTYPE Storage_RenameElement(IStorage FAR* This, const WCHAR *pwcsOldName, const WCHAR *pwcsNewName)
659 {
660 NOTIMPLEMENTED;
661 }
662
663 HRESULT STDMETHODCALLTYPE Storage_SetElementTimes(IStorage FAR* This, const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime)
664 {
665 NOTIMPLEMENTED;
666 }
667
668 HRESULT STDMETHODCALLTYPE Storage_SetClass(IStorage FAR* This, REFCLSID clsid)
669 {
670 return(S_OK);
671 }
672
673 HRESULT STDMETHODCALLTYPE Storage_SetStateBits(IStorage FAR* This, DWORD grfStateBits, DWORD grfMask)
674 {
675 NOTIMPLEMENTED;
676 }
677
678 HRESULT STDMETHODCALLTYPE Storage_Stat(IStorage FAR* This, STATSTG * pstatstg, DWORD grfStatFlag)
679 {
680 NOTIMPLEMENTED;
681 }
682
683
684
685
686
687
688
689
690
691 ////////////////////////////////////// My IOleClientSite functions /////////////////////////////////////
692 // We give the browser object a pointer to our IOleClientSite object when we call OleCreate() or DoVerb().
693
694 /************************* Site_QueryInterface() *************************
695 * The browser object calls this when it wants a pointer to one of our
696 * IOleClientSite, IDocHostUIHandler, or IOleInPlaceSite structures. They
697 * are all accessible via the _IOleClientSiteEx struct we allocated in
698 * EmbedBrowserObject() and passed to DoVerb() and OleCreate().
699 *
700 * This = A pointer to whatever _IOleClientSiteEx struct we passed to
701 * OleCreate() or DoVerb().
702 * riid = A GUID struct that the browser passes us to clue us as to
703 * which type of struct (object) it would like a pointer
704 * returned for.
705 * ppvObject = Where the browser wants us to return a pointer to the
706 * appropriate struct. (ie, It passes us a handle to fill in).
707 *
708 * RETURNS: S_OK if we return the struct, or E_NOINTERFACE if we don't have
709 * the requested struct.
710 */
711
712 HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject)
713 {
714 // It just so happens that the first arg passed to us is our _IOleClientSiteEx struct we allocated
715 // and passed to DoVerb() and OleCreate(). Nevermind that 'This' is declared is an IOleClientSite *.
716 // Remember that in EmbedBrowserObject(), we allocated our own _IOleClientSiteEx struct, and lied
717 // to OleCreate() and DoVerb() -- passing our _IOleClientSiteEx struct and saying it was an
718 // IOleClientSite struct. It's ok. An _IOleClientSiteEx starts with an embedded IOleClientSite, so
719 // the browser didn't mind. So that's what the browser object is passing us now. The browser doesn't
720 // know that it's really an _IOleClientSiteEx struct. But we do. So we can recast it and use it as
721 // so here.
722
723 // If the browser is asking us to match IID_IOleClientSite, then it wants us to return a pointer to
724 // our IOleClientSite struct. Then the browser will use the VTable in that struct to call our
725 // IOleClientSite functions. It will also pass this same pointer to all of our IOleClientSite
726 // functions.
727 //
728 // Actually, we're going to lie to the browser again. We're going to return our own _IOleClientSiteEx
729 // struct, and tell the browser that it's a IOleClientSite struct. It's ok. The first thing in our
730 // _IOleClientSiteEx is an embedded IOleClientSite, so the browser doesn't mind. We want the browser
731 // to continue passing our _IOleClientSiteEx pointer wherever it would normally pass a IOleClientSite
732 // pointer.
733 //
734 // The IUnknown interface uses the same VTable as the first object in our _IOleClientSiteEx
735 // struct (which happens to be an IOleClientSite). So if the browser is asking us to match
736 // IID_IUnknown, then we'll also return a pointer to our _IOleClientSiteEx.
737
738 if (!memcmp(riid, &IID_IUnknown, sizeof(GUID)) || !memcmp(riid, &IID_IOleClientSite, sizeof(GUID)))
739 *ppvObject = &((_IOleClientSiteEx *)This)->client;
740
741 // If the browser is asking us to match IID_IOleInPlaceSite, then it wants us to return a pointer to
742 // our IOleInPlaceSite struct. Then the browser will use the VTable in that struct to call our
743 // IOleInPlaceSite functions. It will also pass this same pointer to all of our IOleInPlaceSite
744 // functions (except for Site_QueryInterface, Site_AddRef, and Site_Release. Those will always get
745 // the pointer to our _IOleClientSiteEx.
746 //
747 // Actually, we're going to lie to the browser. We're going to return our own _IOleInPlaceSiteEx
748 // struct, and tell the browser that it's a IOleInPlaceSite struct. It's ok. The first thing in
749 // our _IOleInPlaceSiteEx is an embedded IOleInPlaceSite, so the browser doesn't mind. We want the
750 // browser to continue passing our _IOleInPlaceSiteEx pointer wherever it would normally pass a
751 // IOleInPlaceSite pointer.
752 else if (!memcmp(riid, &IID_IOleInPlaceSite, sizeof(GUID)))
753 *ppvObject = &((_IOleClientSiteEx *)This)->inplace;
754
755 // If the browser is asking us to match IID_IDocHostUIHandler, then it wants us to return a pointer to
756 // our IDocHostUIHandler struct. Then the browser will use the VTable in that struct to call our
757 // IDocHostUIHandler functions. It will also pass this same pointer to all of our IDocHostUIHandler
758 // functions (except for Site_QueryInterface, Site_AddRef, and Site_Release. Those will always get
759 // the pointer to our _IOleClientSiteEx.
760 //
761 // Actually, we're going to lie to the browser. We're going to return our own _IDocHostUIHandlerEx
762 // struct, and tell the browser that it's a IDocHostUIHandler struct. It's ok. The first thing in
763 // our _IDocHostUIHandlerEx is an embedded IDocHostUIHandler, so the browser doesn't mind. We want the
764 // browser to continue passing our _IDocHostUIHandlerEx pointer wherever it would normally pass a
765 // IDocHostUIHandler pointer. My, we're really playing dirty tricks on the browser here. heheh.
766 else if (!memcmp(riid, &IID_IDocHostUIHandler, sizeof(GUID)))
767 *ppvObject = &((_IOleClientSiteEx *)This)->ui;
768
769 // For other types of objects the browser wants, just report that we don't have any such objects.
770 // NOTE: If you want to add additional functionality to your browser hosting, you may need to
771 // provide some more objects here. You'll have to investigate what the browser is asking for
772 // (ie, what REFIID it is passing).
773 else
774 {
775 *ppvObject = 0;
776 return(E_NOINTERFACE);
777 }
778
779 return(S_OK);
780 }
781
782 HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This)
783 {
784 return(1);
785 }
786
787 HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This)
788 {
789 return(1);
790 }
791
792 HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This)
793 {
794 NOTIMPLEMENTED;
795 }
796
797 HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk)
798 {
799 NOTIMPLEMENTED;
800 }
801
802 HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer)
803 {
804 // Tell the browser that we are a simple object and don't support a container
805 *ppContainer = 0;
806
807 return(E_NOINTERFACE);
808 }
809
810 HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This)
811 {
812 return(NOERROR);
813 }
814
815 HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow)
816 {
817 NOTIMPLEMENTED;
818 }
819
820 HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This)
821 {
822 NOTIMPLEMENTED;
823 }
824
825
826
827
828
829
830
831
832
833
834
835 ////////////////////////////////////// My IOleInPlaceSite functions /////////////////////////////////////
836 // The browser object asks us for the pointer to our IOleInPlaceSite object by calling our IOleClientSite's
837 // QueryInterface (ie, Site_QueryInterface) and specifying a REFIID of IID_IOleInPlaceSite.
838
839 HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(IOleInPlaceSite FAR* This, REFIID riid, LPVOID FAR* ppvObj)
840 {
841 // The browser assumes that our IOleInPlaceSite object is associated with our IOleClientSite
842 // object. So it is possible that the browser may call our IOleInPlaceSite's QueryInterface()
843 // to ask us to return a pointer to our IOleClientSite, in the same way that the browser calls
844 // our IOleClientSite's QueryInterface() to ask for a pointer to our IOleInPlaceSite.
845 //
846 // Rather than duplicate much of the code in IOleClientSite's QueryInterface, let's just get
847 // a pointer to our _IOleClientSiteEx object, substitute it as the 'This' arg, and call our
848 // our IOleClientSite's QueryInterface. Note that since our IOleInPlaceSite is embedded right
849 // inside our _IOleClientSiteEx, and comes immediately after the IOleClientSite, we can employ
850 // the following trickery to get the pointer to our _IOleClientSiteEx.
851 return(Site_QueryInterface((IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj));
852 }
853
854 HRESULT STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR* This)
855 {
856 return(1);
857 }
858
859 HRESULT STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR* This)
860 {
861 return(1);
862 }
863
864 HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd)
865 {
866 // Return the HWND of the window that contains this browser object. We stored that
867 // HWND in our _IOleInPlaceSiteEx struct. Nevermind that the function declaration for
868 // Site_GetWindow says that 'This' is an IOleInPlaceSite *. Remember that in
869 // EmbedBrowserObject(), we allocated our own _IOleInPlaceSiteEx struct which
870 // contained an embedded IOleInPlaceSite struct within it. And when the browser
871 // called Site_QueryInterface() to get a pointer to our IOleInPlaceSite object, we
872 // returned a pointer to our _IOleClientSiteEx. The browser doesn't know this. But
873 // we do. That's what we're really being passed, so we can recast it and use it as
874 // so here.
875 *lphwnd = ((_IOleInPlaceSiteEx FAR*)This)->frame.window;
876
877 return(S_OK);
878 }
879
880 HRESULT STDMETHODCALLTYPE InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode)
881 {
882 NOTIMPLEMENTED;
883 }
884
885 HRESULT STDMETHODCALLTYPE InPlace_CanInPlaceActivate(IOleInPlaceSite FAR* This)
886 {
887 // Tell the browser we can in place activate
888 return(S_OK);
889 }
890
891 HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceActivate(IOleInPlaceSite FAR* This)
892 {
893 // Tell the browser we did it ok
894 return(S_OK);
895 }
896
897 HRESULT STDMETHODCALLTYPE InPlace_OnUIActivate(IOleInPlaceSite FAR* This)
898 {
899 return(S_OK);
900 }
901
902 HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
903 {
904 // Give the browser the pointer to our IOleInPlaceFrame struct. We stored that pointer
905 // in our _IOleInPlaceSiteEx struct. Nevermind that the function declaration for
906 // Site_GetWindowContext says that 'This' is an IOleInPlaceSite *. Remember that in
907 // EmbedBrowserObject(), we allocated our own _IOleInPlaceSiteEx struct which
908 // contained an embedded IOleInPlaceSite struct within it. And when the browser
909 // called Site_QueryInterface() to get a pointer to our IOleInPlaceSite object, we
910 // returned a pointer to our _IOleClientSiteEx. The browser doesn't know this. But
911 // we do. That's what we're really being passed, so we can recast it and use it as
912 // so here.
913 //
914 // Actually, we're giving the browser a pointer to our own _IOleInPlaceSiteEx struct,
915 // but telling the browser that it's a IOleInPlaceSite struct. No problem. Our
916 // _IOleInPlaceSiteEx starts with an embedded IOleInPlaceSite, so the browser is
917 // cool with it. And we want the browser to pass a pointer to this _IOleInPlaceSiteEx
918 // wherever it would pass a IOleInPlaceSite struct to our IOleInPlaceSite functions.
919 *lplpFrame = (LPOLEINPLACEFRAME)&((_IOleInPlaceSiteEx *)This)->frame;
920
921 // We have no OLEINPLACEUIWINDOW
922 *lplpDoc = 0;
923
924 // Fill in some other info for the browser
925 lpFrameInfo->fMDIApp = FALSE;
926 lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window;
927 lpFrameInfo->haccel = 0;
928 lpFrameInfo->cAccelEntries = 0;
929
930 // Give the browser the dimensions of where it can draw. We give it our entire window to fill.
931 // We do this in InPlace_OnPosRectChange() which is called right when a window is first
932 // created anyway, so no need to duplicate it here.
933 // GetClientRect(lpFrameInfo->hwndFrame, lprcPosRect);
934 // GetClientRect(lpFrameInfo->hwndFrame, lprcClipRect);
935
936 return(S_OK);
937 }
938
939 HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent)
940 {
941 NOTIMPLEMENTED;
942 }
943
944 HRESULT STDMETHODCALLTYPE InPlace_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable)
945 {
946 return(S_OK);
947 }
948
949 HRESULT STDMETHODCALLTYPE InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR* This)
950 {
951 return(S_OK);
952 }
953
954 HRESULT STDMETHODCALLTYPE InPlace_DiscardUndoState(IOleInPlaceSite FAR* This)
955 {
956 NOTIMPLEMENTED;
957 }
958
959 HRESULT STDMETHODCALLTYPE InPlace_DeactivateAndUndo(IOleInPlaceSite FAR* This)
960 {
961 NOTIMPLEMENTED;
962 }
963
964 // Called when the position of the browser object is changed, such as when we call the IWebBrowser2's put_Width(),
965 // put_Height(), put_Left(), or put_Right().
966 HRESULT STDMETHODCALLTYPE InPlace_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect)
967 {
968 IOleObject *browserObject;
969 IOleInPlaceObject *inplace;
970
971 // We need to get the browser's IOleInPlaceObject object so we can call its SetObjectRects
972 // function.
973 browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) - sizeof(IOleClientSite)));
974 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IOleInPlaceObject, (void**)&inplace))
975 {
976 // Give the browser the dimensions of where it can draw.
977 inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect);
978 }
979
980 return(S_OK);
981 }
982
983
984
985
986
987
988
989 ////////////////////////////////////// My IOleInPlaceFrame functions /////////////////////////////////////////
990
991 HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj)
992 {
993 NOTIMPLEMENTED;
994 }
995
996 HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This)
997 {
998 return(1);
999 }
1000
1001 HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This)
1002 {
1003 return(1);
1004 }
1005
1006 HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd)
1007 {
1008 // Give the browser the HWND to our window that contains the browser object. We
1009 // stored that HWND in our IOleInPlaceFrame struct. Nevermind that the function
1010 // declaration for Frame_GetWindow says that 'This' is an IOleInPlaceFrame *. Remember
1011 // that in EmbedBrowserObject(), we allocated our own IOleInPlaceFrameEx struct which
1012 // contained an embedded IOleInPlaceFrame struct within it. And then we lied when
1013 // Site_GetWindowContext() returned that IOleInPlaceFrameEx. So that's what the
1014 // browser is passing us. It doesn't know that. But we do. So we can recast it and
1015 // use it as so here.
1016 *lphwnd = ((_IOleInPlaceFrameEx *)This)->window;
1017 return(S_OK);
1018 }
1019
1020 HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode)
1021 {
1022 NOTIMPLEMENTED;
1023 }
1024
1025 HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder)
1026 {
1027 NOTIMPLEMENTED;
1028 }
1029
1030 HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths)
1031 {
1032 NOTIMPLEMENTED;
1033 }
1034
1035 HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths)
1036 {
1037 NOTIMPLEMENTED;
1038 }
1039
1040 HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
1041 {
1042 return(S_OK);
1043 }
1044
1045 HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
1046 {
1047 NOTIMPLEMENTED;
1048 }
1049
1050 HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
1051 {
1052 return(S_OK);
1053 }
1054
1055 HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared)
1056 {
1057 NOTIMPLEMENTED;
1058 }
1059
1060 HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText)
1061 {
1062 return(S_OK);
1063 }
1064
1065 HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable)
1066 {
1067 return(S_OK);
1068 }
1069
1070 HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID)
1071 {
1072 NOTIMPLEMENTED;
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082 /*************************** UnEmbedBrowserObject() ************************
1083 * Called to detach the browser object from our host window, and free its
1084 * resources, right before we destroy our window.
1085 *
1086 * hwnd = Handle to the window hosting the browser object.
1087 *
1088 * NOTE: The pointer to the browser object must have been stored in the
1089 * window's USERDATA field. In other words, don't call UnEmbedBrowserObject().
1090 * with a HWND that wasn't successfully passed to EmbedBrowserObject().
1091 */
1092
1093 void _UnEmbedBrowserObject(HWND hwnd)
1094 {
1095 IOleObject **browserHandle;
1096 IOleObject *browserObject;
1097
1098 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when we
1099 // initially attached the browser object to this window. If 0, you may have called this
1100 // for a window that wasn't successfully passed to EmbedBrowserObject(). Bad boy! Or, we
1101 // may have failed the EmbedBrowserObject() call in WM_CREATE, in which case, our window
1102 // may get a WM_DESTROY which could call this a second time (ie, since we may call
1103 // UnEmbedBrowserObject in EmbedBrowserObject).
1104 if ((browserHandle = (IOleObject **)dw_window_get_data(hwnd, "_dw_html")))
1105 {
1106 // Unembed the browser object, and release its resources.
1107 browserObject = *browserHandle;
1108 browserObject->lpVtbl->Close(browserObject, OLECLOSE_NOSAVE);
1109 browserObject->lpVtbl->Release(browserObject);
1110
1111 // Zero out the pointer just in case UnEmbedBrowserObject is called again for this window
1112 dw_window_set_data(hwnd, "_dw_html", NULL);
1113 }
1114 }
1115
1116
1117
1118
1119
1120
1121 /******************************* dw_html_action() **************************
1122 * Implements the functionality of a "Back". "Forward", "Home", "Search",
1123 * "Refresh", or "Stop" button.
1124 *
1125 * hwnd = Handle to the window hosting the browser object.
1126 * action = One of the following:
1127 * 0 = Move back to the previously viewed web page.
1128 * 1 = Move forward to the previously viewed web page.
1129 * 2 = Move to the home page.
1130 * 3 = Search.
1131 * 4 = Refresh the page.
1132 * 5 = Stop the currently loading page.
1133 *
1134 * NOTE: EmbedBrowserObject() must have been successfully called once with the
1135 * specified window, prior to calling this function. You need call
1136 * EmbedBrowserObject() once only, and then you can make multiple calls to
1137 * this function to display numerous pages in the specified window.
1138 */
1139
1140 void API dw_html_action(HWND hwnd, int action)
1141 {
1142 IWebBrowser2 *webBrowser2;
1143 IOleObject *browserObject;
1144
1145 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
1146 // we initially attached the browser object to this window.
1147 browserObject = *((IOleObject **)dw_window_get_data(hwnd, "_dw_html"));
1148
1149 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
1150 // object, so we can call some of the functions in the former's table.
1151 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
1152 {
1153 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
1154 // webBrowser2->lpVtbl.
1155
1156 // Call the desired function
1157 switch (action)
1158 {
1159 case DW_HTML_GOBACK:
1160 {
1161 // Call the IWebBrowser2 object's GoBack function.
1162 webBrowser2->lpVtbl->GoBack(webBrowser2);
1163 break;
1164 }
1165
1166 case DW_HTML_GOFORWARD:
1167 {
1168 // Call the IWebBrowser2 object's GoForward function.
1169 webBrowser2->lpVtbl->GoForward(webBrowser2);
1170 break;
1171 }
1172
1173 case DW_HTML_GOHOME:
1174 {
1175 // Call the IWebBrowser2 object's GoHome function.
1176 webBrowser2->lpVtbl->GoHome(webBrowser2);
1177 break;
1178 }
1179
1180 case DW_HTML_SEARCH:
1181 {
1182 // Call the IWebBrowser2 object's GoSearch function.
1183 webBrowser2->lpVtbl->GoSearch(webBrowser2);
1184 break;
1185 }
1186
1187 case DW_HTML_RELOAD:
1188 {
1189 // Call the IWebBrowser2 object's Refresh function.
1190 webBrowser2->lpVtbl->Refresh(webBrowser2);
1191 }
1192
1193 case DW_HTML_STOP:
1194 {
1195 // Call the IWebBrowser2 object's Stop function.
1196 webBrowser2->lpVtbl->Stop(webBrowser2);
1197 }
1198 }
1199
1200 // Release the IWebBrowser2 object.
1201 webBrowser2->lpVtbl->Release(webBrowser2);
1202 }
1203 }
1204
1205
1206
1207
1208
1209 /******************************* dw_html_raw() ****************************
1210 * Takes a string containing some HTML BODY, and displays it in the specified
1211 * window. For example, perhaps you want to display the HTML text of...
1212 *
1213 * <P>This is a picture.<P><IMG src="mypic.jpg">
1214 *
1215 * hwnd = Handle to the window hosting the browser object.
1216 * string = Pointer to nul-terminated string containing the HTML BODY.
1217 * (NOTE: No <BODY></BODY> tags are required in the string).
1218 *
1219 * RETURNS: 0 if success, or non-zero if an error.
1220 *
1221 * NOTE: EmbedBrowserObject() must have been successfully called once with the
1222 * specified window, prior to calling this function. You need call
1223 * EmbedBrowserObject() once only, and then you can make multiple calls to
1224 * this function to display numerous pages in the specified window.
1225 */
1226
1227 int API dw_html_raw(HWND hwnd, char *string)
1228 {
1229 IWebBrowser2 *webBrowser2;
1230 LPDISPATCH lpDispatch;
1231 IHTMLDocument2 *htmlDoc2;
1232 IOleObject *browserObject;
1233 SAFEARRAY *sfArray;
1234 VARIANT myURL;
1235 VARIANT *pVar;
1236 BSTR bstr;
1237
1238 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
1239 // we initially attached the browser object to this window.
1240 browserObject = *((IOleObject **)dw_window_get_data(hwnd, "_dw_html"));
1241
1242 // Assume an error.
1243 bstr = 0;
1244
1245 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
1246 // object, so we can call some of the functions in the former's table.
1247 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
1248 {
1249 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
1250 // webBrowser2->lpVtbl.
1251
1252 // Before we can get_Document(), we actually need to have some HTML page loaded in the browser. So,
1253 // let's load an empty HTML page. Then, once we have that empty page, we can get_Document() and
1254 // write() to stuff our HTML string into it.
1255 VariantInit(&myURL);
1256 myURL.vt = VT_BSTR;
1257 myURL.bstrVal = SysAllocString(L"about:blank");
1258
1259 // Call the Navigate2() function to actually display the page.
1260 webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);
1261
1262 // Free any resources (including the BSTR).
1263 VariantClear(&myURL);
1264
1265 // Call the IWebBrowser2 object's get_Document so we can get its DISPATCH object. I don't know why you
1266 // don't get the DISPATCH object via the browser object's QueryInterface(), but you don't.
1267 if (!webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch))
1268 {
1269 // We want to get a pointer to the IHTMLDocument2 object embedded within the DISPATCH
1270 // object, so we can call some of the functions in the former's table.
1271 if (!lpDispatch->lpVtbl->QueryInterface(lpDispatch, &IID_IHTMLDocument2, (void**)&htmlDoc2))
1272 {
1273 // Ok, now the pointer to our IHTMLDocument2 object is in 'htmlDoc2', and so its VTable is
1274 // htmlDoc2->lpVtbl.
1275
1276 // Our HTML must be in the form of a BSTR. And it must be passed to write() in an
1277 // array of "VARIENT" structs. So let's create all that.
1278 if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, (SAFEARRAYBOUND *)&ArrayBound)))
1279 {
1280 if (!SafeArrayAccessData(sfArray, (void**)&pVar))
1281 {
1282 pVar->vt = VT_BSTR;
1283 #ifndef UNICODE
1284 {
1285 wchar_t *buffer;
1286 DWORD size;
1287
1288 size = MultiByteToWideChar(CP_ACP, 0, string, -1, 0, 0);
1289 if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) goto bad;
1290 MultiByteToWideChar(CP_ACP, 0, string, -1, buffer, size);
1291 bstr = SysAllocString(buffer);
1292 GlobalFree(buffer);
1293 }
1294 #else
1295 bstr = SysAllocString(string);
1296 #endif
1297 // Store our BSTR pointer in the VARIENT.
1298 if ((pVar->bstrVal = bstr))
1299 {
1300 // Pass the VARIENT with its BSTR to write() in order to shove our desired HTML string
1301 // into the body of that empty page we created above.
1302 htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
1303
1304 // Close the document. If we don't do this, subsequent calls to DisplayHTMLStr
1305 // would append to the current contents of the page
1306 htmlDoc2->lpVtbl->close(htmlDoc2);
1307
1308 // Normally, we'd need to free our BSTR, but SafeArrayDestroy() does it for us
1309 // SysFreeString(bstr);
1310 }
1311 }
1312
1313 // Free the array. This also frees the VARIENT that SafeArrayAccessData created for us,
1314 // and even frees the BSTR we allocated with SysAllocString
1315 SafeArrayDestroy(sfArray);
1316 }
1317
1318 // Release the IHTMLDocument2 object.
1319 bad: htmlDoc2->lpVtbl->Release(htmlDoc2);
1320 }
1321
1322 // Release the DISPATCH object.
1323 lpDispatch->lpVtbl->Release(lpDispatch);
1324 }
1325
1326 // Release the IWebBrowser2 object.
1327 webBrowser2->lpVtbl->Release(webBrowser2);
1328 }
1329
1330 // No error?
1331 if (bstr) return(0);
1332
1333 // An error
1334 return(-1);
1335 }
1336
1337
1338
1339
1340
1341
1342 /******************************* dw_html_url() ****************************
1343 * Displays a URL, or HTML file on disk.
1344 *
1345 * hwnd = Handle to the window hosting the browser object.
1346 * webPageName = Pointer to nul-terminated name of the URL/file.
1347 *
1348 * RETURNS: 0 if success, or non-zero if an error.
1349 *
1350 * NOTE: EmbedBrowserObject() must have been successfully called once with the
1351 * specified window, prior to calling this function. You need call
1352 * EmbedBrowserObject() once only, and then you can make multiple calls to
1353 * this function to display numerous pages in the specified window.
1354 */
1355
1356 int API dw_html_url(HWND hwnd, char *url)
1357 {
1358 IWebBrowser2 *webBrowser2;
1359 VARIANT myURL;
1360 IOleObject *browserObject;
1361
1362 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
1363 // we initially attached the browser object to this window.
1364 browserObject = *((IOleObject **)dw_window_get_data(hwnd, "_dw_html"));
1365
1366 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
1367 // object, so we can call some of the functions in the former's table.
1368 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
1369 {
1370 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
1371 // webBrowser2->lpVtbl.
1372
1373 // Our URL (ie, web address, such as "http://www.microsoft.com" or an HTM filename on disk
1374 // such as "c:\myfile.htm") must be passed to the IWebBrowser2's Navigate2() function as a BSTR.
1375 // A BSTR is like a pascal version of a double-byte character string. In other words, the
1376 // first unsigned short is a count of how many characters are in the string, and then this
1377 // is followed by those characters, each expressed as an unsigned short (rather than a
1378 // char). The string is not nul-terminated. The OS function SysAllocString can allocate and
1379 // copy a UNICODE C string to a BSTR. Of course, we'll need to free that BSTR after we're done
1380 // with it. If we're not using UNICODE, we first have to convert to a UNICODE string.
1381 //
1382 // What's more, our BSTR needs to be stuffed into a VARIENT struct, and that VARIENT struct is
1383 // then passed to Navigate2(). Why? The VARIENT struct makes it possible to define generic
1384 // 'datatypes' that can be used with all languages. Not all languages support things like
1385 // nul-terminated C strings. So, by using a VARIENT, whose first field tells what sort of
1386 // data (ie, string, float, etc) is in the VARIENT, COM interfaces can be used by just about
1387 // any language.
1388 VariantInit(&myURL);
1389 myURL.vt = VT_BSTR;
1390
1391 {
1392 wchar_t *buffer;
1393 DWORD size;
1394
1395 size = MultiByteToWideChar(CP_ACP, 0, url, -1, 0, 0);
1396 if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) goto badalloc;
1397 MultiByteToWideChar(CP_ACP, 0, url, -1, buffer, size);
1398 myURL.bstrVal = SysAllocString(buffer);
1399 GlobalFree(buffer);
1400 }
1401 if (!myURL.bstrVal)
1402 {
1403 badalloc: webBrowser2->lpVtbl->Release(webBrowser2);
1404 return(-6);
1405 }
1406
1407 // Call the Navigate2() function to actually display the page.
1408 webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);
1409
1410 // Free any resources (including the BSTR we allocated above).
1411 VariantClear(&myURL);
1412
1413 // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it,
1414 // so we can release our hold on it). Note that we'll still maintain our hold on the browser
1415 // object.
1416 webBrowser2->lpVtbl->Release(webBrowser2);
1417
1418 // Success
1419 return(0);
1420 }
1421
1422 return(-5);
1423 }
1424
1425
1426
1427
1428
1429 /******************************* ResizeBrowser() ****************************
1430 * Resizes the browser object for the specified window to the specified
1431 * width and height.
1432 *
1433 * hwnd = Handle to the window hosting the browser object.
1434 * width = Width.
1435 * height = Height.
1436 *
1437 * NOTE: EmbedBrowserObject() must have been successfully called once with the
1438 * specified window, prior to calling this function. You need call
1439 * EmbedBrowserObject() once only, and then you can make multiple calls to
1440 * this function to resize the browser object.
1441 */
1442
1443 void _ResizeBrowser(HWND hwnd, DWORD width, DWORD height)
1444 {
1445 IWebBrowser2 *webBrowser2;
1446 IOleObject *browserObject;
1447
1448 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
1449 // we initially attached the browser object to this window.
1450 browserObject = *((IOleObject **)dw_window_get_data(hwnd, "_dw_html"));
1451
1452 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
1453 // object, so we can call some of the functions in the former's table.
1454 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
1455 {
1456 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
1457 // webBrowser2->lpVtbl.
1458
1459 // Call are put_Width() and put_Height() to set the new width/height.
1460 webBrowser2->lpVtbl->put_Width(webBrowser2, width);
1461 webBrowser2->lpVtbl->put_Height(webBrowser2, height);
1462
1463 // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it,
1464 // so we can release our hold on it). Note that we'll still maintain our hold on the browser
1465 // object.
1466 webBrowser2->lpVtbl->Release(webBrowser2);
1467 }
1468 }
1469
1470
1471
1472
1473
1474 /***************************** EmbedBrowserObject() **************************
1475 * Puts the browser object inside our host window, and save a pointer to this
1476 * window's browser object in the window's GWL_USERDATA field.
1477 *
1478 * hwnd = Handle of our window into which we embed the browser object.
1479 *
1480 * RETURNS: 0 if success, or non-zero if an error.
1481 *
1482 * NOTE: We tell the browser object to occupy the entire client area of the
1483 * window.
1484 *
1485 * NOTE: No HTML page will be displayed here. We can do that with a subsequent
1486 * call to either DisplayHTMLPage() or DisplayHTMLStr(). This is merely once-only
1487 * initialization for using the browser object. In a nutshell, what we do
1488 * here is get a pointer to the browser object in our window's GWL_USERDATA
1489 * so we can access that object's functions whenever we want, and we also pass
1490 * pointers to our IOleClientSite, IOleInPlaceFrame, and IStorage structs so that
1491 * the browser can call our functions in our struct's VTables.
1492 */
1493
1494 long _EmbedBrowserObject(HWND hwnd)
1495 {
1496 IOleObject *browserObject;
1497 IWebBrowser2 *webBrowser2;
1498 RECT rect;
1499 char *ptr;
1500 _IOleClientSiteEx *_iOleClientSiteEx;
1501
1502 // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to get our window handle. We
1503 // could store that in some global. But then, that would mean that our functions would work with only that
1504 // one window. If we want to create multiple windows, each hosting its own browser object (to display its
1505 // own web page), then we need to create unique IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame
1506 // structs for each window. And we'll put an extra field at the end of those structs to store our extra
1507 // data such as a window handle. So, our functions won't have to touch global data, and can therefore be
1508 // re-entrant and work with multiple objects/windows.
1509 //
1510 // Remember that a pointer to our IOleClientSite we create here will be passed as the first arg to every
1511 // one of our IOleClientSite functions. Ditto with the IOleInPlaceFrame object we create here, and the
1512 // IOleInPlaceFrame functions. So, our functions are able to retrieve the window handle we'll store here,
1513 // and then, they'll work with all such windows containing a browser control.
1514 //
1515 // Furthermore, since the browser will be calling our IOleClientSite's QueryInterface to get a pointer to
1516 // our IOleInPlaceSite and IDocHostUIHandler objects, that means that our IOleClientSite QueryInterface
1517 // must have an easy way to grab those pointers. Probably the easiest thing to do is just embed our
1518 // IOleInPlaceSite and IDocHostUIHandler objects inside of an extended IOleClientSite which we'll call
1519 // a _IOleClientSiteEx. As long as they come after the pointer to the IOleClientSite VTable, then we're
1520 // ok.
1521 //
1522 // Of course, we need to GlobalAlloc the above structs now. We'll just get all 4 with a single call to
1523 // GlobalAlloc, especially since 3 of them are all contained inside of our _IOleClientSiteEx anyway.
1524 //
1525 // So, we're not actually allocating separate IOleClientSite, IOleInPlaceSite, IOleInPlaceFrame and
1526 // IDocHostUIHandler structs.
1527 //
1528 // One final thing. We're going to allocate extra room to store the pointer to the browser object.
1529 if (!(ptr = (char *)GlobalAlloc(GMEM_FIXED, sizeof(_IOleClientSiteEx) + sizeof(IOleObject *))))
1530 return(-1);
1531
1532 // Initialize our IOleClientSite object with a pointer to our IOleClientSite VTable.
1533 _iOleClientSiteEx = (_IOleClientSiteEx *)(ptr + sizeof(IOleObject *));
1534 _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;
1535
1536 // Initialize our IOleInPlaceSite object with a pointer to our IOleInPlaceSite VTable.
1537 _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;
1538
1539 // Initialize our IOleInPlaceFrame object with a pointer to our IOleInPlaceFrame VTable.
1540 _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable;
1541
1542 // Save our HWND (in the IOleInPlaceFrame object) so our IOleInPlaceFrame functions can retrieve it.
1543 _iOleClientSiteEx->inplace.frame.window = hwnd;
1544
1545 // Initialize our IDocHostUIHandler object with a pointer to our IDocHostUIHandler VTable.
1546 _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable;
1547
1548 // Get a pointer to the browser object and lock it down (so it doesn't "disappear" while we're using
1549 // it in this program). We do this by calling the OS function OleCreate().
1550 //
1551 // NOTE: We need this pointer to interact with and control the browser. With normal WIN32 controls such as a
1552 // Static, Edit, Combobox, etc, you obtain an HWND and send messages to it with SendMessage(). Not so with
1553 // the browser object. You need to get a pointer to its "base structure" (as returned by OleCreate()). This
1554 // structure contains an array of pointers to functions you can call within the browser object. Actually, the
1555 // base structure contains a 'lpVtbl' field that is a pointer to that array. We'll call the array a 'VTable'.
1556 //
1557 // For example, the browser object happens to have a SetHostNames() function we want to call. So, after we
1558 // retrieve the pointer to the browser object (in a local we'll name 'browserObject'), then we can call that
1559 // function, and pass it args, as so:
1560 //
1561 // browserObject->lpVtbl->SetHostNames(browserObject, SomeString, SomeString);
1562 //
1563 // There's our pointer to the browser object in 'browserObject'. And there's the pointer to the browser object's
1564 // VTable in 'browserObject->lpVtbl'. And the pointer to the SetHostNames function happens to be stored in an
1565 // field named 'SetHostNames' within the VTable. So we are actually indirectly calling SetHostNames by using
1566 // a pointer to it. That's how you use a VTable.
1567 //
1568 // NOTE: We pass our _IOleClientSiteEx struct and lie -- saying that it's a IOleClientSite. It's ok. A
1569 // _IOleClientSiteEx struct starts with an embedded IOleClientSite. So the browser won't care, and we want
1570 // this extended struct passed to our IOleClientSite functions.
1571
1572 if (!OleCreate(&CLSID_WebBrowser, &IID_IOleObject, OLERENDER_DRAW, 0, (IOleClientSite *)_iOleClientSiteEx, &MyIStorage, (void**)&browserObject))
1573 {
1574 // Ok, we now have the pointer to the browser object in 'browserObject'. Let's save this in the
1575 // memory block we allocated above, and then save the pointer to that whole thing in our window's
1576 // USERDATA field. That way, if we need multiple windows each hosting its own browser object, we can
1577 // call EmbedBrowserObject() for each one, and easily associate the appropriate browser object with
1578 // its matching window and its own objects containing per-window data.
1579 *((IOleObject **)ptr) = browserObject;
1580 dw_window_set_data(hwnd, "_dw_html", (void *)ptr);
1581
1582 // We can now call the browser object's SetHostNames function. SetHostNames lets the browser object know our
1583 // application's name and the name of the document in which we're embedding the browser. (Since we have no
1584 // document name, we'll pass a 0 for the latter). When the browser object is opened for editing, it displays
1585 // these names in its titlebar.
1586 //
1587 // We are passing 3 args to SetHostNames. You'll note that the first arg to SetHostNames is the base
1588 // address of our browser control. This is something that you always have to remember when working in C
1589 // (as opposed to C++). When calling a VTable function, the first arg to that function must always be the
1590 // structure which contains the VTable. (In this case, that's the browser control itself). Why? That's
1591 // because that function is always assumed to be written in C++. And the first argument to any C++ function
1592 // must be its 'this' pointer (ie, the base address of its class, which in this case is our browser object
1593 // pointer). In C++, you don't have to pass this first arg, because the C++ compiler is smart enough to
1594 // produce an executable that always adds this first arg. In fact, the C++ compiler is smart enough to
1595 // know to fetch the function pointer from the VTable, so you don't even need to reference that. In other
1596 // words, the C++ equivalent code would be:
1597 //
1598 // browserObject->SetHostNames(L"My Host Name", 0);
1599 //
1600 // So, when you're trying to convert C++ code to C, always remember to add this first arg whenever you're
1601 // dealing with a VTable (ie, the field is usually named 'lpVtbl') in the standard objects, and also add
1602 // the reference to the VTable itself.
1603 //
1604 // Oh yeah, the L is because we need UNICODE strings. And BTW, the host and document names can be anything
1605 // you want.
1606
1607 browserObject->lpVtbl->SetHostNames(browserObject, L"My Host Name", 0);
1608
1609 GetClientRect(hwnd, &rect);
1610
1611 // Let browser object know that it is embedded in an OLE container.
1612 if (!OleSetContainedObject((struct IUnknown *)browserObject, TRUE) &&
1613
1614 // Set the display area of our browser control the same as our window's size
1615 // and actually put the browser object into our window.
1616 !browserObject->lpVtbl->DoVerb(browserObject, OLEIVERB_SHOW, NULL, (IOleClientSite *)_iOleClientSiteEx, -1, hwnd, &rect) &&
1617
1618 // Ok, now things may seem to get even trickier, One of those function pointers in the browser's VTable is
1619 // to the QueryInterface() function. What does this function do? It lets us grab the base address of any
1620 // other object that may be embedded within the browser object. And this other object has its own VTable
1621 // containing pointers to more functions we can call for that object.
1622 //
1623 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
1624 // object, so we can call some of the functions in the former's table. For example, one IWebBrowser2 function
1625 // we intend to call below will be Navigate2(). So we call the browser object's QueryInterface to get our
1626 // pointer to the IWebBrowser2 object.
1627 !browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
1628 {
1629 // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
1630 // webBrowser2->lpVtbl.
1631
1632 // Let's call several functions in the IWebBrowser2 object to position the browser display area
1633 // in our window. The functions we call are put_Left(), put_Top(), put_Width(), and put_Height().
1634 // Note that we reference the IWebBrowser2 object's VTable to get pointers to those functions. And
1635 // also note that the first arg we pass to each is the pointer to the IWebBrowser2 object.
1636 webBrowser2->lpVtbl->put_Left(webBrowser2, 0);
1637 webBrowser2->lpVtbl->put_Top(webBrowser2, 0);
1638 webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
1639 webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
1640
1641 // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it
1642 // right now, so we can release our hold on it). Note that we'll still maintain our hold on the
1643 // browser object until we're done with that object.
1644 webBrowser2->lpVtbl->Release(webBrowser2);
1645
1646 // Success
1647 return(0);
1648 }
1649
1650 // Something went wrong!
1651 _UnEmbedBrowserObject(hwnd);
1652 return(-3);
1653 }
1654
1655 GlobalFree(ptr);
1656 return(-2);
1657 }
1658
1659
1660
1661
1662
1663
1664 /************************** browserWindowProc() *************************
1665 * Our message handler for our window to host the browser.
1666 */
1667
1668 LRESULT CALLBACK _browserWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1669 {
1670 switch (uMsg)
1671 {
1672 case WM_SIZE:
1673 {
1674 // Resize the browser object to fit the window
1675 _ResizeBrowser(hwnd, LOWORD(lParam), HIWORD(lParam));
1676 return(0);
1677 }
1678
1679 case WM_CREATE:
1680 {
1681 // Embed the browser object into our host window. We need do this only
1682 // once. Note that the browser object will start calling some of our
1683 // IOleInPlaceFrame and IOleClientSite functions as soon as we start
1684 // calling browser object functions in EmbedBrowserObject().
1685 if (_EmbedBrowserObject(hwnd)) return(-1);
1686
1687 // Success
1688 return(0);
1689 }
1690
1691 case WM_DESTROY:
1692 {
1693 // Detach the browser object from this window, and free resources.
1694 _UnEmbedBrowserObject(hwnd);
1695
1696 return(TRUE);
1697 }
1698 }
1699
1700 return(DefWindowProc(hwnd, uMsg, wParam, lParam));
1701 }
1702