mshtml: Use lazy allocation for connection points.
[wine] / dlls / atl100 / tests / atl.c
1 /*
2  * Copyright 2012 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20 #include <stdio.h>
21
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <atlbase.h>
26 #include <mshtml.h>
27
28 #include <wine/test.h>
29
30 static const GUID CLSID_Test =
31     {0x178fc163,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
32 #define CLSID_TEST_STR "178fc163-0000-0000-0000-000000000046"
33
34 static const GUID CATID_CatTest1 =
35     {0x178fc163,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x46}};
36 #define CATID_CATTEST1_STR "178fc163-0000-0000-0000-000000000146"
37
38 static const GUID CATID_CatTest2 =
39     {0x178fc163,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x46}};
40 #define CATID_CATTEST2_STR "178fc163-0000-0000-0000-000000000246"
41
42 static const char *debugstr_guid(REFIID riid)
43 {
44     static char buf[50];
45
46     if(!riid)
47         return "(null)";
48
49     sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
50             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
51             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
52             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
53
54     return buf;
55 }
56
57 static void test_winmodule(void)
58 {
59     _AtlCreateWndData create_data[3];
60     _ATL_WIN_MODULE winmod;
61     void *p;
62     HRESULT hres;
63
64     winmod.cbSize = 0xdeadbeef;
65     hres = AtlWinModuleInit(&winmod);
66     ok(hres == E_INVALIDARG, "AtlWinModuleInit failed: %08x\n", hres);
67
68     winmod.cbSize = sizeof(winmod);
69     winmod.m_pCreateWndList = (void*)0xdeadbeef;
70     winmod.m_csWindowCreate.LockCount = 0xdeadbeef;
71     winmod.m_rgWindowClassAtoms.m_aT = (void*)0xdeadbeef;
72     winmod.m_rgWindowClassAtoms.m_nSize = 0xdeadbeef;
73     winmod.m_rgWindowClassAtoms.m_nAllocSize = 0xdeadbeef;
74     hres = AtlWinModuleInit(&winmod);
75     ok(hres == S_OK, "AtlWinModuleInit failed: %08x\n", hres);
76     ok(!winmod.m_pCreateWndList, "winmod.m_pCreateWndList = %p\n", winmod.m_pCreateWndList);
77     ok(winmod.m_csWindowCreate.LockCount == -1, "winmod.m_csWindowCreate.LockCount = %d\n",
78        winmod.m_csWindowCreate.LockCount);
79     ok(winmod.m_rgWindowClassAtoms.m_aT == (void*)0xdeadbeef, "winmod.m_rgWindowClassAtoms.m_aT = %p\n",
80        winmod.m_rgWindowClassAtoms.m_aT);
81     ok(winmod.m_rgWindowClassAtoms.m_nSize == 0xdeadbeef, "winmod.m_rgWindowClassAtoms.m_nSize = %d\n",
82        winmod.m_rgWindowClassAtoms.m_nSize);
83     ok(winmod.m_rgWindowClassAtoms.m_nAllocSize == 0xdeadbeef, "winmod.m_rgWindowClassAtoms.m_nAllocSize = %d\n",
84        winmod.m_rgWindowClassAtoms.m_nAllocSize);
85
86     InitializeCriticalSection(&winmod.m_csWindowCreate);
87
88     AtlWinModuleAddCreateWndData(&winmod, create_data, (void*)0xdead0001);
89     ok(winmod.m_pCreateWndList == create_data, "winmod.m_pCreateWndList != create_data\n");
90     ok(create_data[0].m_pThis == (void*)0xdead0001, "unexpected create_data[0].m_pThis %p\n", create_data[0].m_pThis);
91     ok(create_data[0].m_dwThreadID == GetCurrentThreadId(), "unexpected create_data[0].m_dwThreadID %x\n",
92        create_data[0].m_dwThreadID);
93     ok(!create_data[0].m_pNext, "unexpected create_data[0].m_pNext %p\n", create_data[0].m_pNext);
94
95     AtlWinModuleAddCreateWndData(&winmod, create_data+1, (void*)0xdead0002);
96     ok(winmod.m_pCreateWndList == create_data+1, "winmod.m_pCreateWndList != create_data\n");
97     ok(create_data[1].m_pThis == (void*)0xdead0002, "unexpected create_data[1].m_pThis %p\n", create_data[1].m_pThis);
98     ok(create_data[1].m_dwThreadID == GetCurrentThreadId(), "unexpected create_data[1].m_dwThreadID %x\n",
99        create_data[1].m_dwThreadID);
100     ok(create_data[1].m_pNext == create_data, "unexpected create_data[1].m_pNext %p\n", create_data[1].m_pNext);
101
102     AtlWinModuleAddCreateWndData(&winmod, create_data+2, (void*)0xdead0003);
103     ok(winmod.m_pCreateWndList == create_data+2, "winmod.m_pCreateWndList != create_data\n");
104     ok(create_data[2].m_pThis == (void*)0xdead0003, "unexpected create_data[2].m_pThis %p\n", create_data[2].m_pThis);
105     ok(create_data[2].m_dwThreadID == GetCurrentThreadId(), "unexpected create_data[2].m_dwThreadID %x\n",
106        create_data[2].m_dwThreadID);
107     ok(create_data[2].m_pNext == create_data+1, "unexpected create_data[2].m_pNext %p\n", create_data[2].m_pNext);
108
109     p = AtlWinModuleExtractCreateWndData(&winmod);
110     ok(p == (void*)0xdead0003, "unexpected AtlWinModuleExtractCreateWndData result %p\n", p);
111     ok(winmod.m_pCreateWndList == create_data+1, "winmod.m_pCreateWndList != create_data\n");
112     ok(create_data[2].m_pNext == create_data+1, "unexpected create_data[2].m_pNext %p\n", create_data[2].m_pNext);
113
114     create_data[1].m_dwThreadID = 0xdeadbeef;
115
116     p = AtlWinModuleExtractCreateWndData(&winmod);
117     ok(p == (void*)0xdead0001, "unexpected AtlWinModuleExtractCreateWndData result %p\n", p);
118     ok(winmod.m_pCreateWndList == create_data+1, "winmod.m_pCreateWndList != create_data\n");
119     ok(!create_data[0].m_pNext, "unexpected create_data[0].m_pNext %p\n", create_data[0].m_pNext);
120     ok(!create_data[1].m_pNext, "unexpected create_data[1].m_pNext %p\n", create_data[1].m_pNext);
121
122     p = AtlWinModuleExtractCreateWndData(&winmod);
123     ok(!p, "unexpected AtlWinModuleExtractCreateWndData result %p\n", p);
124     ok(winmod.m_pCreateWndList == create_data+1, "winmod.m_pCreateWndList != create_data\n");
125 }
126
127 #define test_key_exists(a,b) _test_key_exists(__LINE__,a,b)
128 static void _test_key_exists(unsigned line, HKEY root, const char *key_name)
129 {
130     HKEY key;
131     DWORD res;
132
133     res = RegOpenKeyA(root, key_name, &key);
134     ok_(__FILE__,line)(res == ERROR_SUCCESS, "Could not open key %s\n", key_name);
135     if(res == ERROR_SUCCESS)
136         RegCloseKey(key);
137 }
138
139 #define test_key_not_exists(a,b) _test_key_not_exists(__LINE__,a,b)
140 static void _test_key_not_exists(unsigned line, HKEY root, const char *key_name)
141 {
142     HKEY key;
143     DWORD res;
144
145     res = RegOpenKeyA(root, key_name, &key);
146     ok_(__FILE__,line)(res == ERROR_FILE_NOT_FOUND, "Attempting to open %s returned %u\n", key_name, res);
147     if(res == ERROR_SUCCESS)
148         RegCloseKey(key);
149 }
150
151 static void test_regcat(void)
152 {
153     unsigned char b;
154     HRESULT hres;
155
156     const struct _ATL_CATMAP_ENTRY catmap[] = {
157         {_ATL_CATMAP_ENTRY_IMPLEMENTED, &CATID_CatTest1},
158         {_ATL_CATMAP_ENTRY_REQUIRED, &CATID_CatTest2},
159         {_ATL_CATMAP_ENTRY_END}
160     };
161
162     hres = AtlRegisterClassCategoriesHelper(&CLSID_Test, catmap, TRUE);
163     ok(hres == S_OK, "AtlRegisterClassCategoriesHelper failed: %08x\n", hres);
164
165     test_key_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}");
166     test_key_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}\\Implemented Categories\\{" CATID_CATTEST1_STR "}");
167     test_key_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}\\Required Categories\\{" CATID_CATTEST2_STR "}");
168
169     hres = AtlRegisterClassCategoriesHelper(&CLSID_Test, catmap, FALSE);
170     ok(hres == S_OK, "AtlRegisterClassCategoriesHelper failed: %08x\n", hres);
171
172     test_key_not_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}\\Implemented Categories");
173     test_key_not_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}\\Required Categories");
174     test_key_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}");
175
176     ok(RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}") == ERROR_SUCCESS, "Could not delete key\n");
177
178     hres = AtlRegisterClassCategoriesHelper(&CLSID_Test, NULL, TRUE);
179     ok(hres == S_OK, "AtlRegisterClassCategoriesHelper failed: %08x\n", hres);
180
181     test_key_not_exists(HKEY_CLASSES_ROOT, "CLSID\\{" CLSID_TEST_STR "}");
182
183     b = 10;
184     hres = AtlGetPerUserRegistration(&b);
185     ok(hres == S_OK, "AtlGetPerUserRegistration failed: %08x\n", hres);
186     ok(!b, "AtlGetPerUserRegistration returned %x\n", b);
187 }
188
189 static void test_typelib(void)
190 {
191     ITypeLib *typelib;
192     HINSTANCE inst;
193     size_t len;
194     BSTR path;
195     HRESULT hres;
196
197     static const WCHAR scrrun_dll_suffixW[] = {'\\','s','c','r','r','u','n','.','d','l','l',0};
198     static const WCHAR mshtml_tlb_suffixW[] = {'\\','m','s','h','t','m','l','.','t','l','b',0};
199
200     inst = LoadLibraryA("scrrun.dll");
201     ok(inst != NULL, "Could not load scrrun.dll\n");
202
203     typelib = NULL;
204     hres = AtlLoadTypeLib(inst, NULL, &path, &typelib);
205     ok(hres == S_OK, "AtlLoadTypeLib failed: %08x\n", hres);
206     FreeLibrary(inst);
207
208     len = SysStringLen(path);
209     ok(len > sizeof(scrrun_dll_suffixW)/sizeof(WCHAR)
210        && lstrcmpiW(path+len-sizeof(scrrun_dll_suffixW)/sizeof(WCHAR), scrrun_dll_suffixW),
211        "unexpected path %s\n", wine_dbgstr_w(path));
212     SysFreeString(path);
213     ok(typelib != NULL, "typelib == NULL\n");
214     ITypeLib_Release(typelib);
215
216     inst = LoadLibraryA("mshtml.dll");
217     ok(inst != NULL, "Could not load mshtml.dll\n");
218
219     typelib = NULL;
220     hres = AtlLoadTypeLib(inst, NULL, &path, &typelib);
221     ok(hres == S_OK, "AtlLoadTypeLib failed: %08x\n", hres);
222     FreeLibrary(inst);
223
224     len = SysStringLen(path);
225     ok(len > sizeof(mshtml_tlb_suffixW)/sizeof(WCHAR)
226        && lstrcmpiW(path+len-sizeof(mshtml_tlb_suffixW)/sizeof(WCHAR), mshtml_tlb_suffixW),
227        "unexpected path %s\n", wine_dbgstr_w(path));
228     SysFreeString(path);
229     ok(typelib != NULL, "typelib == NULL\n");
230     ITypeLib_Release(typelib);
231 }
232
233 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface, REFIID riid, void **ppv)
234 {
235     if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
236         *ppv = iface;
237         return S_OK;
238     }
239
240     ok(0, "unexpected call\n");
241     return E_NOINTERFACE;
242 }
243
244 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
245 {
246     return 2;
247 }
248
249 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
250 {
251     return 1;
252 }
253
254 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
255 {
256     ok(0, "unexpected call\n");
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
261         IConnectionPointContainer **ppCPC)
262 {
263     ok(0, "unexpected call\n");
264     return E_NOTIMPL;
265 }
266
267 static int advise_cnt;
268
269 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
270                                              DWORD *pdwCookie)
271 {
272     ok(pUnkSink == (IUnknown*)0xdead0000, "pUnkSink = %p\n", pUnkSink);
273     *pdwCookie = 0xdeadbeef;
274     advise_cnt++;
275     return S_OK;
276 }
277
278 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
279 {
280     ok(dwCookie == 0xdeadbeef, "dwCookie = %x\n", dwCookie);
281     advise_cnt--;
282     return S_OK;
283 }
284
285 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
286                                                       IEnumConnections **ppEnum)
287 {
288     ok(0, "unexpected call\n");
289     return E_NOTIMPL;
290 }
291
292 static const IConnectionPointVtbl ConnectionPointVtbl =
293 {
294     ConnectionPoint_QueryInterface,
295     ConnectionPoint_AddRef,
296     ConnectionPoint_Release,
297     ConnectionPoint_GetConnectionInterface,
298     ConnectionPoint_GetConnectionPointContainer,
299     ConnectionPoint_Advise,
300     ConnectionPoint_Unadvise,
301     ConnectionPoint_EnumConnections
302 };
303
304 static IConnectionPoint ConnectionPoint = { &ConnectionPointVtbl };
305
306 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
307         REFIID riid, void **ppv)
308 {
309     if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) {
310         *ppv = iface;
311         return S_OK;
312     }
313
314     ok(0, "unexpected call\n");
315     return E_NOTIMPL;
316 }
317
318 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
319 {
320     return 2;
321 }
322
323 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
324 {
325     return 1;
326 }
327
328 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
329         IEnumConnectionPoints **ppEnum)
330 {
331     ok(0, "unexpected call\n");
332     return E_NOTIMPL;
333 }
334
335 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
336         REFIID riid, IConnectionPoint **ppCP)
337 {
338     ok(IsEqualGUID(riid, &CLSID_Test), "unexpected riid\n");
339     *ppCP = &ConnectionPoint;
340     return S_OK;
341 }
342
343 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
344     ConnectionPointContainer_QueryInterface,
345     ConnectionPointContainer_AddRef,
346     ConnectionPointContainer_Release,
347     ConnectionPointContainer_EnumConnectionPoints,
348     ConnectionPointContainer_FindConnectionPoint
349 };
350
351 static IConnectionPointContainer ConnectionPointContainer = { &ConnectionPointContainerVtbl };
352
353 static void test_cp(void)
354 {
355     DWORD cookie = 0;
356     HRESULT hres;
357
358     hres = AtlAdvise((IUnknown*)&ConnectionPointContainer, (IUnknown*)0xdead0000, &CLSID_Test, &cookie);
359     ok(hres == S_OK, "AtlAdvise failed: %08x\n", hres);
360     ok(cookie == 0xdeadbeef, "cookie = %x\n", cookie);
361     ok(advise_cnt == 1, "advise_cnt = %d\n", advise_cnt);
362
363     hres = AtlUnadvise((IUnknown*)&ConnectionPointContainer, &CLSID_Test, 0xdeadbeef);
364     ok(hres == S_OK, "AtlUnadvise failed: %08x\n", hres);
365     ok(!advise_cnt, "advise_cnt = %d\n", advise_cnt);
366 }
367
368 static CLSID persist_clsid;
369
370 static HRESULT WINAPI Persist_QueryInterface(IPersist *iface, REFIID riid, void **ppv)
371 {
372     ok(0, "unexpected call\n");
373     return E_NOINTERFACE;
374 }
375
376 static ULONG WINAPI Persist_AddRef(IPersist *iface)
377 {
378     return 2;
379 }
380
381 static ULONG WINAPI Persist_Release(IPersist *iface)
382 {
383     return 1;
384 }
385
386 static HRESULT WINAPI Persist_GetClassID(IPersist *iface, CLSID *pClassID)
387 {
388     *pClassID = persist_clsid;
389     return S_OK;
390 }
391
392 static const IPersistVtbl PersistVtbl = {
393     Persist_QueryInterface,
394     Persist_AddRef,
395     Persist_Release,
396     Persist_GetClassID
397 };
398
399 static IPersist Persist = { &PersistVtbl };
400
401 static HRESULT WINAPI ProvideClassInfo2_QueryInterface(IProvideClassInfo2 *iface, REFIID riid, void **ppv)
402 {
403     ok(0, "unexpected call\n");
404     return E_NOINTERFACE;
405 }
406
407 static ULONG WINAPI ProvideClassInfo2_AddRef(IProvideClassInfo2 *iface)
408 {
409     return 2;
410 }
411
412 static ULONG WINAPI ProvideClassInfo2_Release(IProvideClassInfo2 *iface)
413 {
414     return 1;
415 }
416
417 static HRESULT WINAPI ProvideClassInfo2_GetClassInfo(IProvideClassInfo2 *iface, ITypeInfo **ppTI)
418 {
419     ok(0, "unexpected call\n");
420     return E_NOTIMPL;
421 }
422
423 static HRESULT WINAPI ProvideClassInfo2_GetGUID(IProvideClassInfo2 *iface, DWORD dwGuidKind, GUID *pGUID)
424 {
425     ok(dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID, "unexpected dwGuidKind %x\n", dwGuidKind);
426     *pGUID = DIID_DispHTMLBody;
427     return S_OK;
428 }
429
430 static const IProvideClassInfo2Vtbl ProvideClassInfo2Vtbl = {
431     ProvideClassInfo2_QueryInterface,
432     ProvideClassInfo2_AddRef,
433     ProvideClassInfo2_Release,
434     ProvideClassInfo2_GetClassInfo,
435     ProvideClassInfo2_GetGUID
436 };
437
438 static IProvideClassInfo2 ProvideClassInfo2 = { &ProvideClassInfo2Vtbl };
439 static BOOL support_classinfo2;
440
441 static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
442 {
443     *ppv = NULL;
444
445     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDispatch, riid)) {
446         *ppv = iface;
447         return S_OK;
448     }
449
450     if(IsEqualGUID(&IID_IProvideClassInfo2, riid)) {
451         if(!support_classinfo2)
452             return E_NOINTERFACE;
453         *ppv = &ProvideClassInfo2;
454         return S_OK;
455     }
456
457     if(IsEqualGUID(&IID_IPersist, riid)) {
458         *ppv = &Persist;
459         return S_OK;
460     }
461
462     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
463     return E_NOINTERFACE;
464 }
465
466 static ULONG WINAPI Dispatch_AddRef(IDispatch *iface)
467 {
468     return 2;
469 }
470
471 static ULONG WINAPI Dispatch_Release(IDispatch *iface)
472 {
473     return 1;
474 }
475
476 static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
477 {
478     ok(0, "unexpected call\n");
479     return E_NOTIMPL;
480 }
481
482 static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid,
483         ITypeInfo **ppTInfo)
484 {
485     ITypeLib *typelib;
486     HRESULT hres;
487
488     static const WCHAR mshtml_tlbW[] = {'m','s','h','t','m','l','.','t','l','b',0};
489
490     ok(!iTInfo, "iTInfo = %d\n", iTInfo);
491     ok(!lcid, "lcid = %x\n", lcid);
492
493     hres = LoadTypeLib(mshtml_tlbW, &typelib);
494     ok(hres == S_OK, "LoadTypeLib failed: %08x\n", hres);
495
496     hres = ITypeLib_GetTypeInfoOfGuid(typelib, &IID_IHTMLElement, ppTInfo);
497     ok(hres == S_OK, "GetTypeInfoOfGuid failed: %08x\n", hres);
498
499     ITypeLib_Release(typelib);
500     return S_OK;
501 }
502
503 static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames,
504         UINT cNames, LCID lcid, DISPID *rgDispId)
505 {
506     ok(0, "unexpected call\n");
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid,
511         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
512         EXCEPINFO *pExcepInfo, UINT *puArgErr)
513 {
514     ok(0, "unexpected call\n");
515     return E_NOTIMPL;
516 }
517
518 static const IDispatchVtbl DispatchVtbl = {
519     Dispatch_QueryInterface,
520     Dispatch_AddRef,
521     Dispatch_Release,
522     Dispatch_GetTypeInfoCount,
523     Dispatch_GetTypeInfo,
524     Dispatch_GetIDsOfNames,
525     Dispatch_Invoke
526 };
527
528 static IDispatch Dispatch = { &DispatchVtbl };
529
530 static void test_source_iface(void)
531 {
532     unsigned short maj_ver, min_ver;
533     IID libid, iid;
534     HRESULT hres;
535
536     support_classinfo2 = TRUE;
537
538     maj_ver = min_ver = 0xdead;
539     hres = AtlGetObjectSourceInterface((IUnknown*)&Dispatch, &libid, &iid, &maj_ver, &min_ver);
540     ok(hres == S_OK, "AtlGetObjectSourceInterface failed: %08x\n", hres);
541     ok(IsEqualGUID(&libid, &LIBID_MSHTML), "libid = %s\n", debugstr_guid(&libid));
542     ok(IsEqualGUID(&iid, &DIID_DispHTMLBody), "iid = %s\n", debugstr_guid(&iid));
543     ok(maj_ver == 4 && min_ver == 0, "ver = %d.%d\n", maj_ver, min_ver);
544
545     support_classinfo2 = FALSE;
546     persist_clsid = CLSID_HTMLDocument;
547
548     maj_ver = min_ver = 0xdead;
549     hres = AtlGetObjectSourceInterface((IUnknown*)&Dispatch, &libid, &iid, &maj_ver, &min_ver);
550     ok(hres == S_OK, "AtlGetObjectSourceInterface failed: %08x\n", hres);
551     ok(IsEqualGUID(&libid, &LIBID_MSHTML), "libid = %s\n", debugstr_guid(&libid));
552     ok(IsEqualGUID(&iid, &DIID_HTMLDocumentEvents), "iid = %s\n", debugstr_guid(&iid));
553     ok(maj_ver == 4 && min_ver == 0, "ver = %d.%d\n", maj_ver, min_ver);
554
555     persist_clsid = CLSID_HTMLStyle;
556
557     maj_ver = min_ver = 0xdead;
558     hres = AtlGetObjectSourceInterface((IUnknown*)&Dispatch, &libid, &iid, &maj_ver, &min_ver);
559     ok(hres == S_OK, "AtlGetObjectSourceInterface failed: %08x\n", hres);
560     ok(IsEqualGUID(&libid, &LIBID_MSHTML), "libid = %s\n", debugstr_guid(&libid));
561     ok(IsEqualGUID(&iid, &IID_NULL), "iid = %s\n", debugstr_guid(&iid));
562     ok(maj_ver == 4 && min_ver == 0, "ver = %d.%d\n", maj_ver, min_ver);
563 }
564
565 START_TEST(atl)
566 {
567     CoInitialize(NULL);
568
569     test_winmodule();
570     test_regcat();
571     test_typelib();
572     test_cp();
573     test_source_iface();
574
575     CoUninitialize();
576 }