Mercurial > dwindows
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 |