2 * Copyright 2010 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <wine/test.h>
33 #include "mshtml_test.h"
35 #define DEFINE_EXPECT(func) \
36 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
38 #define SET_EXPECT(func) \
39 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
41 #define CHECK_EXPECT2(func) \
43 ok(expect_ ##func, "unexpected call " #func "\n"); \
44 called_ ## func = TRUE; \
47 #define CHECK_EXPECT(func) \
49 CHECK_EXPECT2(func); \
50 expect_ ## func = FALSE; \
53 #define CHECK_CALLED(func) \
55 ok(called_ ## func, "expected " #func "\n"); \
56 expect_ ## func = called_ ## func = FALSE; \
59 DEFINE_EXPECT(CreateInstance);
61 static HWND container_hwnd;
63 #define TESTACTIVEX_CLSID "{178fc163-f585-4e24-9c13-4bb7f6680746}"
65 static const GUID CLSID_TestActiveX =
66 {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xf6,0x68,0x07,0x46}};
68 static const char *debugstr_guid(REFIID riid)
72 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
73 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
74 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
75 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
80 static const char object_ax_str[] =
81 "<html><head></head><body>"
82 "<object classid=\"clsid:" TESTACTIVEX_CLSID "\" width=\"300\" height=\"200\" id=\"objid\">"
83 "<param name=\"param_name\" value=\"param_value\">"
87 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
91 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
96 if(IsEqualGUID(&IID_IMarshal, riid))
98 if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
100 if(IsEqualGUID(&IID_IClassFactoryEx, riid))
101 return E_NOINTERFACE; /* TODO */
103 ok(0, "unexpected riid %s\n", debugstr_guid(riid));
107 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
112 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
117 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
119 CHECK_EXPECT(CreateInstance);
120 ok(!outer, "outer = %p\n", outer);
121 ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", debugstr_guid(riid));
122 return E_OUTOFMEMORY;
125 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
127 ok(0, "unexpected call\n");
131 static const IClassFactoryVtbl ClassFactoryVtbl = {
132 ClassFactory_QueryInterface,
134 ClassFactory_Release,
135 ClassFactory_CreateInstance,
136 ClassFactory_LockServer
139 static HRESULT cs_qi(REFIID,void **);
140 static IOleDocumentView *view;
142 static HRESULT WINAPI InPlaceFrame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, void **ppv)
144 static const GUID undocumented_frame_iid = {0xfbece6c9,0x48d7,0x4a37,{0x8f,0xe3,0x6a,0xd4,0x27,0x2f,0xdd,0xac}};
146 if(!IsEqualGUID(&undocumented_frame_iid, riid))
147 ok(0, "unexpected riid %s\n", debugstr_guid(riid));
150 return E_NOINTERFACE;
153 static ULONG WINAPI InPlaceFrame_AddRef(IOleInPlaceFrame *iface)
158 static ULONG WINAPI InPlaceFrame_Release(IOleInPlaceFrame *iface)
163 static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd)
168 static HRESULT WINAPI InPlaceFrame_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode)
173 static HRESULT WINAPI InPlaceFrame_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder)
178 static HRESULT WINAPI InPlaceFrame_RequestBorderSpace(IOleInPlaceFrame *iface,
179 LPCBORDERWIDTHS pborderwidths)
184 static HRESULT WINAPI InPlaceFrame_SetBorderSpace(IOleInPlaceFrame *iface,
185 LPCBORDERWIDTHS pborderwidths)
190 static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface,
191 IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
196 static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface,
197 IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
202 static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared,
203 LPOLEMENUGROUPWIDTHS lpMenuWidths)
208 static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared,
209 HOLEMENU holemenu, HWND hwndActiveObject)
211 ok(0, "unexpected call\n");
215 static HRESULT WINAPI InPlaceFrame_RemoveMenus(IOleInPlaceFrame *iface, HMENU hmenuShared)
217 ok(0, "unexpected call\n");
221 static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLESTR pszStatusText)
226 static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable)
231 static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID)
233 ok(0, "unexpected call\n");
237 static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = {
238 InPlaceFrame_QueryInterface,
240 InPlaceFrame_Release,
241 InPlaceFrame_GetWindow,
242 InPlaceFrame_ContextSensitiveHelp,
243 InPlaceFrame_GetBorder,
244 InPlaceFrame_RequestBorderSpace,
245 InPlaceFrame_SetBorderSpace,
246 InPlaceFrame_SetActiveObject,
247 InPlaceFrame_InsertMenus,
248 InPlaceFrame_SetMenu,
249 InPlaceFrame_RemoveMenus,
250 InPlaceFrame_SetStatusText,
251 InPlaceFrame_EnableModeless,
252 InPlaceFrame_TranslateAccelerator
255 static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl };
257 static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = {
258 InPlaceFrame_QueryInterface,
260 InPlaceFrame_Release,
261 InPlaceFrame_GetWindow,
262 InPlaceFrame_ContextSensitiveHelp,
263 InPlaceFrame_GetBorder,
264 InPlaceFrame_RequestBorderSpace,
265 InPlaceFrame_SetBorderSpace,
266 InPlaceUIWindow_SetActiveObject,
269 static IOleInPlaceFrame InPlaceUIWindow = { &InPlaceUIWindowVtbl };
271 static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSite *iface, REFIID riid, void **ppv)
273 return cs_qi(riid, ppv);
276 static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSite *iface)
281 static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSite *iface)
286 static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSite *iface, HWND *phwnd)
288 *phwnd = container_hwnd;
292 static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSite *iface, BOOL fEnterMode)
294 ok(0, "unexpected call\n");
298 static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSite *iface)
303 static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSite *iface)
308 static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSite *iface)
313 static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSite *iface,
314 IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect,
315 LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
317 static const RECT rect = {0,0,500,500};
319 *ppFrame = &InPlaceFrame;
320 *ppDoc = (IOleInPlaceUIWindow*)&InPlaceUIWindow;
322 *lprcClipRect = rect;
324 lpFrameInfo->cb = sizeof(*lpFrameInfo);
325 lpFrameInfo->fMDIApp = FALSE;
326 lpFrameInfo->hwndFrame = container_hwnd;
327 lpFrameInfo->haccel = NULL;
328 lpFrameInfo->cAccelEntries = 0;
333 static HRESULT WINAPI InPlaceSite_Scroll(IOleInPlaceSite *iface, SIZE scrollExtant)
338 static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSite *iface, BOOL fUndoable)
343 static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSite *iface)
348 static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSite *iface)
353 static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSite *iface)
358 static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSite *iface, LPCRECT lprcPosRect)
363 static const IOleInPlaceSiteVtbl InPlaceSiteVtbl = {
364 InPlaceSite_QueryInterface,
367 InPlaceSite_GetWindow,
368 InPlaceSite_ContextSensitiveHelp,
369 InPlaceSite_CanInPlaceActivate,
370 InPlaceSite_OnInPlaceActivate,
371 InPlaceSite_OnUIActivate,
372 InPlaceSite_GetWindowContext,
374 InPlaceSite_OnUIDeactivate,
375 InPlaceSite_OnInPlaceDeactivate,
376 InPlaceSite_DiscardUndoState,
377 InPlaceSite_DeactivateAndUndo,
378 InPlaceSite_OnPosRectChange,
381 static IOleInPlaceSite InPlaceSite = { &InPlaceSiteVtbl };
383 static HRESULT WINAPI ClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
385 return cs_qi(riid, ppv);
388 static ULONG WINAPI ClientSite_AddRef(IOleClientSite *iface)
393 static ULONG WINAPI ClientSite_Release(IOleClientSite *iface)
398 static HRESULT WINAPI ClientSite_SaveObject(IOleClientSite *iface)
400 ok(0, "unexpected call\n");
404 static HRESULT WINAPI ClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker,
407 ok(0, "unexpected call\n");
411 static HRESULT WINAPI ClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer)
416 static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface)
418 ok(0, "unexpected call\n");
422 static HRESULT WINAPI ClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow)
424 ok(0, "unexpected call\n");
428 static HRESULT WINAPI ClientSite_RequestNewObjectLayout(IOleClientSite *iface)
430 ok(0, "unexpected call\n");
434 static const IOleClientSiteVtbl ClientSiteVtbl = {
435 ClientSite_QueryInterface,
438 ClientSite_SaveObject,
439 ClientSite_GetMoniker,
440 ClientSite_GetContainer,
441 ClientSite_ShowObject,
442 ClientSite_OnShowWindow,
443 ClientSite_RequestNewObjectLayout
446 static IOleClientSite ClientSite = { &ClientSiteVtbl };
448 static HRESULT WINAPI DocumentSite_QueryInterface(IOleDocumentSite *iface, REFIID riid, void **ppv)
450 return cs_qi(riid, ppv);
453 static ULONG WINAPI DocumentSite_AddRef(IOleDocumentSite *iface)
458 static ULONG WINAPI DocumentSite_Release(IOleDocumentSite *iface)
463 static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocumentView *pViewToActivate)
465 RECT rect = {0,0,400,500};
466 IOleDocument *document;
469 hres = IOleDocumentView_QueryInterface(pViewToActivate, &IID_IOleDocument, (void**)&document);
470 ok(hres == S_OK, "could not get IOleDocument: %08x\n", hres);
472 hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view);
473 IOleDocument_Release(document);
474 ok(hres == S_OK, "CreateView failed: %08x\n", hres);
476 hres = IOleDocumentView_SetInPlaceSite(view, &InPlaceSite);
477 ok(hres == S_OK, "SetInPlaceSite failed: %08x\n", hres);
479 hres = IOleDocumentView_UIActivate(view, TRUE);
480 ok(hres == S_OK, "UIActivate failed: %08x\n", hres);
482 hres = IOleDocumentView_SetRect(view, &rect);
483 ok(hres == S_OK, "SetRect failed: %08x\n", hres);
485 hres = IOleDocumentView_Show(view, TRUE);
486 ok(hres == S_OK, "Show failed: %08x\n", hres);
491 static const IOleDocumentSiteVtbl DocumentSiteVtbl = {
492 DocumentSite_QueryInterface,
494 DocumentSite_Release,
495 DocumentSite_ActivateMe
498 static IOleDocumentSite DocumentSite = { &DocumentSiteVtbl };
500 static HRESULT cs_qi(REFIID riid, void **ppv)
504 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IOleClientSite, riid))
506 else if(IsEqualGUID(&IID_IOleDocumentSite, riid))
507 *ppv = &DocumentSite;
508 else if(IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IOleInPlaceSite, riid))
511 return *ppv ? S_OK : E_NOINTERFACE;
514 static IClassFactory activex_cf = { &ClassFactoryVtbl };
515 static IHTMLDocument2 *notif_doc;
516 static BOOL doc_complete;
518 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
519 REFIID riid, void**ppv)
521 if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
526 ok(0, "unexpected call\n");
527 return E_NOINTERFACE;
530 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
535 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
540 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
542 if(dispID == DISPID_READYSTATE){
546 static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
548 hres = IHTMLDocument2_get_readyState(notif_doc, &state);
549 ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
551 if(!lstrcmpW(state, completeW))
554 SysFreeString(state);
560 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
562 ok(0, "unexpected call\n");
566 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
567 PropertyNotifySink_QueryInterface,
568 PropertyNotifySink_AddRef,
569 PropertyNotifySink_Release,
570 PropertyNotifySink_OnChanged,
571 PropertyNotifySink_OnRequestEdit
574 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
576 static void doc_load_string(IHTMLDocument2 *doc, const char *str)
578 IPersistStreamInit *init;
585 doc_complete = FALSE;
587 mem = GlobalAlloc(0, len);
588 memcpy(mem, str, len);
589 CreateStreamOnHGlobal(mem, TRUE, &stream);
591 IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
593 IPersistStreamInit_Load(init, stream);
594 IPersistStreamInit_Release(init);
595 IStream_Release(stream);
598 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
600 IConnectionPointContainer *container;
601 IConnectionPoint *cp;
605 hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
606 ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
608 hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
609 IConnectionPointContainer_Release(container);
610 ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
612 hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
613 IConnectionPoint_Release(cp);
614 ok(hres == S_OK, "Advise failed: %08x\n", hres);
617 static void set_client_site(IHTMLDocument2 *doc, BOOL set)
623 IOleDocumentView_Show(view, FALSE);
624 IOleDocumentView_CloseView(view, 0);
625 IOleDocumentView_SetInPlaceSite(view, NULL);
626 IOleDocumentView_Release(view);
630 hres = IHTMLDocument2_QueryInterface(doc, &IID_IOleObject, (void**)&oleobj);
631 ok(hres == S_OK, "Could not et IOleObject: %08x\n", hres);
633 hres = IOleObject_SetClientSite(oleobj, set ? &ClientSite : NULL);
634 ok(hres == S_OK, "SetClientSite failed: %08x\n", hres);
639 hres = IOleObject_QueryInterface(oleobj, &IID_IHlinkTarget, (void**)&hlink);
640 ok(hres == S_OK, "Could not get IHlinkTarget iface: %08x\n", hres);
642 hres = IHlinkTarget_Navigate(hlink, 0, NULL);
643 ok(hres == S_OK, "Navgate failed: %08x\n", hres);
645 IHlinkTarget_Release(hlink);
648 IOleObject_Release(oleobj);
650 static IHTMLDocument2 *create_document(void)
655 hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
656 &IID_IHTMLDocument2, (void**)&doc);
657 ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
662 static IHTMLDocument2 *create_doc(const char *str)
667 doc = create_document();
668 set_client_site(doc, TRUE);
669 doc_load_string(doc, str);
670 do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
672 while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
673 TranslateMessage(&msg);
674 DispatchMessage(&msg);
680 static void release_doc(IHTMLDocument2 *doc)
684 set_client_site(doc, FALSE);
685 ref = IHTMLDocument2_Release(doc);
686 ok(!ref, "ref = %d\n", ref);
689 static void test_object_ax(void)
693 SET_EXPECT(CreateInstance);
694 doc = create_doc(object_ax_str);
696 CHECK_CALLED(CreateInstance);
701 static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
703 return DefWindowProc(hwnd, msg, wParam, lParam);
706 static HWND create_container_window(void)
708 static const WCHAR html_document_testW[] =
709 {'H','T','M','L','D','o','c','u','m','e','n','t','T','e','s','t',0};
710 static WNDCLASSEXW wndclass = {
714 0, 0, NULL, NULL, NULL, NULL, NULL,
719 RegisterClassExW(&wndclass);
720 return CreateWindowW(html_document_testW, html_document_testW,
721 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
722 515, 530, NULL, NULL, NULL, NULL);
725 static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
731 RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
735 res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
736 if(res != ERROR_SUCCESS)
740 res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
744 return res == ERROR_SUCCESS;
747 static BOOL init_registry(BOOL init)
749 return init_key("TestActiveX\\CLSID", TESTACTIVEX_CLSID, init)
750 && init_key("CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95801-9882-11cf-9fa9-00aa006c42c4}",
752 && init_key("CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95802-9882-11cf-9fa9-00aa006c42c4}",
756 static BOOL register_activex(void)
761 if(!init_registry(TRUE)) {
762 init_registry(FALSE);
766 hres = CoRegisterClassObject(&CLSID_TestActiveX, (IUnknown*)&activex_cf,
767 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id);
768 ok(hres == S_OK, "Could not register control: %08x\n", hres);
773 static BOOL check_ie(void)
778 static const WCHAR xW[] = {'x',0};
779 static const WCHAR yW[] = {'y',0};
781 if(!lstrcmpW(xW, yW))
784 hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
785 &IID_IHTMLDocument5, (void**)&doc);
789 IHTMLDocument5_Release(doc);
799 win_skip("Too old IE\n");
803 if(is_ie_hardened()) {
805 win_skip("IE running in Enhanced Security Configuration\n");
809 container_hwnd = create_container_window();
810 ShowWindow(container_hwnd, SW_SHOW);
812 if(register_activex()) {
814 init_registry(FALSE);
816 skip("Could not register ActiveX\n");
819 DestroyWindow(container_hwnd);