6444834ca1cb55e17c4342a16f0aee49319b084a
[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_IAccIdentity) },
38 { ID_NAME(IID_IAccPropServer) },
39 { ID_NAME(IID_IAccPropServices) },
40 { ID_NAME(IID_IAccessible) },
41 { ID_NAME(IID_IAccessibleHandler) },
42 { ID_NAME(IID_IAccessControl), TRUE },
43 { ID_NAME(IID_IAccessor) },
44 { ID_NAME(IID_IActiveDesktop), TRUE },
45 { ID_NAME(IID_IActiveDesktopP), TRUE },
46 { ID_NAME(IID_IActionProgress) },
47 { ID_NAME(IID_IActionProgressDialog) },
48 { ID_NAME(IID_IAddressBarParser), TRUE },
49 { ID_NAME(IID_IAddressBand), TRUE },
50 { ID_NAME(IID_IAddressEditBox), TRUE },
51 { ID_NAME(IID_IAugmentedShellFolder), TRUE },
52 { ID_NAME(IID_IAugmentedShellFolder2), TRUE },
53 { ID_NAME(IID_IAutoComplete), TRUE },
54 { ID_NAME(IID_IAutoComplete2), TRUE },
55 { ID_NAME(IID_IAutoCompleteDropDown) },
56 { ID_NAME(IID_IBandHost) },
57 { ID_NAME(IID_IBandNavigate), },
58 { ID_NAME(IID_IBandProxy), TRUE },
59 { ID_NAME(IID_IBandSite) },
60 { ID_NAME(IID_IBandSiteHelper), TRUE },
61 { ID_NAME(IID_IBanneredBar), TRUE },
62 { ID_NAME(IID_IBindCtx) },
63 { ID_NAME(IID_IBindEventHandler) },
64 { ID_NAME(IID_IBindHost) },
65 { ID_NAME(IID_IBinding) },
66 { ID_NAME(IID_IBindProtocol), TRUE },
67 { ID_NAME(IID_IBindResource) },
68 { ID_NAME(IID_IBindStatusCallback) },
69 { ID_NAME(IID_IBrowserFrameOptions), TRUE },
70 { ID_NAME(IID_IBrowserService) },
71 { ID_NAME(IID_IBrowserService2), TRUE },
72 { ID_NAME(IID_IBrowserService3), TRUE },
73 { ID_NAME(IID_IBrowserService4), TRUE },
74 { ID_NAME(IID_ICDBurn) },
75 { ID_NAME(IID_ICDBurnExt) },
76 { ID_NAME(IID_ICallFactory), TRUE },
77 { ID_NAME(IID_IClassFactory) },
78 { ID_NAME(IID_IClassFactory2) },
79 { ID_NAME(IID_IClassFactory3), TRUE },
80 { ID_NAME(IID_IClientSecurity), TRUE },
81 { ID_NAME(IID_ICommDlgBrowser) },
82 { ID_NAME(IID_ICommDlgBrowser2) },
83 { ID_NAME(IID_ICommDlgBrowser3) },
84 { ID_NAME(IID_IComputerInfoChangeNotify), },
85 { ID_NAME(IID_IComThreadingInfo), TRUE },
86 { ID_NAME(IID_IContext), TRUE },
87 { ID_NAME(IID_IContextMenu), TRUE },
88 { ID_NAME(IID_IContextMenu2), TRUE },
89 { ID_NAME(IID_IContextMenu3), TRUE },
90 { ID_NAME(IID_IContextMenuCB), TRUE },
91 { ID_NAME(IID_IContextMenuSite) },
92 { ID_NAME(IID_IContinue) },
93 { ID_NAME(IID_ICopyHookA), TRUE },
94 { ID_NAME(IID_ICopyHookW), TRUE },
95 { ID_NAME(IID_IDVGetEnum), TRUE },
96 { ID_NAME(IID_IDataObject) },
97 //{ ID_NAME(IID_IDefViewID) }, == DefViewFrame3
98 { ID_NAME(IID_IDefViewFrame), TRUE },
99 { ID_NAME(IID_IDefViewFrame3) },
100 { ID_NAME(IID_IDefViewFrameGroup) },
101 { ID_NAME(IID_IDefViewSafety), },
102 { ID_NAME(IID_IDefViewScript), TRUE },
103 { ID_NAME(IID_IDelayedRelease), TRUE },
104 { ID_NAME(IID_IDeskBand) },
105 { ID_NAME(IID_IDeskBandEx) },
106 { ID_NAME(IID_IDeskBar), TRUE },
107 { ID_NAME(IID_IDeskBarClient), TRUE },
108 { ID_NAME(IID_IDeskMovr), TRUE },
109 { ID_NAME(IID_IDispatch) },
110 { ID_NAME(IID_IDockingWindow) },
111 { ID_NAME(IID_IDockingWindowFrame), TRUE },
112 { ID_NAME(IID_IDockingWindowSite), TRUE },
113 { ID_NAME(IID_IDocViewSite), TRUE },
114 { ID_NAME(IID_IDragSourceHelper), TRUE },
115 { ID_NAME(IID_IDropSource) },
116 { ID_NAME(IID_IDropTarget) },
117 { ID_NAME(IID_IDropTargetHelper), TRUE },
118 { ID_NAME(IID_IEnumExtraSearch) },
119 { ID_NAME(IID_IEnumGUID) },
120 { ID_NAME(IID_IEnumIDList) },
121 { ID_NAME(IID_IEnumMoniker) },
122 //{ ID_NAME(IID_IEnumNetCfgBindingInterface) },
123 //{ ID_NAME(IID_IEnumNetCfgBindingPath) },
124 { ID_NAME(IID_IEnumNetCfgComponent), TRUE },
125 { ID_NAME(IID_IEnumNetConnection) },
126 { ID_NAME(IID_IEnumShellItems) },
127 { ID_NAME(IID_IEnumSTATSTG) },
128 { ID_NAME(IID_IEnumString) },
129 { ID_NAME(IID_IEnumUnknown) },
130 { ID_NAME(IID_IEnumVARIANT) },
131 { ID_NAME(IID_IErrorLog) },
132 { ID_NAME(IID_IExplorerBrowser) },
133 { ID_NAME(IID_IExplorerToolbar), TRUE },
134 { ID_NAME(IID_IExtractIconA), TRUE },
135 { ID_NAME(IID_IExtractIconW), TRUE },
136 { ID_NAME(IID_IExtractImage) },
137 { ID_NAME(IID_IExtractImage2) },
138 { ID_NAME(IID_IFileDialog) },
139 { ID_NAME(IID_IFileDialog2), TRUE },
140 { ID_NAME(IID_IFileOpenDialog) },
141 { ID_NAME(IID_IFileSaveDialog) },
142 { ID_NAME(IID_IFileSearchBand) },
143 { ID_NAME(IID_IFileViewerA), TRUE },
144 { ID_NAME(IID_IFileViewerSite), TRUE },
145 { ID_NAME(IID_IFileViewerW), TRUE },
146 { ID_NAME(IID_IFolderBandPriv) },
147 { ID_NAME(IID_IFolderFilter) },
148 { ID_NAME(IID_IFolderFilterSite) },
149 { ID_NAME(IID_IFolderView) },
150 { ID_NAME(IID_IFolderView2) },
151 { ID_NAME(IID_IFolderViewHost), TRUE },
152 { ID_NAME(IID_IFolderViewOC) },
153 { ID_NAME(IID_IFolderViewSettings) },
154 { ID_NAME(IID_IForegroundTransfer), TRUE },
155 { ID_NAME(IID_IGetNameSpaceExtensionPointer),TRUE},
156 { ID_NAME(IID_IGlobalFolderSettings), TRUE },
157 { ID_NAME(IID_IHWEventHandler) },
158 { ID_NAME(IID_IHWEventHandler2) },
159 { ID_NAME(IID_IImageList), TRUE },
160 { ID_NAME(IID_IImageList2), TRUE },
161 { ID_NAME(IID_IInitializeObject), TRUE },
162 { ID_NAME(IID_IInputObject) },
163 { ID_NAME(IID_IInputObjectSite) },
164 { ID_NAME(IID_IInternalUnknown), TRUE },
165 { ID_NAME(IID_IMarshal) },
166 { ID_NAME(IID_IMarshal2), TRUE },
167 { ID_NAME(IID_IMenuBand), TRUE },
168 { ID_NAME(IID_IMenuPopup), TRUE },
169 { ID_NAME(IID_IModalWindow) },
170 { ID_NAME(IID_IMoniker) },
171 { ID_NAME(IID_IMultiMonitorDockingSite), TRUE },
172 { ID_NAME(IID_IMultiQI), TRUE },
173 { ID_NAME(IID_INameSpaceTreeControl), TRUE },
174 { ID_NAME(IID_INamespaceProxy), TRUE },
175 { ID_NAME(IID_INamespaceWalk) },
176 { ID_NAME(IID_INamespaceWalkCB) },
177 { ID_NAME(IID_INamespaceWalkCB2) },
178 { ID_NAME(IID_INetCfg), TRUE },
179 //{ ID_NAME(IID_INetCfgBindingInterface) },
180 //{ ID_NAME(IID_INetCfgBindingPath) },
181 { ID_NAME(IID_INetCfgComponent), TRUE },
182 { ID_NAME(IID_INetCfgComponentBindings), TRUE },
183 { ID_NAME(IID_INetCfgComponentControl), TRUE },
184 { ID_NAME(IID_INetCfgComponentPropertyUi), TRUE },
185 { ID_NAME(IID_INetCfgLock), TRUE },
186 { ID_NAME(IID_INetCfgPnpReconfigCallback), TRUE },
187 { ID_NAME(IID_INetConnectionConnectUi), TRUE },
188 { ID_NAME(IID_INetConnectionPropertyUi), TRUE },
189 { ID_NAME(IID_INetConnectionPropertyUi2), TRUE },
190 { ID_NAME(IID_INetConnectionManager) },
191 { ID_NAME(IID_INetLanConnectionUiInfo), TRUE },
192 { ID_NAME(IID_INewShortcutHookA), TRUE },
193 { ID_NAME(IID_INewShortcutHookW), TRUE },
194 { ID_NAME(IID_INewWindowManager) },
195 { ID_NAME(IID_INSCTree), TRUE },
196 { ID_NAME(IID_INSCTree2), TRUE },
197 { ID_NAME(IID_IObjMgr), TRUE },
198 { ID_NAME(IID_IObjectSafety) },
199 { ID_NAME(IID_IObjectWithSite) },
200 { ID_NAME(IID_IOleCommandTarget) },
201 { ID_NAME(IID_IOleInPlaceActiveObject) },
202 { ID_NAME(IID_IOleInPlaceFrame) },
203 { ID_NAME(IID_IOleInPlaceObject) },
204 { ID_NAME(IID_IOleInPlaceObjectWindowless), TRUE },
205 { ID_NAME(IID_IOleInPlaceSite) },
206 { ID_NAME(IID_IOleInPlaceSiteEx) },
207 { ID_NAME(IID_IOleInPlaceSiteWindowless), TRUE },
208 { ID_NAME(IID_IOleInPlaceUIWindow) },
209 { ID_NAME(IID_IOleObject) },
210 { ID_NAME(IID_IOleWindow) },
211 { ID_NAME(IID_IPersist) },
212 { ID_NAME(IID_IPersistFile) },
213 { ID_NAME(IID_IPersistFolder) },
214 { ID_NAME(IID_IPersistFolder2) },
215 { ID_NAME(IID_IPersistFolder3) },
216 { ID_NAME(IID_IPersistFreeThreadedObject), TRUE },
217 { ID_NAME(IID_IPersistHistory) },
218 { ID_NAME(IID_IPersistIDList) },
219 { ID_NAME(IID_IPersistMemory) },
220 { ID_NAME(IID_IPersistPropertyBag) },
221 { ID_NAME(IID_IPersistPropertyBag2) },
222 { ID_NAME(IID_IPersistStorage) },
223 { ID_NAME(IID_IPersistStream) },
224 { ID_NAME(IID_IPersistStreamInit) },
225 { ID_NAME(IID_IPreviewHandler) },
226 { ID_NAME(IID_IPreviewHandlerFrame) },
227 { ID_NAME(IID_IPreviewHandlerVisuals) },
228 { ID_NAME(IID_IProgressDialog), TRUE },
229 { ID_NAME(IID_IPropertyBag) },
230 { ID_NAME(IID_IPropertyBag2) },
231 { ID_NAME(IID_IPropSheetPage), TRUE },
232 { ID_NAME(IID_IQueryAssociations), TRUE },
233 { ID_NAME(IID_IQueryInfo), TRUE },
234 { ID_NAME(IID_IRegTreeOptions), TRUE },
235 { ID_NAME(IID_IRemoteComputer) },
236 { ID_NAME(IID_IResolveShellLink) },
237 { ID_NAME(IID_IRpcOptions), TRUE },
238 { ID_NAME(IID_IRunnableObject) },
239 { ID_NAME(IID_IScriptErrorList) },
240 { ID_NAME(IID_ISearch) },
241 { ID_NAME(IID_ISearchAssistantOC) },
242 { ID_NAME(IID_ISearchAssistantOC2) },
243 { ID_NAME(IID_ISearchAssistantOC3) },
244 { ID_NAME(IID_ISearches) },
245 { ID_NAME(IID_IServerSecurity), TRUE },
246 { ID_NAME(IID_IServiceProvider) },
247 { ID_NAME(IID_IShellApp), TRUE },
248 { ID_NAME(IID_IShellBrowser) },
249 { ID_NAME(IID_IShellBrowserService), TRUE },
250 { ID_NAME(IID_IShellChangeNotify), TRUE },
251 { ID_NAME(IID_IShellCopyHookA), TRUE },
252 { ID_NAME(IID_IShellCopyHookW), TRUE },
253 { ID_NAME(IID_IShellDesktopTray), TRUE },
254 { ID_NAME(IID_IShellDetails), TRUE },
255 { ID_NAME(IID_IShellDispatch) },
256 { ID_NAME(IID_IShellDispatch2) },
257 { ID_NAME(IID_IShellDispatch3) },
258 { ID_NAME(IID_IShellDispatch4) },
259 { ID_NAME(IID_IShellDispatch5), TRUE },
260 { ID_NAME(IID_IShellDispatch6), TRUE },
261 { ID_NAME(IID_IShellExecuteHookA), TRUE },
262 { ID_NAME(IID_IShellExecuteHookW), TRUE },
263 { ID_NAME(IID_IShellExtInit), TRUE },
264 { ID_NAME(IID_IShellFavoritesNameSpace) },
265 { ID_NAME(IID_IShellFolder) },
266 { ID_NAME(IID_IShellFolder2) },
267 { ID_NAME(IID_IShellFolderBand), TRUE },
268 { ID_NAME(IID_IShellFolderSearchable), TRUE },
269 { ID_NAME(IID_IShellFolderSearchableCallback), TRUE },
270 { ID_NAME(IID_IShellFolderView), TRUE },
271 { ID_NAME(IID_IShellFolderViewCB), TRUE },
272 { ID_NAME(IID_IShellFolderViewDual) },
273 { ID_NAME(IID_IShellFolderViewDual2) },
274 { ID_NAME(IID_IShellFolderViewDual3), TRUE },
275 { ID_NAME(IID_IShellFolderViewType), TRUE },
276 { ID_NAME(IID_IShellIcon) },
277 { ID_NAME(IID_IShellIconOverlay), TRUE },
278 { ID_NAME(IID_IShellIconOverlayIdentifier), TRUE },
279 { ID_NAME(IID_IShellImageData), TRUE },
280 { ID_NAME(IID_IShellImageDataAbort), TRUE },
281 { ID_NAME(IID_IShellImageDataFactory), TRUE },
282 { ID_NAME(IID_IShellItem) },
283 { ID_NAME(IID_IShellItem2) },
284 { ID_NAME(IID_IShellItemArray) },
285 { ID_NAME(IID_IShellItemFilter) },
286 { ID_NAME(IID_IShellLinkA) },
287 { ID_NAME(IID_IShellLinkDataList), TRUE },
288 { ID_NAME(IID_IShellLinkDual) },
289 { ID_NAME(IID_IShellLinkDual2) },
290 { ID_NAME(IID_IShellLinkW) },
291 { ID_NAME(IID_IShellMenu), TRUE },
292 { ID_NAME(IID_IShellMenu2), TRUE },
293 { ID_NAME(IID_IShellMenuAcc), TRUE },
294 { ID_NAME(IID_IShellMenuCallback), TRUE },
295 { ID_NAME(IID_IShellNameSpace) },
296 { ID_NAME(IID_IShellPropSheetExt), TRUE },
297 { ID_NAME(IID_IShellService), TRUE },
298 { ID_NAME(IID_IShellTaskScheduler), TRUE },
299 { ID_NAME(IID_IShellUIHelper) },
300 { ID_NAME(IID_IShellUIHelper2), TRUE },
301 { ID_NAME(IID_IShellView) },
302 { ID_NAME(IID_IShellView2) },
303 { ID_NAME(IID_IShellView3) },
304 { ID_NAME(IID_IShellWindows) },
305 { ID_NAME(IID_IStorage) },
306 { ID_NAME(IID_IStream) },
307 { ID_NAME(IID_ISurrogate) },
308 { ID_NAME(IID_ISynchronize) },
309 { ID_NAME(IID_ISynchronizeContainer), TRUE },
310 { ID_NAME(IID_ISynchronizeEvent), TRUE },
311 { ID_NAME(IID_ISynchronizeHandle), TRUE },
312 { ID_NAME(IID_ITaskbarList) },
313 { ID_NAME(IID_ITaskbarList2) },
314 { ID_NAME(IID_ITrackShellMenu), TRUE },
315 { ID_NAME(IID_ITranslateShellChangeNotify), TRUE },
316 { ID_NAME(IID_ITrayPriv), TRUE },
317 { ID_NAME(IID_ITrayPriv2), TRUE },
318 { ID_NAME(IID_IUnknown) },
319 { ID_NAME(IID_IURLSearchHook), TRUE },
320 { ID_NAME(IID_IURLSearchHook2), TRUE },
321 { ID_NAME(IID_IViewObject) },
322 { ID_NAME(IID_IViewObject2) },
323 { ID_NAME(IID_IViewObjectEx), TRUE },
324 { ID_NAME(IID_IWebBrowser) },
325 { ID_NAME(IID_IWebBrowser2) },
326 { ID_NAME(IID_IWebBrowserApp) },
327 { ID_NAME(IID_IWinEventHandler), TRUE },
328
329 { ID_NAME(IID_DFConstraint), TRUE },
330 { ID_NAME(DIID__SearchAssistantEvents) },
331 { ID_NAME(DIID_DShellFolderViewEvents) },
332 { ID_NAME(DIID_DShellNameSpaceEvents) },
333 { ID_NAME(DIID_DShellWindowsEvents) },
334 { ID_NAME(DIID_DWebBrowserEvents) },
335 { ID_NAME(DIID_DWebBrowserEvents2) },
336 { ID_NAME(DIID_XMLDOMDocumentEvents ) },
337
338 { ID_NAME(IID_CDefView), TRUE },
339 { ID_NAME(IID_Folder) },
340 { ID_NAME(IID_Folder2) },
341 { ID_NAME(IID_Folder3) },
342 { ID_NAME(IID_FolderItem) },
343 { ID_NAME(IID_FolderItem2) },
344 { ID_NAME(IID_FolderItems) },
345 { ID_NAME(IID_FolderItems2) },
346 { ID_NAME(IID_FolderItems3) },
347 { ID_NAME(IID_FolderItemVerb) },
348 { ID_NAME(IID_FolderItemVerbs) },
349
350 { ID_NAME(CLSID_ShellDesktop), TRUE }
351 };
352 static const INT KnownInterfaceCount = RTL_NUMBER_OF(KnownInterfaces);
353
354 static
355 PCKNOWN_INTERFACE
356 FindInterface(
357 _In_ const IID *iid)
358 {
359 INT i;
360
361 for (i = 0; i < KnownInterfaceCount; i++)
362 if (IsEqualIID(KnownInterfaces[i].iid, iid))
363 return &KnownInterfaces[i];
364 ASSERT(i != KnownInterfaceCount);
365 return NULL;
366 }
367
368 static
369 BOOLEAN
370 IsInterfaceExpected(
371 _In_ PCCLASS_AND_INTERFACES class,
372 _In_ const IID *iid)
373 {
374 INT i;
375
376 for (i = 0; class->ifaces[i].iid; i++)
377 if (IsEqualIID(class->ifaces[i].iid, iid))
378 return TRUE;
379 return FALSE;
380 }
381
382 #define INTF_NOT_EXPOSED LONG_MAX
383 static
384 LONG
385 GetInterfaceOffset(
386 _In_ PUNKNOWN pUnk,
387 _In_ const IID *iid)
388 {
389 HRESULT hr;
390 PVOID pObj;
391 PUNKNOWN pUnk2;
392 LONG offset;
393
394 hr = IUnknown_QueryInterface(pUnk, iid, &pObj);
395 ok(hr == S_OK || hr == E_NOINTERFACE, "IUnknown::QueryInterface returned 0x%lx\n", hr);
396 if (FAILED(hr))
397 return INTF_NOT_EXPOSED;
398
399 pUnk2 = pObj;
400 offset = (LONG_PTR)pObj - (LONG_PTR)pUnk;
401 IUnknown_Release(pUnk2);
402 return offset;
403 }
404
405 static
406 VOID
407 TestModuleInterfaces(
408 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
409 _In_ INT ExpectedInterfaceCount)
410 {
411 HRESULT hr;
412 PVOID pObj;
413 PUNKNOWN pUnk;
414 INT iClass, iIntf;
415 PCCLASS_AND_INTERFACES class;
416
417 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
418 {
419 class = &ExpectedInterfaces[iClass];
420 hr = CoCreateInstance(class->clsid,
421 NULL,
422 CLSCTX_INPROC_SERVER,
423 &IID_IUnknown,
424 &pObj);
425 ok(hr == S_OK, "CoCreateInstance failed. hr=0x%lx\n", hr);
426 if (FAILED(hr))
427 {
428 skip("Failed to instantiate %s.\n", class->name);
429 continue;
430 }
431
432 pUnk = pObj;
433
434 /* Check that all expected interfaces are present and have the right offset */
435 for (iIntf = 0; class->ifaces[iIntf].iid; iIntf++)
436 {
437 PCKNOWN_INTERFACE iface = FindInterface(class->ifaces[iIntf].iid);
438 LONG offset = GetInterfaceOffset(pUnk, iface->iid);
439 if (offset == INTF_NOT_EXPOSED)
440 ok(0, "%s is missing %s (offset %ld)\n", class->name, iface->name, class->ifaces[iIntf].offset);
441 else if (class->ifaces[iIntf].offset != FARAWY)
442 {
443 #ifdef FAIL_WRONG_OFFSET
444 ok(offset == class->ifaces[iIntf].offset, "%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
445 #else
446 if (offset != class->ifaces[iIntf].offset)
447 mytrace("%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
448 #endif
449 }
450 }
451
452 /* Check that none other than the expected interfaces are present */
453 for (iIntf = 0; iIntf < KnownInterfaceCount; iIntf++)
454 {
455 PCKNOWN_INTERFACE iface = &KnownInterfaces[iIntf];
456 LONG offset;
457 if (IsInterfaceExpected(class, iface->iid))
458 continue;
459 offset = GetInterfaceOffset(pUnk, iface->iid);
460 #ifdef GENERATE_TABLE_ENTRIES
461 ok(offset == INTF_NOT_EXPOSED, "%s: { %s0x%lx, &%s },\n", class->name, offset < 0 ? "-" : "", offset < 0 ? -offset : offset, iface->name);
462 #else
463 ok(offset == INTF_NOT_EXPOSED, "%s exposes %s (offset %ld), but shouldn't\n", class->name, iface->name, offset);
464 #endif
465 }
466
467 // TODO: do some aggregation
468
469 IUnknown_Release(pUnk);
470 }
471 }
472
473 static
474 VOID
475 TestModuleRegistry(
476 _In_ PCWSTR ModuleName,
477 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
478 _In_ INT ExpectedInterfaceCount)
479 {
480 INT iClass;
481 PCCLASS_AND_INTERFACES class;
482 HKEY hKeyClasses;
483 LONG result;
484
485 result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyClasses);
486 ok(result == NO_ERROR, "Failed to open classes key, error %lu\n", result);
487 if (!myskip(result == NO_ERROR, "No classes key\n"))
488 {
489 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
490 {
491 HKEY hKey;
492 HKEY hKeyServer;
493 NTSTATUS status;
494 UNICODE_STRING clsid;
495 DWORD type;
496 WCHAR data[100];
497 DWORD dataSize;
498 PCWSTR expectedThreadingModel;
499
500 class = &ExpectedInterfaces[iClass];
501 status = RtlStringFromGUID(class->clsid, &clsid);
502 ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", class->name, status);
503 if (myskip(NT_SUCCESS(status), "No guid string\n"))
504 continue;
505
506 result = RegOpenKeyExW(hKeyClasses, clsid.Buffer, 0, KEY_ENUMERATE_SUB_KEYS, &hKey);
507 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
508 RtlFreeUnicodeString(&clsid);
509 if (myskip(result == NO_ERROR, "No key\n"))
510 continue;
511
512 result = RegOpenKeyExW(hKey, L"InProcServer32", 0, KEY_QUERY_VALUE, &hKeyServer);
513 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
514 RegCloseKey(hKey);
515 if (myskip(result == NO_ERROR, "No key\n"))
516 continue;
517
518 dataSize = sizeof(data);
519 result = RegQueryValueExW(hKeyServer, NULL, NULL, &type, (PBYTE)data, &dataSize);
520 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
521 if (!myskip(result == NO_ERROR, "No module name\n"))
522 {
523 ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
524 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
525 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
526 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
527 // TODO: Use SearchPath (or assume everything's in system32) and do a proper full path compare
528 PathStripPathW(data);
529 PathRemoveExtensionW(data);
530 ok(!wcsicmp(data, ModuleName), "Server is %ls, expected %ls for %s\n", data, ModuleName, class->name);
531 }
532
533 dataSize = sizeof(data);
534 result = RegQueryValueExW(hKeyServer, L"ThreadingModel", NULL, &type, (PBYTE)data, &dataSize);
535 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
536 if (!myskip(result == NO_ERROR, "No ThreadingModel\n"))
537 {
538 ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
539 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
540 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
541 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
542 expectedThreadingModel = class->ThreadingModel;
543 if (!expectedThreadingModel)
544 expectedThreadingModel = L"Apartment";
545 ok(!wcsicmp(data, expectedThreadingModel), "Server is %ls, expected %ls for %s\n", data, expectedThreadingModel, class->name);
546 }
547
548 RegCloseKey(hKeyServer);
549 }
550 RegCloseKey(hKeyClasses);
551 }
552 }
553
554 static
555 VOID
556 TestManualInstantiation(
557 _In_ PCWSTR ModuleName,
558 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
559 _In_ INT ExpectedInterfaceCount)
560 {
561 INT iClass;
562 PCCLASS_AND_INTERFACES class;
563 HRESULT (__stdcall *DllGetClassObject)(REFCLSID, REFIID, PVOID *);
564
565 DllGetClassObject = (PVOID)GetProcAddress(GetModuleHandleW(ModuleName), "DllGetClassObject");
566 ok(DllGetClassObject != NULL, "DllGetClassObject not found in %ls, error %lu\n", ModuleName, GetLastError());
567 if (myskip(DllGetClassObject != NULL, "No DllGetClassObject\n"))
568 return;
569
570 for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
571 {
572 PVOID pv;
573 HRESULT hr;
574 class = &ExpectedInterfaces[iClass];
575 hr = DllGetClassObject(class->clsid, &IID_IClassFactory, &pv);
576 ok(hr == S_OK, "DllGetClassObject failed for %s, hr = 0x%lx\n", class->name, hr);
577 if (!myskip(SUCCEEDED(hr), "No class factory\n"))
578 {
579 IClassFactory *pCF = pv;
580 hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IUnknown, &pv);
581 ok(hr == S_OK, "IClassFactory::CreateInstance failed for %s, hr = 0x%lx\n", class->name, hr);
582 if (!myskip(SUCCEEDED(hr), "No instance\n"))
583 {
584 IUnknown *pUnk = pv;
585 IUnknown_Release(pUnk);
586 }
587 IClassFactory_Release(pCF);
588 }
589 }
590 }
591
592 VOID
593 TestClasses(
594 _In_ PCWSTR ModuleName,
595 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
596 _In_ INT ExpectedInterfaceCount)
597 {
598 HRESULT hr;
599
600 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
601 ok(hr == S_OK, "CoInitializeEx failed. hr=0x%lx\n", hr);
602 if (myskip(SUCCEEDED(hr), "Failed to initialize COM. Cannot perform tests\n"))
603 return;
604
605 TestModuleInterfaces(ExpectedInterfaces, ExpectedInterfaceCount);
606 TestModuleRegistry(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
607 TestManualInstantiation(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
608
609 CoUninitialize();
610 }
611
612 static
613 VOID
614 TestInterfaceRegistry(
615 _In_ PCKNOWN_INTERFACE Interfaces,
616 _In_ INT InterfaceCount)
617 {
618 INT i;
619 HKEY hKeyInterface;
620 LONG result;
621
622 result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Interface", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyInterface);
623 ok(result == NO_ERROR, "Failed to open interface key, error %lu\n", result);
624 if (!myskip(result == NO_ERROR, "No interface key\n"))
625 {
626 for (i = 0; i < InterfaceCount; i++)
627 {
628 HKEY hKey;
629 NTSTATUS status;
630 UNICODE_STRING iid;
631 DWORD type;
632 WCHAR data[100];
633 DWORD dataSize;
634 PCKNOWN_INTERFACE iface;
635 PCWSTR expectedName;
636
637 iface = &Interfaces[i];
638 status = RtlStringFromGUID(iface->iid, &iid);
639 ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", iface->name, status);
640 if (myskip(NT_SUCCESS(status), "No guid string\n"))
641 continue;
642
643 result = RegOpenKeyExW(hKeyInterface, iid.Buffer, 0, KEY_QUERY_VALUE, &hKey);
644 if (iface->noreg)
645 {
646 ok(result == ERROR_FILE_NOT_FOUND, "RegOpenKeyEx returned %lu for %s\n", result, iface->name);
647 }
648 else
649 {
650 ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", iface->name, result);
651 (void)myskip(result == NO_ERROR, "No key\n");
652 }
653 RtlFreeUnicodeString(&iid);
654 if (result != NO_ERROR)
655 continue;
656
657 dataSize = sizeof(data);
658 result = RegQueryValueExW(hKey, NULL, NULL, &type, (PBYTE)data, &dataSize);
659 ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", iface->name, result);
660 if (!myskip(result == NO_ERROR, "No module name\n"))
661 {
662 ok(type == REG_SZ, "type %lu for %s\n", type, iface->name);
663 ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, iface->name);
664 ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, iface->name);
665 ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", iface->name);
666 expectedName = wcschr(iface->wname, L'_');
667 if (expectedName)
668 expectedName++;
669 else
670 expectedName = iface->wname;
671 ok(!wcsicmp(data, expectedName), "Name is %ls, expected %ls\n", data, expectedName);
672 }
673
674 RegCloseKey(hKey);
675 }
676 RegCloseKey(hKeyInterface);
677 }
678 }
679
680 START_TEST(interfaces)
681 {
682 TestInterfaceRegistry(KnownInterfaces, KnownInterfaceCount);
683 }