[REACTOS]
[reactos.git] / rostests / apitests / com / com_apitest.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: COM interface test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include "com_apitest.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define myskip(c, ...) ((c) ? 0 : (skip(__VA_ARGS__), 1))
14 #define mytrace(...) do { \
15 int debug = winetest_debug; \
16 winetest_debug = 1; \
17 trace(__VA_ARGS__); \
18 winetest_debug = debug; \
19 } while (0)
20
21 typedef struct _KNOWN_INTERFACE
22 {
23 const IID *iid;
24 PCSTR name;
25 PCWSTR wname;
26 BOOLEAN noreg;
27 } KNOWN_INTERFACE;
28 typedef const KNOWN_INTERFACE *PCKNOWN_INTERFACE;
29
30 #undef ID_NAME
31 #define ID_NAME(c) &c, #c, L ## #c
32 static KNOWN_INTERFACE KnownInterfaces[] =
33 {
34 { ID_NAME(IID_IACList), TRUE },
35 { ID_NAME(IID_IACList2), TRUE },
36 { ID_NAME(IID_IADesktopP2), TRUE },
37 { ID_NAME(IID_IAccessible) },
38 { ID_NAME(IID_IAccessControl), TRUE },
39 { ID_NAME(IID_IAccessor) },
40 { ID_NAME(IID_IActiveDesktop), TRUE },
41 { ID_NAME(IID_IActiveDesktopP), TRUE },
42 { ID_NAME(IID_IAddressBarParser), TRUE },
43 { ID_NAME(IID_IAddressBand), TRUE },
44 { ID_NAME(IID_IAddressEditBox), TRUE },
45 { ID_NAME(IID_IAugmentedShellFolder), TRUE },
46 { ID_NAME(IID_IAugmentedShellFolder2), TRUE },
47 { ID_NAME(IID_IAutoComplete), TRUE },
48 { ID_NAME(IID_IAutoComplete2), TRUE },
49 { ID_NAME(IID_IBandNavigate), TRUE },
50 { ID_NAME(IID_IBandProxy), TRUE },
51 { ID_NAME(IID_IBandSite) },
52 { ID_NAME(IID_IBandSiteHelper), TRUE },
53 { ID_NAME(IID_IBanneredBar), TRUE },
54 { ID_NAME(IID_IBindCtx) },
55 { ID_NAME(IID_IBrowserFrameOptions), TRUE },
56 { ID_NAME(IID_IBrowserService) },
57 { ID_NAME(IID_IBrowserService2), TRUE },
58 { ID_NAME(IID_IBrowserService3), TRUE },
59 { ID_NAME(IID_IClassFactory) },
60 { ID_NAME(IID_IClassFactory2) },
61 { ID_NAME(IID_IClassFactory3), TRUE },
62 { ID_NAME(IID_IClientSecurity), TRUE },
63 { ID_NAME(IID_IComThreadingInfo), TRUE },
64 { ID_NAME(IID_IContext), TRUE },
65 { ID_NAME(IID_IContextMenu), TRUE },
66 { ID_NAME(IID_IContextMenu2), TRUE },
67 { ID_NAME(IID_IContextMenu3), TRUE },
68 { ID_NAME(IID_IContextMenuCB), TRUE },
69 { ID_NAME(IID_IContextMenuSite) },
70 { ID_NAME(IID_IContinue) },
71 { ID_NAME(IID_IDVGetEnum), TRUE },
72 { ID_NAME(IID_IDataObject) },
73 //{ ID_NAME(IID_IDefViewID) }, == DefViewFrame3
74 { ID_NAME(IID_IDefViewFrame), TRUE },
75 { ID_NAME(IID_IDefViewFrame3) },
76 { ID_NAME(IID_IDefViewFrameGroup) },
77 { ID_NAME(IID_IDefViewSafety), },
78 { ID_NAME(IID_IDefViewScript), TRUE },
79 { ID_NAME(IID_IDeskBand) },
80 { ID_NAME(IID_IDeskBandEx) },
81 { ID_NAME(IID_IDeskBar), TRUE },
82 { ID_NAME(IID_IDeskBarClient), TRUE },
83 { ID_NAME(IID_IDeskMovr), TRUE },
84 { ID_NAME(IID_IDispatch) },
85 { ID_NAME(IID_IDockingWindow) },
86 { ID_NAME(IID_IDockingWindowFrame), TRUE },
87 { ID_NAME(IID_IDockingWindowSite), TRUE },
88 { ID_NAME(IID_IDocViewSite), TRUE },
89 { ID_NAME(IID_IDragSourceHelper), TRUE },
90 { ID_NAME(IID_IDropSource) },
91 { ID_NAME(IID_IDropTarget) },
92 { ID_NAME(IID_IDropTargetHelper), TRUE },
93 { ID_NAME(IID_IEnumExtraSearch) },
94 { ID_NAME(IID_IEnumGUID) },
95 { ID_NAME(IID_IEnumIDList) },
96 { ID_NAME(IID_IEnumShellItems) },
97 { ID_NAME(IID_IEnumString) },
98 { ID_NAME(IID_IEnumUnknown) },
99 { ID_NAME(IID_IEnumVARIANT) },
100 { ID_NAME(IID_IErrorLog) },
101 { ID_NAME(IID_IExplorerToolbar), TRUE },
102 { ID_NAME(IID_IExtractIconA), TRUE },
103 { ID_NAME(IID_IExtractIconW), TRUE },
104 { ID_NAME(IID_IExtractImage) },
105 { ID_NAME(IID_IExtractImage2) },
106 { ID_NAME(IID_IFileDialog) },
107 { ID_NAME(IID_IFileDialog2), TRUE },
108 { ID_NAME(IID_IFileSearchBand) },
109 { ID_NAME(IID_IFolderBandPriv) },
110 { ID_NAME(IID_IFolderFilter) },
111 { ID_NAME(IID_IFolderFilterSite) },
112 { ID_NAME(IID_IFolderView) },
113 { ID_NAME(IID_IFolderView2) },
114 { ID_NAME(IID_IFolderViewOC) },
115 { ID_NAME(IID_IFolderViewSettings) },
116 { ID_NAME(IID_IGlobalFolderSettings), TRUE },
117 { ID_NAME(IID_IInitializeObject), TRUE },
118 { ID_NAME(IID_IInputObject) },
119 { ID_NAME(IID_IInputObjectSite) },
120 { ID_NAME(IID_IInternalUnknown), TRUE },
121 { ID_NAME(IID_IMarshal) },
122 { ID_NAME(IID_IMenuBand), TRUE },
123 { ID_NAME(IID_IMenuPopup), TRUE },
124 { ID_NAME(IID_IMoniker) },
125 { ID_NAME(IID_IMultiMonitorDockingSite), TRUE },
126 { ID_NAME(IID_IMultiQI), TRUE },
127 { ID_NAME(IID_INamespaceProxy), TRUE },
128 { ID_NAME(IID_INameSpaceTreeControl), TRUE },
129 { ID_NAME(IID_INSCTree), TRUE },
130 { ID_NAME(IID_INSCTree2), TRUE },
131 { ID_NAME(IID_IObjMgr), TRUE },
132 { ID_NAME(IID_IObjectSafety) },
133 { ID_NAME(IID_IObjectWithSite) },
134 { ID_NAME(IID_IOleCommandTarget) },
135 { ID_NAME(IID_IOleInPlaceActiveObject) },
136 { ID_NAME(IID_IOleInPlaceFrame) },
137 { ID_NAME(IID_IOleInPlaceObject) },
138 { ID_NAME(IID_IOleInPlaceObjectWindowless), TRUE },
139 { ID_NAME(IID_IOleInPlaceSite) },
140 { ID_NAME(IID_IOleInPlaceSiteEx) },
141 { ID_NAME(IID_IOleInPlaceSiteWindowless), TRUE },
142 { ID_NAME(IID_IOleInPlaceUIWindow) },
143 { ID_NAME(IID_IOleObject) },
144 { ID_NAME(IID_IOleWindow) },
145 { ID_NAME(IID_IPersist) },
146 { ID_NAME(IID_IPersistFile) },
147 { ID_NAME(IID_IPersistFolder) },
148 { ID_NAME(IID_IPersistFolder2) },
149 { ID_NAME(IID_IPersistFolder3) },
150 { ID_NAME(IID_IPersistHistory) },
151 { ID_NAME(IID_IPersistIDList) },
152 { ID_NAME(IID_IPersistMemory) },
153 { ID_NAME(IID_IPersistPropertyBag) },
154 { ID_NAME(IID_IPersistPropertyBag2) },
155 { ID_NAME(IID_IPersistStorage) },
156 { ID_NAME(IID_IPersistStream) },
157 { ID_NAME(IID_IPersistStreamInit) },
158 { ID_NAME(IID_IProgressDialog), TRUE },
159 { ID_NAME(IID_IPropertyBag) },
160 { ID_NAME(IID_IPropertyBag2) },
161 { ID_NAME(IID_IQueryAssociations), TRUE },
162 { ID_NAME(IID_IQueryInfo), TRUE },
163 { ID_NAME(IID_IRegTreeOptions), TRUE },
164 { ID_NAME(IID_IRunnableObject) },
165 { ID_NAME(IID_IServerSecurity), TRUE },
166 { ID_NAME(IID_IServiceProvider) },
167 { ID_NAME(IID_ISFHelper), TRUE },
168 { ID_NAME(IID_IShellBrowser) },
169 { ID_NAME(IID_IShellBrowserService), TRUE },
170 { ID_NAME(IID_IShellChangeNotify), TRUE },
171 { ID_NAME(IID_IShellDesktopTray), TRUE },
172 { ID_NAME(IID_IShellDispatch) },
173 { ID_NAME(IID_IShellDispatch2) },
174 { ID_NAME(IID_IShellDispatch3) },
175 { ID_NAME(IID_IShellDispatch4) },
176 { ID_NAME(IID_IShellDispatch5), TRUE },
177 { ID_NAME(IID_IShellExtInit), TRUE },
178 { ID_NAME(IID_IShellPropSheetExt), TRUE },
179 { ID_NAME(IID_IShellIconOverlayIdentifier), TRUE },
180 { ID_NAME(IID_IShellFolder) },
181 { ID_NAME(IID_IShellFolder2) },
182 { ID_NAME(IID_IShellFolderBand), TRUE },
183 { ID_NAME(IID_IShellFolderView), TRUE },
184 { ID_NAME(IID_IShellFolderViewCB), TRUE },
185 { ID_NAME(IID_IShellFolderViewDual) },
186 { ID_NAME(IID_IShellFolderViewDual2) },
187 { ID_NAME(IID_IShellIcon) },
188 { ID_NAME(IID_IShellItem) },
189 { ID_NAME(IID_IShellItem2) },
190 { ID_NAME(IID_IShellItemArray) },
191 { ID_NAME(IID_IShellItemFilter) },
192 { ID_NAME(IID_IShellLinkA) },
193 { ID_NAME(IID_IShellLinkDual) },
194 { ID_NAME(IID_IShellLinkDual2) },
195 { ID_NAME(IID_IShellLinkW) },
196 { ID_NAME(IID_IShellMenu), TRUE },
197 { ID_NAME(IID_IShellMenu2), TRUE },
198 { ID_NAME(IID_IShellMenuAcc), TRUE },
199 { ID_NAME(IID_IShellMenuCallback), TRUE },
200 { ID_NAME(IID_IShellNameSpace) },
201 { ID_NAME(IID_IShellService), TRUE },
202 { ID_NAME(IID_IShellView) },
203 { ID_NAME(IID_IShellView2) },
204 { ID_NAME(IID_IShellView3) },
205 { ID_NAME(IID_IShellWindows) },
206 { ID_NAME(IID_IStorage) },
207 { ID_NAME(IID_IStream) },
208 { ID_NAME(IID_ISurrogate) },
209 { ID_NAME(IID_ISynchronize) },
210 { ID_NAME(IID_ISynchronizeContainer), TRUE },
211 { ID_NAME(IID_ISynchronizeEvent), TRUE },
212 { ID_NAME(IID_ISynchronizeHandle), TRUE },
213 { ID_NAME(IID_ITaskbarList) },
214 { ID_NAME(IID_ITaskbarList2) },
215 { ID_NAME(IID_ITrackShellMenu), TRUE },
216 { ID_NAME(IID_ITrayPriv), TRUE },
217 { ID_NAME(IID_ITrayPriv2), TRUE },
218 { ID_NAME(IID_IUnknown) },
219 { ID_NAME(IID_IViewObject) },
220 { ID_NAME(IID_IViewObject2) },
221 { ID_NAME(IID_IViewObjectEx), TRUE },
222 { ID_NAME(IID_IWinEventHandler), TRUE },
223
224 { ID_NAME(IID_DFConstraint), TRUE },
225 { ID_NAME(DIID_DShellFolderViewEvents) },
226
227 { ID_NAME(IID_CDefView), TRUE },
228 { ID_NAME(IID_Folder) },
229 { ID_NAME(IID_Folder2) },
230 { ID_NAME(IID_Folder3) },
231 { ID_NAME(IID_FolderItem) },
232 { ID_NAME(IID_FolderItem2) },
233 { ID_NAME(IID_FolderItems) },
234 { ID_NAME(IID_FolderItems2) },
235 { ID_NAME(IID_FolderItems3) },
236 { ID_NAME(IID_FolderItemVerb) },
237 { ID_NAME(IID_FolderItemVerbs) },
238
239 { ID_NAME(CLSID_ShellDesktop), TRUE }
240 };
241 static const INT KnownInterfaceCount = RTL_NUMBER_OF(KnownInterfaces);
242
243 static
244 PCKNOWN_INTERFACE
245 FindInterface(
246 _In_ const IID *iid)
247 {
248 INT i;
249
250 for (i = 0; i < KnownInterfaceCount; i++)
251 if (IsEqualIID(KnownInterfaces[i].iid, iid))
252 return &KnownInterfaces[i];
253 ASSERT(i != KnownInterfaceCount);
254 return NULL;
255 }
256
257 static
258 BOOLEAN
259 IsInterfaceExpected(
260 _In_ PCCLASS_AND_INTERFACES class,
261 _In_ const IID *iid)
262 {
263 INT i;
264
265 for (i = 0; class->ifaces[i].iid; i++)
266 if (IsEqualIID(class->ifaces[i].iid, iid))
267 return TRUE;
268 return FALSE;
269 }
270
271 #define INTF_NOT_EXPOSED LONG_MAX
272 static
273 LONG
274 GetInterfaceOffset(
275 _In_ PUNKNOWN pUnk,
276 _In_ const IID *iid)
277 {
278 HRESULT hr;
279 PVOID pObj;
280 PUNKNOWN pUnk2;
281 LONG offset;
282
283 hr = IUnknown_QueryInterface(pUnk, iid, &pObj);
284 ok(hr == S_OK || hr == E_NOINTERFACE, "IUnknown::QueryInterface returned 0x%lx\n", hr);
285 if (FAILED(hr))
286 return INTF_NOT_EXPOSED;
287
288 pUnk2 = pObj;
289 offset = (LONG_PTR)pObj - (LONG_PTR)pUnk;
290 IUnknown_Release(pUnk2);
291 return offset;
292 }
293
294 static
295 VOID
296 TestModuleInterfaces(
297 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
298 _In_ INT ExpectedInterfaceCount)
299 {
300 HRESULT hr;
301 PVOID pObj;
302 PUNKNOWN pUnk;
303 INT iClass, iIntf;
304 PCCLASS_AND_INTERFACES class;
305
306 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
307 {
308 class = &ExpectedInterfaces[iClass];
309 hr = CoCreateInstance(class->clsid,
310 NULL,
311 CLSCTX_INPROC_SERVER,
312 &IID_IUnknown,
313 &pObj);
314 ok(hr == S_OK, "CoCreateInstance failed. hr=0x%lx\n", hr);
315 if (FAILED(hr))
316 {
317 skip("Failed to instantiate %s.\n", class->name);
318 continue;
319 }
320
321 pUnk = pObj;
322
323 /* Check that all expected interfaces are present and have the right offset */
324 for (iIntf = 0; class->ifaces[iIntf].iid; iIntf++)
325 {
326 PCKNOWN_INTERFACE iface = FindInterface(class->ifaces[iIntf].iid);
327 LONG offset = GetInterfaceOffset(pUnk, iface->iid);
328 if (offset == INTF_NOT_EXPOSED)
329 ok(0, "%s is missing %s (offset %ld)\n", class->name, iface->name, class->ifaces[iIntf].offset);
330 else if (class->ifaces[iIntf].offset != FARAWY)
331 {
332 #ifdef FAIL_WRONG_OFFSET
333 ok(offset == class->ifaces[iIntf].offset, "%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
334 #else
335 if (offset != class->ifaces[iIntf].offset)
336 mytrace("%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
337 #endif
338 }
339 }
340
341 /* Check that none other than the expected interfaces are present */
342 for (iIntf = 0; iIntf < KnownInterfaceCount; iIntf++)
343 {
344 PCKNOWN_INTERFACE iface = &KnownInterfaces[iIntf];
345 LONG offset;
346 if (IsInterfaceExpected(class, iface->iid))
347 continue;
348 offset = GetInterfaceOffset(pUnk, iface->iid);
349 #ifdef GENERATE_TABLE_ENTRIES
350 ok(offset == INTF_NOT_EXPOSED, "%s: { %s0x%x, &%s },\n", class->name, offset < 0 ? "-" : "", offset < 0 ? -offset : offset, iface->name);
351 #else
352 ok(offset == INTF_NOT_EXPOSED, "%s exposes %s (offset %ld), but shouldn't\n", class->name, iface->name, offset);
353 #endif
354 }
355
356 // TODO: do some aggregation
357
358 IUnknown_Release(pUnk);
359 }
360 }
361
362 static
363 VOID
364 TestModuleRegistry(
365 _In_ PCWSTR ModuleName,
366 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
367 _In_ INT ExpectedInterfaceCount)
368 {
369 INT iClass;
370 PCCLASS_AND_INTERFACES class;
371 HKEY hKeyClasses;
372 LONG result;
373
374 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyClasses);
375 ok(result == NO_ERROR, "Failed to open classes key, error %lu\n", result);
376 if (!myskip(result == NO_ERROR, "No classes key\n"))
377 {
378 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
379 {
380 HKEY hKey;
381 HKEY hKeyServer;
382 NTSTATUS status;
383 UNICODE_STRING clsid;
384 DWORD type;
385 WCHAR data[100];
386 DWORD dataSize;
387 PCWSTR expectedThreadingModel;
388
389 class = &ExpectedInterfaces[iClass];
390 status = RtlStringFromGUID(class->clsid, &clsid);
391 ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", class->name, status);
392 if (myskip(NT_SUCCESS(status), "No guid string\n"))
393 continue;
394
395 result = RegOpenKeyEx(hKeyClasses, clsid.Buffer, 0, KEY_ENUMERATE_SUB_KEYS, &hKey);
396 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
397 RtlFreeUnicodeString(&clsid);
398 if (myskip(result == NO_ERROR, "No key\n"))
399 continue;
400
401 result = RegOpenKeyEx(hKey, L"InProcServer32", 0, KEY_QUERY_VALUE, &hKeyServer);
402 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
403 RegCloseKey(hKey);
404 if (myskip(result == NO_ERROR, "No key\n"))
405 continue;
406
407 dataSize = sizeof(data);
408 result = RegQueryValueEx(hKeyServer, NULL, NULL, &type, (PBYTE)data, &dataSize);
409 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
410 if (!myskip(result == NO_ERROR, "No module name\n"))
411 {
412 ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
413 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
414 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
415 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
416 // TODO: Use SearchPath (or assume everything's in system32) and do a proper full path compare
417 PathStripPathW(data);
418 PathRemoveExtensionW(data);
419 ok(!wcsicmp(data, ModuleName), "Server is %ls, expected %ls for %s\n", data, ModuleName, class->name);
420 }
421
422 dataSize = sizeof(data);
423 result = RegQueryValueEx(hKeyServer, L"ThreadingModel", NULL, &type, (PBYTE)data, &dataSize);
424 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
425 if (!myskip(result == NO_ERROR, "No ThreadingModel\n"))
426 {
427 ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
428 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
429 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
430 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
431 expectedThreadingModel = class->ThreadingModel;
432 if (!expectedThreadingModel)
433 expectedThreadingModel = L"Apartment";
434 ok(!wcsicmp(data, expectedThreadingModel), "Server is %ls, expected %ls for %s\n", data, expectedThreadingModel, class->name);
435 }
436
437 RegCloseKey(hKeyServer);
438 }
439 RegCloseKey(hKeyClasses);
440 }
441 }
442
443 static
444 VOID
445 TestManualInstantiation(
446 _In_ PCWSTR ModuleName,
447 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
448 _In_ INT ExpectedInterfaceCount)
449 {
450 INT iClass;
451 PCCLASS_AND_INTERFACES class;
452 HRESULT (__stdcall *DllGetClassObject)(REFCLSID, REFIID, PVOID *);
453
454 DllGetClassObject = (PVOID)GetProcAddress(GetModuleHandle(ModuleName), "DllGetClassObject");
455 ok(DllGetClassObject != NULL, "DllGetClassObject not found in %ls, error %lu\n", ModuleName, GetLastError());
456 if (myskip(DllGetClassObject != NULL, "No DllGetClassObject\n"))
457 return;
458
459 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
460 {
461 PVOID pv;
462 HRESULT hr;
463 class = &ExpectedInterfaces[iClass];
464 hr = DllGetClassObject(class->clsid, &IID_IClassFactory, &pv);
465 ok(hr == S_OK, "DllGetClassObject failed for %s, hr = 0x%lx\n", class->name, hr);
466 if (!myskip(SUCCEEDED(hr), "No class factory\n"))
467 {
468 IClassFactory *pCF = pv;
469 hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IUnknown, &pv);
470 ok(hr == S_OK, "IClassFactory::CreateInstance failed for %s, hr = 0x%lx\n", class->name, hr);
471 if (!myskip(SUCCEEDED(hr), "No instance\n"))
472 {
473 IUnknown *pUnk = pv;
474 IUnknown_Release(pUnk);
475 }
476 IClassFactory_Release(pCF);
477 }
478 }
479 }
480
481 VOID
482 TestClasses(
483 _In_ PCWSTR ModuleName,
484 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
485 _In_ INT ExpectedInterfaceCount)
486 {
487 HRESULT hr;
488
489 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
490 ok(hr == S_OK, "CoInitializeEx failed. hr=0x%lx\n", hr);
491 if (myskip(SUCCEEDED(hr), "Failed to initialize COM. Cannot perform tests\n"))
492 return;
493
494 TestModuleInterfaces(ExpectedInterfaces, ExpectedInterfaceCount);
495 TestModuleRegistry(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
496 TestManualInstantiation(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
497
498 CoUninitialize();
499 }
500
501 static
502 VOID
503 TestInterfaceRegistry(
504 _In_ PCKNOWN_INTERFACE Interfaces,
505 _In_ INT InterfaceCount)
506 {
507 INT i;
508 HKEY hKeyInterface;
509 LONG result;
510
511 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Interface", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyInterface);
512 ok(result == NO_ERROR, "Failed to open interface key, error %lu\n", result);
513 if (!myskip(result == NO_ERROR, "No interface key\n"))
514 {
515 for (i = 0; i < InterfaceCount; i++)
516 {
517 HKEY hKey;
518 NTSTATUS status;
519 UNICODE_STRING iid;
520 DWORD type;
521 WCHAR data[100];
522 DWORD dataSize;
523 PCKNOWN_INTERFACE iface;
524 PCWSTR expectedName;
525
526 iface = &Interfaces[i];
527 status = RtlStringFromGUID(iface->iid, &iid);
528 ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", iface->name, status);
529 if (myskip(NT_SUCCESS(status), "No guid string\n"))
530 continue;
531
532 result = RegOpenKeyEx(hKeyInterface, iid.Buffer, 0, KEY_QUERY_VALUE, &hKey);
533 if (iface->noreg)
534 {
535 ok(result == ERROR_FILE_NOT_FOUND, "RegOpenKeyEx returned %lu for %s\n", result, iface->name);
536 }
537 else
538 {
539 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", iface->name, result);
540 (void)myskip(result == NO_ERROR, "No key\n");
541 }
542 RtlFreeUnicodeString(&iid);
543 if (result != NO_ERROR)
544 continue;
545
546 dataSize = sizeof(data);
547 result = RegQueryValueEx(hKey, NULL, NULL, &type, (PBYTE)data, &dataSize);
548 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", iface->name, result);
549 if (!myskip(result == NO_ERROR, "No module name\n"))
550 {
551 ok(type == REG_SZ, "type %lu for %s\n", type, iface->name);
552 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, iface->name);
553 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, iface->name);
554 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", iface->name);
555 expectedName = wcschr(iface->wname, L'_');
556 if (expectedName)
557 expectedName++;
558 else
559 expectedName = iface->wname;
560 ok(!wcsicmp(data, expectedName), "Name is %ls, expected %ls\n", data, expectedName);
561 }
562
563 RegCloseKey(hKey);
564 }
565 RegCloseKey(hKeyInterface);
566 }
567 }
568
569 START_TEST(interfaces)
570 {
571 TestInterfaceRegistry(KnownInterfaces, KnownInterfaceCount);
572 }