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>
8 #include "com_apitest.h"
13 #define myskip(c, ...) ((c) ? 0 : (skip(__VA_ARGS__), 1))
14 #define mytrace(...) do { \
15 int debug = winetest_debug; \
18 winetest_debug = debug; \
21 typedef struct _KNOWN_INTERFACE
26 typedef const KNOWN_INTERFACE
*PCKNOWN_INTERFACE
;
29 #define ID_NAME(c) { &c, #c }
30 static KNOWN_INTERFACE KnownInterfaces
[] =
33 ID_NAME(IID_IACList2
),
34 ID_NAME(IID_IADesktopP2
),
35 ID_NAME(IID_IAccessible
),
36 ID_NAME(IID_IAccessControl
),
37 ID_NAME(IID_IAccessor
),
38 ID_NAME(IID_IActiveDesktop
),
39 ID_NAME(IID_IActiveDesktopP
),
40 ID_NAME(IID_IAddressBarParser
),
41 ID_NAME(IID_IAddressBand
),
42 ID_NAME(IID_IAddressEditBox
),
43 ID_NAME(IID_IAugmentedShellFolder
),
44 ID_NAME(IID_IAugmentedShellFolder2
),
45 ID_NAME(IID_IAutoComplete
),
46 ID_NAME(IID_IAutoComplete2
),
47 ID_NAME(IID_IBandNavigate
),
48 ID_NAME(IID_IBandProxy
),
49 ID_NAME(IID_IBandSite
),
50 ID_NAME(IID_IBandSiteHelper
),
51 ID_NAME(IID_IBanneredBar
),
52 ID_NAME(IID_IBindCtx
),
53 ID_NAME(IID_IBrowserFrameOptions
),
54 ID_NAME(IID_IBrowserService
),
55 ID_NAME(IID_IBrowserService2
),
56 ID_NAME(IID_IBrowserService3
),
57 ID_NAME(IID_IClassFactory
),
58 ID_NAME(IID_IClassFactory2
),
59 ID_NAME(IID_IClassFactory3
),
60 ID_NAME(IID_IClientSecurity
),
61 ID_NAME(IID_IComThreadingInfo
),
62 ID_NAME(IID_IContext
),
63 ID_NAME(IID_IContextMenu
),
64 ID_NAME(IID_IContextMenu2
),
65 ID_NAME(IID_IContextMenu3
),
66 ID_NAME(IID_IContextMenuCB
),
67 ID_NAME(IID_IContextMenuSite
),
68 ID_NAME(IID_IContinue
),
69 ID_NAME(IID_IDVGetEnum
),
70 ID_NAME(IID_IDataObject
),
71 ID_NAME(IID_IDefViewID
),
72 ID_NAME(IID_IDefViewFrame
),
73 ID_NAME(IID_IDefViewFrame3
),
74 ID_NAME(IID_IDefViewFrameGroup
),
75 ID_NAME(IID_IDefViewSafety
),
76 ID_NAME(IID_IDefViewScript
),
77 ID_NAME(IID_IDeskBand
),
78 ID_NAME(IID_IDeskBandEx
),
79 ID_NAME(IID_IDeskBar
),
80 ID_NAME(IID_IDeskBarClient
),
81 ID_NAME(IID_IDeskMovr
),
82 ID_NAME(IID_IDispatch
),
83 ID_NAME(IID_IDockingWindow
),
84 ID_NAME(IID_IDockingWindowFrame
),
85 ID_NAME(IID_IDockingWindowSite
),
86 ID_NAME(IID_IDocViewSite
),
87 ID_NAME(IID_IDragSourceHelper
),
88 ID_NAME(IID_IDropSource
),
89 ID_NAME(IID_IDropTarget
),
90 ID_NAME(IID_IDropTargetHelper
),
91 ID_NAME(IID_IEnumExtraSearch
),
92 ID_NAME(IID_IEnumGUID
),
93 ID_NAME(IID_IEnumIDList
),
94 ID_NAME(IID_IEnumShellItems
),
95 ID_NAME(IID_IEnumString
),
96 ID_NAME(IID_IEnumUnknown
),
97 ID_NAME(IID_IEnumVARIANT
),
98 ID_NAME(IID_IErrorLog
),
99 ID_NAME(IID_IExplorerToolbar
),
100 ID_NAME(IID_IExtractIconA
),
101 ID_NAME(IID_IExtractIconW
),
102 ID_NAME(IID_IExtractImage
),
103 ID_NAME(IID_IExtractImage2
),
104 ID_NAME(IID_IFileDialog
),
105 ID_NAME(IID_IFileDialog2
),
106 ID_NAME(IID_IFileSearchBand
),
107 ID_NAME(IID_IFolderBandPriv
),
108 ID_NAME(IID_IFolderFilter
),
109 ID_NAME(IID_IFolderFilterSite
),
110 ID_NAME(IID_IFolderView
),
111 ID_NAME(IID_IFolderView2
),
112 ID_NAME(IID_IFolderViewOC
),
113 ID_NAME(IID_IFolderViewSettings
),
114 ID_NAME(IID_IGlobalFolderSettings
),
115 ID_NAME(IID_IInitializeObject
),
116 ID_NAME(IID_IInputObject
),
117 ID_NAME(IID_IInputObjectSite
),
118 ID_NAME(IID_IInternalUnknown
),
119 ID_NAME(IID_IMarshal
),
120 ID_NAME(IID_IMenuBand
),
121 ID_NAME(IID_IMenuPopup
),
122 ID_NAME(IID_IMoniker
),
123 ID_NAME(IID_IMultiMonitorDockingSite
),
124 ID_NAME(IID_IMultiQI
),
125 ID_NAME(IID_INamespaceProxy
),
126 ID_NAME(IID_INameSpaceTreeControl
),
127 ID_NAME(IID_INSCTree
),
128 ID_NAME(IID_INSCTree2
),
129 ID_NAME(IID_IObjMgr
),
130 ID_NAME(IID_IObjectSafety
),
131 ID_NAME(IID_IObjectWithSite
),
132 ID_NAME(IID_IOleCommandTarget
),
133 ID_NAME(IID_IOleInPlaceActiveObject
),
134 ID_NAME(IID_IOleInPlaceFrame
),
135 ID_NAME(IID_IOleInPlaceObject
),
136 ID_NAME(IID_IOleInPlaceObjectWindowless
),
137 ID_NAME(IID_IOleInPlaceSite
),
138 ID_NAME(IID_IOleInPlaceSiteEx
),
139 ID_NAME(IID_IOleInPlaceSiteWindowless
),
140 ID_NAME(IID_IOleInPlaceUIWindow
),
141 ID_NAME(IID_IOleObject
),
142 ID_NAME(IID_IOleWindow
),
143 ID_NAME(IID_IPersist
),
144 ID_NAME(IID_IPersistFile
),
145 ID_NAME(IID_IPersistFolder
),
146 ID_NAME(IID_IPersistFolder2
),
147 ID_NAME(IID_IPersistFolder3
),
148 ID_NAME(IID_IPersistHistory
),
149 ID_NAME(IID_IPersistIDList
),
150 ID_NAME(IID_IPersistMemory
),
151 ID_NAME(IID_IPersistPropertyBag
),
152 ID_NAME(IID_IPersistPropertyBag2
),
153 ID_NAME(IID_IPersistStorage
),
154 ID_NAME(IID_IPersistStream
),
155 ID_NAME(IID_IPersistStreamInit
),
156 ID_NAME(IID_IProgressDialog
),
157 ID_NAME(IID_IPropertyBag
),
158 ID_NAME(IID_IPropertyBag2
),
159 ID_NAME(IID_IQueryAssociations
),
160 ID_NAME(IID_IQueryInfo
),
161 ID_NAME(IID_IRegTreeOptions
),
162 ID_NAME(IID_IRunnableObject
),
163 ID_NAME(IID_IServerSecurity
),
164 ID_NAME(IID_IServiceProvider
),
165 ID_NAME(IID_ISFHelper
),
166 ID_NAME(IID_IShellBrowser
),
167 ID_NAME(IID_IShellBrowserService
),
168 ID_NAME(IID_IShellChangeNotify
),
169 ID_NAME(IID_IShellDesktopTray
),
170 ID_NAME(IID_IShellDispatch
),
171 ID_NAME(IID_IShellDispatch2
),
172 ID_NAME(IID_IShellDispatch3
),
173 ID_NAME(IID_IShellDispatch4
),
174 ID_NAME(IID_IShellDispatch5
),
175 ID_NAME(IID_IShellExtInit
),
176 ID_NAME(IID_IShellPropSheetExt
),
177 ID_NAME(IID_IShellIconOverlayIdentifier
),
178 ID_NAME(IID_IShellFolder
),
179 ID_NAME(IID_IShellFolder2
),
180 ID_NAME(IID_IShellFolderBand
),
181 ID_NAME(IID_IShellFolderView
),
182 ID_NAME(IID_IShellFolderViewCB
),
183 ID_NAME(IID_IShellFolderViewDual
),
184 ID_NAME(IID_IShellFolderViewDual2
),
185 ID_NAME(IID_IShellIcon
),
186 ID_NAME(IID_IShellItem
),
187 ID_NAME(IID_IShellItem2
),
188 ID_NAME(IID_IShellItemArray
),
189 ID_NAME(IID_IShellItemFilter
),
190 ID_NAME(IID_IShellLinkA
),
191 ID_NAME(IID_IShellLinkDual
),
192 ID_NAME(IID_IShellLinkDual2
),
193 ID_NAME(IID_IShellLinkW
),
194 ID_NAME(IID_IShellMenu
),
195 ID_NAME(IID_IShellMenu2
),
196 ID_NAME(IID_IShellMenuAcc
),
197 ID_NAME(IID_IShellMenuCallback
),
198 ID_NAME(IID_IShellNameSpace
),
199 ID_NAME(IID_IShellService
),
200 ID_NAME(IID_IShellView
),
201 ID_NAME(IID_IShellView2
),
202 ID_NAME(IID_IShellView3
),
203 ID_NAME(IID_IShellWindows
),
204 ID_NAME(IID_IStorage
),
205 ID_NAME(IID_IStream
),
206 ID_NAME(IID_ISurrogate
),
207 ID_NAME(IID_ISynchronize
),
208 ID_NAME(IID_ISynchronizeContainer
),
209 ID_NAME(IID_ISynchronizeEvent
),
210 ID_NAME(IID_ISynchronizeHandle
),
211 ID_NAME(IID_ITaskbarList
),
212 ID_NAME(IID_ITaskbarList2
),
213 ID_NAME(IID_ITrackShellMenu
),
214 ID_NAME(IID_ITrayPriv
),
215 ID_NAME(IID_ITrayPriv2
),
216 ID_NAME(IID_IUnknown
),
217 ID_NAME(IID_IViewObject
),
218 ID_NAME(IID_IViewObject2
),
219 ID_NAME(IID_IViewObjectEx
),
220 ID_NAME(IID_IWinEventHandler
),
222 ID_NAME(IID_DFConstraint
),
223 ID_NAME(DIID_DShellFolderViewEvents
),
225 ID_NAME(IID_CDefView
),
227 ID_NAME(IID_Folder2
),
228 ID_NAME(IID_Folder3
),
229 ID_NAME(IID_FolderItem
),
230 ID_NAME(IID_FolderItem2
),
231 ID_NAME(IID_FolderItems
),
232 ID_NAME(IID_FolderItems2
),
233 ID_NAME(IID_FolderItems3
),
234 ID_NAME(IID_FolderItemVerb
),
235 ID_NAME(IID_FolderItemVerbs
),
237 ID_NAME(CLSID_ShellDesktop
)
239 static const INT KnownInterfaceCount
= RTL_NUMBER_OF(KnownInterfaces
);
248 for (i
= 0; i
< KnownInterfaceCount
; i
++)
249 if (IsEqualIID(KnownInterfaces
[i
].iid
, iid
))
250 return &KnownInterfaces
[i
];
251 ASSERT(i
!= KnownInterfaceCount
);
258 _In_ PCCLASS_AND_INTERFACES
class,
263 for (i
= 0; class->ifaces
[i
].iid
; i
++)
264 if (IsEqualIID(class->ifaces
[i
].iid
, iid
))
269 #define INTF_NOT_EXPOSED LONG_MAX
281 hr
= IUnknown_QueryInterface(pUnk
, iid
, &pObj
);
282 ok(hr
== S_OK
|| hr
== E_NOINTERFACE
, "IUnknown::QueryInterface returned 0x%lx\n", hr
);
284 return INTF_NOT_EXPOSED
;
287 offset
= (LONG_PTR
)pObj
- (LONG_PTR
)pUnk
;
288 IUnknown_Release(pUnk2
);
294 TestModuleInterfaces(
295 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces
,
296 _In_ INT ExpectedInterfaceCount
)
302 PCCLASS_AND_INTERFACES
class;
304 for (iClass
= 0; iClass
< ExpectedInterfaceCount
; iClass
++)
306 class = &ExpectedInterfaces
[iClass
];
307 hr
= CoCreateInstance(class->clsid
,
309 CLSCTX_INPROC_SERVER
,
312 ok(hr
== S_OK
, "CoCreateInstance failed. hr=0x%lx\n", hr
);
315 skip("Failed to instantiate %s.\n", class->name
);
321 /* Check that all expected interfaces are present and have the right offset */
322 for (iIntf
= 0; class->ifaces
[iIntf
].iid
; iIntf
++)
324 PCKNOWN_INTERFACE iface
= FindInterface(class->ifaces
[iIntf
].iid
);
325 LONG offset
= GetInterfaceOffset(pUnk
, iface
->iid
);
326 if (offset
== INTF_NOT_EXPOSED
)
327 ok(0, "%s is missing %s (offset %ld)\n", class->name
, iface
->name
, class->ifaces
[iIntf
].offset
);
328 else if (class->ifaces
[iIntf
].offset
!= FARAWY
)
330 #ifdef FAIL_WRONG_OFFSET
331 ok(offset
== class->ifaces
[iIntf
].offset
, "%s, %s offset is %ld, expected %ld\n", class->name
, iface
->name
, offset
, class->ifaces
[iIntf
].offset
);
333 if (offset
!= class->ifaces
[iIntf
].offset
)
334 mytrace("%s, %s offset is %ld, expected %ld\n", class->name
, iface
->name
, offset
, class->ifaces
[iIntf
].offset
);
339 /* Check that none other than the expected interfaces are present */
340 for (iIntf
= 0; iIntf
< KnownInterfaceCount
; iIntf
++)
342 PCKNOWN_INTERFACE iface
= &KnownInterfaces
[iIntf
];
344 if (IsInterfaceExpected(class, iface
->iid
))
346 offset
= GetInterfaceOffset(pUnk
, iface
->iid
);
347 #ifdef GENERATE_TABLE_ENTRIES
348 ok(offset
== INTF_NOT_EXPOSED
, "%s: { %s%x, &%s },\n", class->name
, offset
< 0 ? "-" : "", offset
< 0 ? -offset
: offset
, iface
->name
);
350 ok(offset
== INTF_NOT_EXPOSED
, "%s exposes %s (offset %ld), but shouldn't\n", class->name
, iface
->name
, offset
);
354 // TODO: do some aggregation
356 IUnknown_Release(pUnk
);
363 _In_ PCWSTR ModuleName
,
364 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces
,
365 _In_ INT ExpectedInterfaceCount
)
368 PCCLASS_AND_INTERFACES
class;
372 result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, L
"Software\\Classes\\CLSID", 0, KEY_ENUMERATE_SUB_KEYS
, &hKeyClasses
);
373 ok(result
== NO_ERROR
, "Failed to open classes key, error %lu\n", result
);
374 if (!myskip(result
== NO_ERROR
, "No classes key\n"))
376 for (iClass
= 0; iClass
< ExpectedInterfaceCount
; iClass
++)
381 UNICODE_STRING clsid
;
385 PCWSTR expectedThreadingModel
;
387 class = &ExpectedInterfaces
[iClass
];
388 status
= RtlStringFromGUID(class->clsid
, &clsid
);
389 ok(status
== STATUS_SUCCESS
, "Failed to convert guid to string for %s, status %lx\n", class->name
, status
);
390 if (myskip(NT_SUCCESS(status
), "No guid string\n"))
393 result
= RegOpenKeyEx(hKeyClasses
, clsid
.Buffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hKey
);
394 ok(result
== NO_ERROR
, "Failed to open key for %s, error %lu\n", class->name
, result
);
395 RtlFreeUnicodeString(&clsid
);
396 if (myskip(result
== NO_ERROR
, "No key\n"))
399 result
= RegOpenKeyEx(hKey
, L
"InProcServer32", 0, KEY_QUERY_VALUE
, &hKeyServer
);
400 ok(result
== NO_ERROR
, "Failed to open key for %s, error %lu\n", class->name
, result
);
402 if (myskip(result
== NO_ERROR
, "No key\n"))
405 dataSize
= sizeof(data
);
406 result
= RegQueryValueEx(hKeyServer
, NULL
, NULL
, &type
, (PBYTE
)data
, &dataSize
);
407 ok(result
== NO_ERROR
, "Failed to query value for %s, error %lu\n", class->name
, result
);
408 if (!myskip(result
== NO_ERROR
, "No module name\n"))
410 ok(type
== REG_SZ
|| type
== REG_EXPAND_SZ
, "type %lu for %s\n", type
, class->name
);
411 ok(dataSize
% sizeof(WCHAR
) == 0, "size %lu for %s\n", dataSize
, class->name
);
412 ok(dataSize
<= sizeof(data
), "size %lu for %s\n", dataSize
, class->name
);
413 ok(data
[dataSize
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
, "Not null terminated for %s\n", class->name
);
414 // TODO: Use SearchPath (or assume everything's in system32) and do a proper full path compare
415 PathStripPathW(data
);
416 PathRemoveExtensionW(data
);
417 ok(!wcsicmp(data
, ModuleName
), "Server is %ls, expected %ls for %s\n", data
, ModuleName
, class->name
);
420 dataSize
= sizeof(data
);
421 result
= RegQueryValueEx(hKeyServer
, L
"ThreadingModel", NULL
, &type
, (PBYTE
)data
, &dataSize
);
422 ok(result
== NO_ERROR
, "Failed to query value for %s, error %lu\n", class->name
, result
);
423 if (!myskip(result
== NO_ERROR
, "No ThreadingModel\n"))
425 ok(type
== REG_SZ
|| type
== REG_EXPAND_SZ
, "type %lu for %s\n", type
, class->name
);
426 ok(dataSize
% sizeof(WCHAR
) == 0, "size %lu for %s\n", dataSize
, class->name
);
427 ok(dataSize
<= sizeof(data
), "size %lu for %s\n", dataSize
, class->name
);
428 ok(data
[dataSize
/ sizeof(WCHAR
) - 1] == UNICODE_NULL
, "Not null terminated for %s\n", class->name
);
429 expectedThreadingModel
= class->ThreadingModel
;
430 if (!expectedThreadingModel
)
431 expectedThreadingModel
= L
"Apartment";
432 ok(!wcsicmp(data
, expectedThreadingModel
), "Server is %ls, expected %ls for %s\n", data
, expectedThreadingModel
, class->name
);
435 RegCloseKey(hKeyServer
);
437 RegCloseKey(hKeyClasses
);
443 TestManualInstantiation(
444 _In_ PCWSTR ModuleName
,
445 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces
,
446 _In_ INT ExpectedInterfaceCount
)
449 PCCLASS_AND_INTERFACES
class;
450 HRESULT (__stdcall
*DllGetClassObject
)(REFCLSID
, REFIID
, PVOID
*);
452 DllGetClassObject
= (PVOID
)GetProcAddress(GetModuleHandle(ModuleName
), "DllGetClassObject");
453 ok(DllGetClassObject
!= NULL
, "DllGetClassObject not found in %ls, error %lu\n", ModuleName
, GetLastError());
454 if (myskip(DllGetClassObject
!= NULL
, "No DllGetClassObject\n"))
457 for (iClass
= 0; iClass
< ExpectedInterfaceCount
; iClass
++)
461 class = &ExpectedInterfaces
[iClass
];
462 hr
= DllGetClassObject(class->clsid
, &IID_IClassFactory
, &pv
);
463 ok(hr
== S_OK
, "DllGetClassObject failed for %s, hr = 0x%lx\n", class->name
, hr
);
464 if (!myskip(SUCCEEDED(hr
), "No class factory\n"))
466 IClassFactory
*pCF
= pv
;
467 hr
= IClassFactory_CreateInstance(pCF
, NULL
, &IID_IUnknown
, &pv
);
468 ok(hr
== S_OK
, "IClassFactory::CreateInstance failed for %s, hr = 0x%lx\n", class->name
, hr
);
469 if (!myskip(SUCCEEDED(hr
), "No instance\n"))
472 IUnknown_Release(pUnk
);
474 IClassFactory_Release(pCF
);
481 _In_ PCWSTR ModuleName
,
482 _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces
,
483 _In_ INT ExpectedInterfaceCount
)
487 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
488 ok(hr
== S_OK
, "CoInitializeEx failed. hr=0x%lx\n", hr
);
489 if (myskip(SUCCEEDED(hr
), "Failed to initialize COM. Cannot perform tests\n"))
492 TestModuleInterfaces(ExpectedInterfaces
, ExpectedInterfaceCount
);
493 TestModuleRegistry(ModuleName
, ExpectedInterfaces
, ExpectedInterfaceCount
);
494 TestManualInstantiation(ModuleName
, ExpectedInterfaces
, ExpectedInterfaceCount
);