mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
823 lines
37 KiB
C
823 lines
37 KiB
C
/*
|
|
* PROJECT: ReactOS api tests
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
* PURPOSE: COM interface test
|
|
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
|
*/
|
|
|
|
#include "com_apitest.h"
|
|
|
|
#include <winreg.h>
|
|
#include <mshtmhst.h>
|
|
#include <shlwapi.h>
|
|
#include <commoncontrols.h>
|
|
#include <activscp.h>
|
|
#include <ndk/rtlfuncs.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define myskip(c, ...) ((c) ? 0 : (skip(__VA_ARGS__), 1))
|
|
#define mytrace(...) do { \
|
|
int debug = winetest_debug; \
|
|
winetest_debug = 1; \
|
|
trace(__VA_ARGS__); \
|
|
winetest_debug = debug; \
|
|
} while (0)
|
|
|
|
typedef struct _KNOWN_INTERFACE
|
|
{
|
|
const IID *iid;
|
|
PCSTR name;
|
|
PCWSTR wname;
|
|
BOOLEAN noreg;
|
|
} KNOWN_INTERFACE;
|
|
typedef const KNOWN_INTERFACE *PCKNOWN_INTERFACE;
|
|
|
|
#undef ID_NAME
|
|
#define ID_NAME(c) &c, #c, L ## #c
|
|
static KNOWN_INTERFACE KnownInterfaces[] =
|
|
{
|
|
{ ID_NAME(IID_IACList), TRUE },
|
|
{ ID_NAME(IID_IACList2), TRUE },
|
|
{ ID_NAME(IID_IADesktopP2), TRUE },
|
|
{ ID_NAME(IID_IAccIdentity) },
|
|
{ ID_NAME(IID_IAccPropServer) },
|
|
{ ID_NAME(IID_IAccPropServices) },
|
|
{ ID_NAME(IID_IAccessible) },
|
|
{ ID_NAME(IID_IAccessibleHandler) },
|
|
{ ID_NAME(IID_IAccessControl), TRUE },
|
|
{ ID_NAME(IID_IAccessor) },
|
|
{ ID_NAME(IID_IACLCustomMRU), TRUE },
|
|
{ ID_NAME(IID_IActiveDesktop), TRUE },
|
|
{ ID_NAME(IID_IActiveDesktopP), TRUE },
|
|
{ ID_NAME(IID_IActionProgress) },
|
|
{ ID_NAME(IID_IActionProgressDialog) },
|
|
{ ID_NAME(IID_IAddressBarParser), TRUE },
|
|
{ ID_NAME(IID_IAddressBand), TRUE },
|
|
{ ID_NAME(IID_IAddressEditBox), TRUE },
|
|
{ ID_NAME(IID_IAsyncMoniker), TRUE },
|
|
{ ID_NAME(IID_IAugmentedShellFolder), TRUE },
|
|
{ ID_NAME(IID_IAugmentedShellFolder2), TRUE },
|
|
{ ID_NAME(IID_IAutoComplete), TRUE },
|
|
{ ID_NAME(IID_IAutoComplete2), TRUE },
|
|
{ ID_NAME(IID_IAutoCompleteDropDown) },
|
|
{ ID_NAME(IID_IBandHost) },
|
|
{ ID_NAME(IID_IBandNavigate), },
|
|
{ ID_NAME(IID_IBandProxy), TRUE },
|
|
{ ID_NAME(IID_IBandSite) },
|
|
{ ID_NAME(IID_IBandSiteHelper), TRUE },
|
|
{ ID_NAME(IID_IBanneredBar), TRUE },
|
|
{ ID_NAME(IID_IBindCtx) },
|
|
{ ID_NAME(IID_IBindEventHandler) },
|
|
{ ID_NAME(IID_IBindHost) },
|
|
{ ID_NAME(IID_IBinding) },
|
|
{ ID_NAME(IID_IBindProtocol), TRUE },
|
|
{ ID_NAME(IID_IBindResource) },
|
|
{ ID_NAME(IID_IBindStatusCallback) },
|
|
{ ID_NAME(IID_IBlockingLock) },
|
|
{ ID_NAME(IID_IBrowserFrameOptions), TRUE },
|
|
{ ID_NAME(IID_IBrowserService) },
|
|
{ ID_NAME(IID_IBrowserService2), TRUE },
|
|
{ ID_NAME(IID_IBrowserService3), TRUE },
|
|
{ ID_NAME(IID_IBrowserService4), TRUE },
|
|
{ ID_NAME(IID_ICDBurn) },
|
|
{ ID_NAME(IID_ICDBurnExt) },
|
|
{ ID_NAME(IID_ICDBurnPriv) },
|
|
{ ID_NAME(IID_ICallFactory), TRUE },
|
|
{ ID_NAME(IID_ICancelMethodCalls), TRUE },
|
|
{ ID_NAME(IID_ICatInformation) },
|
|
{ ID_NAME(IID_ICatRegister) },
|
|
{ ID_NAME(IID_IClassActivator), },
|
|
{ ID_NAME(IID_IClassFactory) },
|
|
{ ID_NAME(IID_IClassFactory2) },
|
|
{ ID_NAME(IID_IClassFactory3), TRUE },
|
|
{ ID_NAME(IID_IClientSecurity), TRUE },
|
|
{ ID_NAME(IID_ICommDlgBrowser) },
|
|
{ ID_NAME(IID_ICommDlgBrowser2) },
|
|
{ ID_NAME(IID_ICommDlgBrowser3) },
|
|
{ ID_NAME(IID_ICompositeFolder) },
|
|
{ ID_NAME(IID_IComputerInfoChangeNotify), },
|
|
{ ID_NAME(IID_IComThreadingInfo), TRUE },
|
|
{ ID_NAME(IID_IConnectionPoint) },
|
|
{ ID_NAME(IID_IConnectionPointContainer) },
|
|
{ ID_NAME(IID_IContext), TRUE },
|
|
{ ID_NAME(IID_IContextMenu), TRUE },
|
|
{ ID_NAME(IID_IContextMenu2), TRUE },
|
|
{ ID_NAME(IID_IContextMenu3), TRUE },
|
|
{ ID_NAME(IID_IContextMenuCB), TRUE },
|
|
{ ID_NAME(IID_IContextMenuSite) },
|
|
{ ID_NAME(IID_IContinue) },
|
|
{ ID_NAME(IID_IContinueCallback) },
|
|
{ ID_NAME(IID_ICopyHookA), TRUE },
|
|
{ ID_NAME(IID_ICopyHookW), TRUE },
|
|
{ ID_NAME(IID_ICurrentWorkingDirectory), TRUE },
|
|
{ ID_NAME(IID_ICustomizeInfoTip) },
|
|
{ ID_NAME(IID_IDVGetEnum), TRUE },
|
|
{ ID_NAME(IID_IDataObject) },
|
|
//{ ID_NAME(IID_IDefViewID) }, == DefViewFrame3
|
|
{ ID_NAME(IID_IDefViewFrame), TRUE },
|
|
{ ID_NAME(IID_IDefViewFrame3) },
|
|
{ ID_NAME(IID_IDefViewFrameGroup) },
|
|
{ ID_NAME(IID_IDefViewSafety), },
|
|
{ ID_NAME(IID_IDefViewScript), TRUE },
|
|
{ ID_NAME(IID_IDelayedRelease), TRUE },
|
|
{ ID_NAME(IID_IDeskBand) },
|
|
{ ID_NAME(IID_IDeskBandEx) },
|
|
{ ID_NAME(IID_IDeskBar), TRUE },
|
|
{ ID_NAME(IID_IDeskBarClient), TRUE },
|
|
{ ID_NAME(IID_IDeskMovr), TRUE },
|
|
{ ID_NAME(IID_IDiscMasterProgressEvents) },
|
|
{ ID_NAME(IID_IDispatch) },
|
|
{ ID_NAME(IID_IDispatchEx) },
|
|
{ ID_NAME(IID_IDockingWindow) },
|
|
{ ID_NAME(IID_IDockingWindowFrame), TRUE },
|
|
{ ID_NAME(IID_IDockingWindowSite), TRUE },
|
|
{ ID_NAME(IID_IDocViewSite), TRUE },
|
|
{ ID_NAME(IID_IDragSourceHelper), TRUE },
|
|
{ ID_NAME(IID_IDriveFolderExt), TRUE },
|
|
{ ID_NAME(IID_IDropSource) },
|
|
{ ID_NAME(IID_IDropTarget) },
|
|
{ ID_NAME(IID_IDropTargetHelper), TRUE },
|
|
{ ID_NAME(IID_IEFrameAuto) },
|
|
//{ ID_NAME(IID_IEnumCATID) }, == EnumGUID
|
|
//{ ID_NAME(IID_IEnumCLSID) }, == EnumGUID
|
|
{ ID_NAME(IID_IEnumCATEGORYINFO) },
|
|
{ ID_NAME(IID_IEnumConnectionPoints) },
|
|
{ ID_NAME(IID_IEnumConnections) },
|
|
{ ID_NAME(IID_IEnumExtraSearch) },
|
|
{ ID_NAME(IID_IEnumGUID) },
|
|
{ ID_NAME(IID_IEnumIDList) },
|
|
{ ID_NAME(IID_IEnumMoniker) },
|
|
//{ ID_NAME(IID_IEnumNetCfgBindingInterface) },
|
|
//{ ID_NAME(IID_IEnumNetCfgBindingPath) },
|
|
{ ID_NAME(IID_IEnumNetCfgComponent), TRUE },
|
|
{ ID_NAME(IID_IEnumNetConnection) },
|
|
{ ID_NAME(IID_IEnumShellItems) },
|
|
{ ID_NAME(IID_IEnumSTATSTG) },
|
|
{ ID_NAME(IID_IEnumString) },
|
|
{ ID_NAME(IID_IEnumUnknown) },
|
|
{ ID_NAME(IID_IEnumVARIANT) },
|
|
{ ID_NAME(IID_IErrorLog) },
|
|
{ ID_NAME(IID_IExplorerBrowser) },
|
|
{ ID_NAME(IID_IExplorerToolbar), TRUE },
|
|
{ ID_NAME(IID_IExtractIconA), TRUE },
|
|
{ ID_NAME(IID_IExtractIconW), TRUE },
|
|
{ ID_NAME(IID_IExtractImage) },
|
|
{ ID_NAME(IID_IExtractImage2) },
|
|
{ ID_NAME(IID_IFileDialog) },
|
|
{ ID_NAME(IID_IFileDialog2), TRUE },
|
|
{ ID_NAME(IID_IFileOpenDialog) },
|
|
{ ID_NAME(IID_IFileSaveDialog) },
|
|
{ ID_NAME(IID_IFileSearchBand) },
|
|
{ ID_NAME(IID_IFileViewerA), TRUE },
|
|
{ ID_NAME(IID_IFileViewerSite), TRUE },
|
|
{ ID_NAME(IID_IFileViewerW), TRUE },
|
|
{ ID_NAME(IID_IFilter) },
|
|
{ ID_NAME(IID_IFolderBandPriv) },
|
|
{ ID_NAME(IID_IFolderFilter) },
|
|
{ ID_NAME(IID_IFolderFilterSite) },
|
|
{ ID_NAME(IID_IFolderView) },
|
|
{ ID_NAME(IID_IFolderView2) },
|
|
{ ID_NAME(IID_IFolderViewHost), TRUE },
|
|
{ ID_NAME(IID_IFolderViewOC) },
|
|
{ ID_NAME(IID_IFolderViewSettings) },
|
|
{ ID_NAME(IID_IForegroundTransfer), TRUE },
|
|
{ ID_NAME(IID_IGetNameSpaceExtensionPointer),TRUE},
|
|
{ ID_NAME(IID_IGlobalFolderSettings), TRUE },
|
|
{ ID_NAME(IID_IHWEventHandler) },
|
|
{ ID_NAME(IID_IHWEventHandler2) },
|
|
{ ID_NAME(IID_IHlinkFrame) },
|
|
{ ID_NAME(IID_IImageList), TRUE },
|
|
{ ID_NAME(IID_IImageList2), TRUE },
|
|
{ ID_NAME(IID_IInitializeObject), TRUE },
|
|
{ ID_NAME(IID_IInitializeWithBindCtx) },
|
|
{ ID_NAME(IID_IInitializeWithFile) },
|
|
{ ID_NAME(IID_IInputObject) },
|
|
{ ID_NAME(IID_IInputObjectSite) },
|
|
{ ID_NAME(IID_IInternalUnknown), TRUE },
|
|
{ ID_NAME(IID_IInternetSecurityManager) },
|
|
{ ID_NAME(IID_IInternetZoneManager), TRUE },
|
|
{ ID_NAME(IID_IItemNameLimits) },
|
|
{ ID_NAME(IID_IMarshal) },
|
|
{ ID_NAME(IID_IMarshal2), TRUE },
|
|
{ ID_NAME(IID_IMenuBand), TRUE },
|
|
{ ID_NAME(IID_IMenuPopup), TRUE },
|
|
{ ID_NAME(IID_IModalWindow) },
|
|
{ ID_NAME(IID_IMoniker) },
|
|
{ ID_NAME(IID_IMultiMonitorDockingSite), TRUE },
|
|
{ ID_NAME(IID_IMultiQI), TRUE },
|
|
{ ID_NAME(IID_INameSpaceTreeControl), TRUE },
|
|
{ ID_NAME(IID_INamespaceProxy), TRUE },
|
|
{ ID_NAME(IID_INamespaceWalk) },
|
|
{ ID_NAME(IID_INamespaceWalkCB) },
|
|
{ ID_NAME(IID_INamespaceWalkCB2) },
|
|
{ ID_NAME(IID_INetCfg), TRUE },
|
|
//{ ID_NAME(IID_INetCfgBindingInterface) },
|
|
//{ ID_NAME(IID_INetCfgBindingPath) },
|
|
{ ID_NAME(IID_INetCfgComponent), TRUE },
|
|
{ ID_NAME(IID_INetCfgComponentBindings), TRUE },
|
|
{ ID_NAME(IID_INetCfgComponentControl), TRUE },
|
|
{ ID_NAME(IID_INetCfgComponentPropertyUi), TRUE },
|
|
{ ID_NAME(IID_INetCfgLock), TRUE },
|
|
{ ID_NAME(IID_INetCfgPnpReconfigCallback), TRUE },
|
|
{ ID_NAME(IID_INetConnectionConnectUi), TRUE },
|
|
{ ID_NAME(IID_INetConnectionPropertyUi), TRUE },
|
|
{ ID_NAME(IID_INetConnectionPropertyUi2), TRUE },
|
|
{ ID_NAME(IID_INetConnectionManager) },
|
|
{ ID_NAME(IID_INetLanConnectionUiInfo), TRUE },
|
|
{ ID_NAME(IID_INewMenuClient) },
|
|
{ ID_NAME(IID_INewShortcutHookA), TRUE },
|
|
{ ID_NAME(IID_INewShortcutHookW), TRUE },
|
|
{ ID_NAME(IID_INewWindowManager) },
|
|
{ ID_NAME(IID_INSCTree), TRUE },
|
|
{ ID_NAME(IID_INSCTree2), TRUE },
|
|
{ ID_NAME(IID_IObjMgr), TRUE },
|
|
{ ID_NAME(IID_IObjectSafety) },
|
|
{ ID_NAME(IID_IObjectWithBackReferences) },
|
|
{ ID_NAME(IID_IObjectWithSite) },
|
|
{ ID_NAME(IID_IOleClientSite) },
|
|
{ ID_NAME(IID_IOleCommandTarget) },
|
|
{ ID_NAME(IID_IOleContainer) },
|
|
{ ID_NAME(IID_IOleControl) },
|
|
{ ID_NAME(IID_IOleControlSite) },
|
|
{ ID_NAME(IID_IOleInPlaceActiveObject) },
|
|
{ ID_NAME(IID_IOleInPlaceFrame) },
|
|
{ ID_NAME(IID_IOleInPlaceObject) },
|
|
{ ID_NAME(IID_IOleInPlaceObjectWindowless), TRUE },
|
|
{ ID_NAME(IID_IOleInPlaceSite) },
|
|
{ ID_NAME(IID_IOleInPlaceSiteEx) },
|
|
{ ID_NAME(IID_IOleInPlaceSiteWindowless), TRUE },
|
|
{ ID_NAME(IID_IOleInPlaceUIWindow) },
|
|
{ ID_NAME(IID_IOleItemContainer), },
|
|
{ ID_NAME(IID_IOleLink), },
|
|
{ ID_NAME(IID_IOleObject) },
|
|
{ ID_NAME(IID_IOleWindow) },
|
|
{ ID_NAME(IID_IParentAndItem) },
|
|
{ ID_NAME(IID_IParseDisplayName), },
|
|
{ ID_NAME(IID_IPersist) },
|
|
{ ID_NAME(IID_IPersistFile) },
|
|
{ ID_NAME(IID_IPersistFolder) },
|
|
{ ID_NAME(IID_IPersistFolder2) },
|
|
{ ID_NAME(IID_IPersistFolder3) },
|
|
{ ID_NAME(IID_IPersistFreeThreadedObject), TRUE },
|
|
{ ID_NAME(IID_IPersistHistory) },
|
|
{ ID_NAME(IID_IPersistIDList) },
|
|
{ ID_NAME(IID_IPersistMemory) },
|
|
{ ID_NAME(IID_IPersistPropertyBag) },
|
|
{ ID_NAME(IID_IPersistPropertyBag2) },
|
|
{ ID_NAME(IID_IPersistStorage) },
|
|
{ ID_NAME(IID_IPersistStream) },
|
|
{ ID_NAME(IID_IPersistStreamInit) },
|
|
{ ID_NAME(IID_IPreviewHandler) },
|
|
{ ID_NAME(IID_IPreviewHandlerFrame) },
|
|
{ ID_NAME(IID_IPreviewHandlerVisuals) },
|
|
{ ID_NAME(IID_IProgressDialog), TRUE },
|
|
{ ID_NAME(IID_IPropertyBag) },
|
|
{ ID_NAME(IID_IPropertyBag2) },
|
|
{ ID_NAME(IID_IPropertySetStorage) },
|
|
{ ID_NAME(IID_IPropertyStore) },
|
|
{ ID_NAME(IID_IPropSheetPage), TRUE },
|
|
{ ID_NAME(IID_IProvideClassInfo) },
|
|
{ ID_NAME(IID_IProvideClassInfo2) },
|
|
{ ID_NAME(IID_IQueryAssociations), TRUE },
|
|
{ ID_NAME(IID_IQueryCancelAutoPlay) },
|
|
{ ID_NAME(IID_IQueryInfo), TRUE },
|
|
{ ID_NAME(IID_IQuickActivate) },
|
|
{ ID_NAME(IID_IRegTreeOptions), TRUE },
|
|
{ ID_NAME(IID_IRemoteComputer) },
|
|
{ ID_NAME(IID_IResolveShellLink) },
|
|
{ ID_NAME(IID_IROTData), },
|
|
{ ID_NAME(IID_IRpcOptions), TRUE },
|
|
{ ID_NAME(IID_IRunnableObject) },
|
|
{ ID_NAME(IID_IRunningObjectTable), },
|
|
{ ID_NAME(IID_ISLTracker), TRUE },
|
|
{ ID_NAME(IID_IScriptErrorList) },
|
|
{ ID_NAME(IID_ISearch) },
|
|
{ ID_NAME(IID_ISearchAssistantOC) },
|
|
{ ID_NAME(IID_ISearchAssistantOC2) },
|
|
{ ID_NAME(IID_ISearchAssistantOC3) },
|
|
{ ID_NAME(IID_ISearchBar) },
|
|
{ ID_NAME(IID_ISearches) },
|
|
{ ID_NAME(IID_ISecMgrCacheSeedTarget) },
|
|
{ ID_NAME(IID_IServerSecurity), TRUE },
|
|
{ ID_NAME(IID_IServiceProvider) },
|
|
{ ID_NAME(IID_IShellApp), TRUE },
|
|
{ ID_NAME(IID_IShellBrowser) },
|
|
{ ID_NAME(IID_IShellBrowserService), TRUE },
|
|
{ ID_NAME(IID_IShellChangeNotify), TRUE },
|
|
{ ID_NAME(IID_IShellCopyHookA), TRUE },
|
|
{ ID_NAME(IID_IShellCopyHookW), TRUE },
|
|
{ ID_NAME(IID_IShellDesktopTray), TRUE },
|
|
{ ID_NAME(IID_IShellDetails), TRUE },
|
|
{ ID_NAME(IID_IShellDispatch) },
|
|
{ ID_NAME(IID_IShellDispatch2) },
|
|
{ ID_NAME(IID_IShellDispatch3) },
|
|
{ ID_NAME(IID_IShellDispatch4) },
|
|
{ ID_NAME(IID_IShellDispatch5), TRUE },
|
|
{ ID_NAME(IID_IShellDispatch6), TRUE },
|
|
{ ID_NAME(IID_IShellExecuteHookA), TRUE },
|
|
{ ID_NAME(IID_IShellExecuteHookW), TRUE },
|
|
{ ID_NAME(IID_IShellExtInit), TRUE },
|
|
{ ID_NAME(IID_IShellFavoritesNameSpace) },
|
|
{ ID_NAME(IID_IShellFolder) },
|
|
{ ID_NAME(IID_IShellFolder2) },
|
|
{ ID_NAME(IID_IShellFolderBand), TRUE },
|
|
{ ID_NAME(IID_IShellFolderSearchable), TRUE },
|
|
{ ID_NAME(IID_IShellFolderSearchableCallback), TRUE },
|
|
{ ID_NAME(IID_IShellFolderView), TRUE },
|
|
{ ID_NAME(IID_IShellFolderViewCB), TRUE },
|
|
{ ID_NAME(IID_IShellFolderViewDual) },
|
|
{ ID_NAME(IID_IShellFolderViewDual2) },
|
|
{ ID_NAME(IID_IShellFolderViewDual3), TRUE },
|
|
{ ID_NAME(IID_IShellFolderViewType), TRUE },
|
|
{ ID_NAME(IID_IShellIcon) },
|
|
{ ID_NAME(IID_IShellIconOverlay), TRUE },
|
|
{ ID_NAME(IID_IShellIconOverlayIdentifier), TRUE },
|
|
{ ID_NAME(IID_IShellImageData), TRUE },
|
|
{ ID_NAME(IID_IShellImageDataAbort), TRUE },
|
|
{ ID_NAME(IID_IShellImageDataFactory), TRUE },
|
|
{ ID_NAME(IID_IShellItem) },
|
|
{ ID_NAME(IID_IShellItem2) },
|
|
{ ID_NAME(IID_IShellItemArray) },
|
|
{ ID_NAME(IID_IShellItemFilter) },
|
|
{ ID_NAME(IID_IShellLinkA) },
|
|
{ ID_NAME(IID_IShellLinkDataList), TRUE },
|
|
{ ID_NAME(IID_IShellLinkDual) },
|
|
{ ID_NAME(IID_IShellLinkDual2) },
|
|
{ ID_NAME(IID_IShellLinkW) },
|
|
{ ID_NAME(IID_IShellMenu), TRUE },
|
|
{ ID_NAME(IID_IShellMenu2), TRUE },
|
|
{ ID_NAME(IID_IShellMenuAcc), TRUE },
|
|
{ ID_NAME(IID_IShellMenuCallback), TRUE },
|
|
{ ID_NAME(IID_IShellNameSpace) },
|
|
{ ID_NAME(IID_IShellPropSheetExt), TRUE },
|
|
{ ID_NAME(IID_IShellService), TRUE },
|
|
{ ID_NAME(IID_IShellTaskScheduler), TRUE },
|
|
{ ID_NAME(IID_IShellUIHelper) },
|
|
{ ID_NAME(IID_IShellUIHelper2), TRUE },
|
|
{ ID_NAME(IID_IShellView) },
|
|
{ ID_NAME(IID_IShellView2) },
|
|
{ ID_NAME(IID_IShellView3) },
|
|
{ ID_NAME(IID_IShellWindows) },
|
|
{ ID_NAME(IID_ISpecifyPropertyPages) },
|
|
{ ID_NAME(IID_IStorage) },
|
|
{ ID_NAME(IID_IStream) },
|
|
{ ID_NAME(IID_ISurrogate) },
|
|
{ ID_NAME(IID_ISynchronize) },
|
|
{ ID_NAME(IID_ISynchronizeContainer), TRUE },
|
|
{ ID_NAME(IID_ISynchronizeEvent), TRUE },
|
|
{ ID_NAME(IID_ISynchronizeHandle), TRUE },
|
|
{ ID_NAME(IID_ITargetEmbedding) },
|
|
{ ID_NAME(IID_ITargetFrame) },
|
|
{ ID_NAME(IID_ITargetFrame2) },
|
|
{ ID_NAME(IID_ITargetFramePriv) },
|
|
{ ID_NAME(IID_ITargetFramePriv2) },
|
|
{ ID_NAME(IID_ITargetNotify) },
|
|
{ ID_NAME(IID_ITaskbarList) },
|
|
{ ID_NAME(IID_ITaskbarList2) },
|
|
{ ID_NAME(IID_ITaskbarList3), TRUE },
|
|
{ ID_NAME(IID_ITaskbarList4), TRUE },
|
|
{ ID_NAME(IID_ITrackShellMenu), TRUE },
|
|
/* This interface is completely different between PSDK and registry/shell32 */
|
|
{ ID_NAME(IID_ITransferAdviseSink), TRUE },
|
|
#define IID_ITransferAdviseSink IID_ITransferAdviseSinkPriv
|
|
{ ID_NAME(IID_ITransferAdviseSink) },
|
|
#undef IID_ITransferAdviseSink
|
|
{ ID_NAME(IID_ITransferDestination), TRUE },
|
|
{ ID_NAME(IID_ITransferSource), TRUE },
|
|
{ ID_NAME(IID_ITranslateShellChangeNotify), TRUE },
|
|
{ ID_NAME(IID_ITrayPriv), TRUE },
|
|
{ ID_NAME(IID_ITrayPriv2), TRUE },
|
|
{ ID_NAME(IID_IUnknown) },
|
|
{ ID_NAME(IID_IURLSearchHook), TRUE },
|
|
{ ID_NAME(IID_IURLSearchHook2), TRUE },
|
|
{ ID_NAME(IID_IUrlHistoryNotify) },
|
|
{ ID_NAME(IID_IUrlHistoryStg) },
|
|
{ ID_NAME(IID_IUrlHistoryStg2) },
|
|
{ ID_NAME(IID_IViewObject) },
|
|
{ ID_NAME(IID_IViewObject2) },
|
|
{ ID_NAME(IID_IViewObjectEx), TRUE },
|
|
{ ID_NAME(IID_IVisualProperties) },
|
|
{ ID_NAME(IID_IWebBrowser) },
|
|
{ ID_NAME(IID_IWebBrowser2) },
|
|
{ ID_NAME(IID_IWebBrowserApp) },
|
|
{ ID_NAME(IID_IWebBrowserPriv) },
|
|
{ ID_NAME(IID_IWebBrowserPriv2) },
|
|
{ ID_NAME(IID_IWinEventHandler), TRUE },
|
|
|
|
{ ID_NAME(IID_DFConstraint), TRUE },
|
|
{ ID_NAME(DIID__SearchAssistantEvents) },
|
|
{ ID_NAME(DIID_DShellFolderViewEvents) },
|
|
{ ID_NAME(DIID_DShellNameSpaceEvents) },
|
|
{ ID_NAME(DIID_DShellWindowsEvents) },
|
|
{ ID_NAME(DIID_DWebBrowserEvents) },
|
|
{ ID_NAME(DIID_DWebBrowserEvents2) },
|
|
{ ID_NAME(DIID_XMLDOMDocumentEvents ) },
|
|
|
|
{ ID_NAME(IID_CDefView), TRUE },
|
|
{ ID_NAME(IID_Folder) },
|
|
{ ID_NAME(IID_Folder2) },
|
|
{ ID_NAME(IID_Folder3) },
|
|
{ ID_NAME(IID_FolderItem) },
|
|
{ ID_NAME(IID_FolderItem2) },
|
|
{ ID_NAME(IID_FolderItems) },
|
|
{ ID_NAME(IID_FolderItems2) },
|
|
{ ID_NAME(IID_FolderItems3) },
|
|
{ ID_NAME(IID_FolderItemVerb) },
|
|
{ ID_NAME(IID_FolderItemVerbs) },
|
|
|
|
{ ID_NAME(CLSID_ShellDesktop), TRUE },
|
|
|
|
{ ID_NAME(IID_IQueryContinue) },
|
|
{ ID_NAME(IID_IUserNotification) },
|
|
{ ID_NAME(IID_IUserNotificationCallback) }, // On Vista+
|
|
{ ID_NAME(IID_IUserNotification2) }, // On Vista+
|
|
|
|
{ ID_NAME(IID_IAggregateFilterCondition) },
|
|
{ ID_NAME(IID_IAliasRegistrationCallback), TRUE },
|
|
{ ID_NAME(IID_IAssociationArrayInitialize), TRUE },
|
|
{ ID_NAME(IID_IAssociationList), TRUE },
|
|
{ ID_NAME(IID_IBackReferencedObject), TRUE },
|
|
{ ID_NAME(IID_IBasePropPage), TRUE },
|
|
{ ID_NAME(IID_ICommonLayoutDefinition), TRUE },
|
|
{ ID_NAME(IID_IControlPanelEnumerator), TRUE },
|
|
{ ID_NAME(IID_IDelegateHostItemContainer), TRUE },
|
|
{ ID_NAME(IID_IDrawPropertyControl), TRUE },
|
|
{ ID_NAME(IID_IEnumAssociationElements), TRUE },
|
|
{ ID_NAME(IID_IEnumerateAssociationElements),TRUE },
|
|
{ ID_NAME(IID_IExecuteCommand), TRUE },
|
|
{ ID_NAME(IID_IFilterCondition) },
|
|
{ ID_NAME(IID_IFolderNotify), TRUE },
|
|
{ ID_NAME(IID_IFolderProperties), TRUE },
|
|
{ ID_NAME(IID_IFolderType), TRUE },
|
|
{ ID_NAME(IID_IFolderWithSearchRoot), TRUE },
|
|
{ ID_NAME(IID_IFrameLayoutDefinition), TRUE },
|
|
{ ID_NAME(IID_IItemFilter), TRUE },
|
|
{ ID_NAME(IID_IItemFilterOwner), TRUE },
|
|
{ ID_NAME(IID_ILocalizableItemParent), TRUE },
|
|
{ ID_NAME(IID_INewItemAdvisor), TRUE },
|
|
{ ID_NAME(IID_IObjectWithAssociationElement),TRUE },
|
|
{ ID_NAME(IID_IObjectWithAssociationList), TRUE },
|
|
{ ID_NAME(IID_IObjectWithQuerySource), TRUE },
|
|
{ ID_NAME(IID_IObjectWithSelection), TRUE },
|
|
{ ID_NAME(IID_IPersistString2), TRUE },
|
|
{ ID_NAME(IID_IPrinterFolder), TRUE },
|
|
{ ID_NAME(IID_IPropertyControl), TRUE },
|
|
{ ID_NAME(IID_IPropertyControlBase), TRUE },
|
|
{ ID_NAME(IID_IPropertyControlSite), TRUE },
|
|
{ ID_NAME(IID_IRegItemCustomAttributes), TRUE },
|
|
{ ID_NAME(IID_IRegItemCustomEnumerator), TRUE },
|
|
{ ID_NAME(IID_IRegItemFolder), TRUE },
|
|
{ ID_NAME(IID_IRootAndRelativeParsingFolder),TRUE },
|
|
{ ID_NAME(IID_IScope), TRUE },
|
|
{ ID_NAME(IID_IScopeItem), TRUE },
|
|
{ ID_NAME(IID_IShellBrowserServce), TRUE },
|
|
{ ID_NAME(IID_IShellFolder3), TRUE },
|
|
{ ID_NAME(IID_ITaskCondition), TRUE },
|
|
{ ID_NAME(IID_ITaskConditionCombiner), TRUE },
|
|
{ ID_NAME(IID_ITaskConditionInit), TRUE },
|
|
{ ID_NAME(IID_ITransferProvider), TRUE },
|
|
{ ID_NAME(IID_IUserEventTimer) },
|
|
{ ID_NAME(IID_IUserEventTimerCallback) },
|
|
{ ID_NAME(IID_IAssociationArrayOld), TRUE },
|
|
{ ID_NAME(IID_IAssociationArray), TRUE },
|
|
#define IID_IDriveFolderExt IID_IDriveFolderExtOld
|
|
{ ID_NAME(IID_IDriveFolderExt) },
|
|
#undef IID_IDriveFolderExt
|
|
{ ID_NAME(IID_IPinnedListOld), TRUE },
|
|
{ ID_NAME(IID_IPinnedList), TRUE },
|
|
{ ID_NAME(IID_IAttachmentExecute), TRUE },
|
|
};
|
|
static const INT KnownInterfaceCount = RTL_NUMBER_OF(KnownInterfaces);
|
|
|
|
static
|
|
PCKNOWN_INTERFACE
|
|
FindInterface(
|
|
_In_ const IID *iid)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < KnownInterfaceCount; i++)
|
|
if (IsEqualIID(KnownInterfaces[i].iid, iid))
|
|
return &KnownInterfaces[i];
|
|
ASSERT(i != KnownInterfaceCount);
|
|
return NULL;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
IsInterfaceExpected(
|
|
_In_ PCCLASS_AND_INTERFACES class,
|
|
_In_ const IID *iid)
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; class->ifaces[i].iid; i++)
|
|
if (IsEqualIID(class->ifaces[i].iid, iid))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
#define INTF_NOT_EXPOSED LONG_MAX
|
|
static
|
|
LONG
|
|
GetInterfaceOffset(
|
|
_In_ PUNKNOWN pUnk,
|
|
_In_ const IID *iid)
|
|
{
|
|
HRESULT hr;
|
|
PVOID pObj;
|
|
PUNKNOWN pUnk2;
|
|
LONG offset;
|
|
|
|
hr = IUnknown_QueryInterface(pUnk, iid, &pObj);
|
|
ok(hr == S_OK || hr == E_NOINTERFACE, "IUnknown::QueryInterface returned 0x%lx\n", hr);
|
|
if (FAILED(hr))
|
|
return INTF_NOT_EXPOSED;
|
|
|
|
pUnk2 = pObj;
|
|
offset = (LONG_PTR)pObj - (LONG_PTR)pUnk;
|
|
IUnknown_Release(pUnk2);
|
|
return offset;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
TestModuleInterfaces(
|
|
_In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
|
|
_In_ INT ExpectedInterfaceCount)
|
|
{
|
|
HRESULT hr;
|
|
PVOID pObj;
|
|
PUNKNOWN pUnk;
|
|
INT iClass, iIntf;
|
|
PCCLASS_AND_INTERFACES class;
|
|
|
|
for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
|
|
{
|
|
class = &ExpectedInterfaces[iClass];
|
|
hr = CoCreateInstance(class->clsid,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IUnknown,
|
|
&pObj);
|
|
ok(hr == S_OK, "CoCreateInstance failed. hr=0x%lx\n", hr);
|
|
if (FAILED(hr))
|
|
{
|
|
skip("Failed to instantiate %s.\n", class->name);
|
|
continue;
|
|
}
|
|
|
|
pUnk = pObj;
|
|
|
|
/* Check that all expected interfaces are present and have the right offset */
|
|
for (iIntf = 0; class->ifaces[iIntf].iid; iIntf++)
|
|
{
|
|
PCKNOWN_INTERFACE iface = FindInterface(class->ifaces[iIntf].iid);
|
|
LONG offset = GetInterfaceOffset(pUnk, iface->iid);
|
|
if (offset == INTF_NOT_EXPOSED)
|
|
ok(0, "%s is missing %s (offset %ld)\n", class->name, iface->name, class->ifaces[iIntf].offset);
|
|
else if (class->ifaces[iIntf].offset != FARAWY)
|
|
{
|
|
#ifdef FAIL_WRONG_OFFSET
|
|
ok(offset == class->ifaces[iIntf].offset, "%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
|
|
#else
|
|
if (offset != class->ifaces[iIntf].offset)
|
|
mytrace("%s, %s offset is %ld, expected %ld\n", class->name, iface->name, offset, class->ifaces[iIntf].offset);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Check that none other than the expected interfaces are present */
|
|
for (iIntf = 0; iIntf < KnownInterfaceCount; iIntf++)
|
|
{
|
|
PCKNOWN_INTERFACE iface = &KnownInterfaces[iIntf];
|
|
LONG offset;
|
|
if (IsInterfaceExpected(class, iface->iid))
|
|
continue;
|
|
offset = GetInterfaceOffset(pUnk, iface->iid);
|
|
#ifdef GENERATE_TABLE_ENTRIES
|
|
ok(offset == INTF_NOT_EXPOSED, "%s: { %s0x%lx, &%s },\n", class->name, offset < 0 ? "-" : "", offset < 0 ? -offset : offset, iface->name);
|
|
#else
|
|
ok(offset == INTF_NOT_EXPOSED, "%s exposes %s (offset %ld), but shouldn't\n", class->name, iface->name, offset);
|
|
#endif
|
|
}
|
|
|
|
// TODO: do some aggregation
|
|
|
|
IUnknown_Release(pUnk);
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
TestModuleRegistry(
|
|
_In_ PCWSTR ModuleName,
|
|
_In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
|
|
_In_ INT ExpectedInterfaceCount)
|
|
{
|
|
INT iClass;
|
|
PCCLASS_AND_INTERFACES class;
|
|
HKEY hKeyClasses;
|
|
LONG result;
|
|
|
|
result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyClasses);
|
|
ok(result == NO_ERROR, "Failed to open classes key, error %lu\n", result);
|
|
if (!myskip(result == NO_ERROR, "No classes key\n"))
|
|
{
|
|
for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
|
|
{
|
|
HKEY hKey;
|
|
HKEY hKeyServer;
|
|
NTSTATUS status;
|
|
UNICODE_STRING clsid;
|
|
DWORD type;
|
|
WCHAR data[100];
|
|
DWORD dataSize;
|
|
PCWSTR expectedThreadingModel;
|
|
|
|
class = &ExpectedInterfaces[iClass];
|
|
status = RtlStringFromGUID(class->clsid, &clsid);
|
|
ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", class->name, status);
|
|
if (myskip(NT_SUCCESS(status), "No guid string\n"))
|
|
continue;
|
|
|
|
result = RegOpenKeyExW(hKeyClasses, clsid.Buffer, 0, KEY_ENUMERATE_SUB_KEYS, &hKey);
|
|
ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
|
|
RtlFreeUnicodeString(&clsid);
|
|
if (myskip(result == NO_ERROR, "No key\n"))
|
|
continue;
|
|
|
|
result = RegOpenKeyExW(hKey, L"InProcServer32", 0, KEY_QUERY_VALUE, &hKeyServer);
|
|
ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", class->name, result);
|
|
RegCloseKey(hKey);
|
|
if (myskip(result == NO_ERROR, "No key\n"))
|
|
continue;
|
|
|
|
dataSize = sizeof(data);
|
|
result = RegQueryValueExW(hKeyServer, NULL, NULL, &type, (PBYTE)data, &dataSize);
|
|
ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
|
|
if (!myskip(result == NO_ERROR, "No module name\n"))
|
|
{
|
|
ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
|
|
ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
|
|
ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
|
|
ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
|
|
// TODO: Use SearchPath (or assume everything's in system32) and do a proper full path compare
|
|
PathStripPathW(data);
|
|
PathRemoveExtensionW(data);
|
|
ok(!wcsicmp(data, ModuleName), "Server is %ls, expected %ls for %s\n", data, ModuleName, class->name);
|
|
}
|
|
|
|
dataSize = sizeof(data);
|
|
result = RegQueryValueExW(hKeyServer, L"ThreadingModel", NULL, &type, (PBYTE)data, &dataSize);
|
|
ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", class->name, result);
|
|
if (!myskip(result == NO_ERROR, "No ThreadingModel\n"))
|
|
{
|
|
ok(type == REG_SZ || type == REG_EXPAND_SZ, "type %lu for %s\n", type, class->name);
|
|
ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, class->name);
|
|
ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, class->name);
|
|
ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
|
|
expectedThreadingModel = class->ThreadingModel;
|
|
if (!expectedThreadingModel)
|
|
expectedThreadingModel = L"Apartment";
|
|
ok(!wcsicmp(data, expectedThreadingModel), "Server is %ls, expected %ls for %s\n", data, expectedThreadingModel, class->name);
|
|
}
|
|
|
|
RegCloseKey(hKeyServer);
|
|
}
|
|
RegCloseKey(hKeyClasses);
|
|
}
|
|
}
|
|
|
|
static
|
|
VOID
|
|
TestManualInstantiation(
|
|
_In_ PCWSTR ModuleName,
|
|
_In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
|
|
_In_ INT ExpectedInterfaceCount)
|
|
{
|
|
INT iClass;
|
|
PCCLASS_AND_INTERFACES class;
|
|
HRESULT (__stdcall *DllGetClassObject)(REFCLSID, REFIID, PVOID *);
|
|
|
|
DllGetClassObject = (PVOID)GetProcAddress(GetModuleHandleW(ModuleName), "DllGetClassObject");
|
|
ok(DllGetClassObject != NULL, "DllGetClassObject not found in %ls, error %lu\n", ModuleName, GetLastError());
|
|
if (myskip(DllGetClassObject != NULL, "No DllGetClassObject\n"))
|
|
return;
|
|
|
|
for (iClass = 0; iClass < ExpectedInterfaceCount; iClass++)
|
|
{
|
|
PVOID pv;
|
|
HRESULT hr;
|
|
class = &ExpectedInterfaces[iClass];
|
|
hr = DllGetClassObject(class->clsid, &IID_IClassFactory, &pv);
|
|
ok(hr == S_OK, "DllGetClassObject failed for %s, hr = 0x%lx\n", class->name, hr);
|
|
if (!myskip(SUCCEEDED(hr), "No class factory\n"))
|
|
{
|
|
IClassFactory *pCF = pv;
|
|
hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IUnknown, &pv);
|
|
ok(hr == S_OK, "IClassFactory::CreateInstance failed for %s, hr = 0x%lx\n", class->name, hr);
|
|
if (!myskip(SUCCEEDED(hr), "No instance\n"))
|
|
{
|
|
IUnknown *pUnk = pv;
|
|
IUnknown_Release(pUnk);
|
|
}
|
|
IClassFactory_Release(pCF);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
TestClasses(
|
|
_In_ PCWSTR ModuleName,
|
|
_In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
|
|
_In_ INT ExpectedInterfaceCount)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
ok(hr == S_OK, "CoInitializeEx failed. hr=0x%lx\n", hr);
|
|
if (myskip(SUCCEEDED(hr), "Failed to initialize COM. Cannot perform tests\n"))
|
|
return;
|
|
|
|
TestModuleInterfaces(ExpectedInterfaces, ExpectedInterfaceCount);
|
|
TestModuleRegistry(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
|
|
TestManualInstantiation(ModuleName, ExpectedInterfaces, ExpectedInterfaceCount);
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
static
|
|
VOID
|
|
TestInterfaceRegistry(
|
|
_In_ PCKNOWN_INTERFACE Interfaces,
|
|
_In_ INT InterfaceCount)
|
|
{
|
|
INT i;
|
|
HKEY hKeyInterface;
|
|
LONG result;
|
|
|
|
result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Classes\\Interface", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyInterface);
|
|
ok(result == NO_ERROR, "Failed to open interface key, error %lu\n", result);
|
|
if (!myskip(result == NO_ERROR, "No interface key\n"))
|
|
{
|
|
for (i = 0; i < InterfaceCount; i++)
|
|
{
|
|
HKEY hKey;
|
|
NTSTATUS status;
|
|
UNICODE_STRING iid;
|
|
DWORD type;
|
|
WCHAR data[100];
|
|
DWORD dataSize;
|
|
PCKNOWN_INTERFACE iface;
|
|
PCWSTR expectedName;
|
|
|
|
iface = &Interfaces[i];
|
|
status = RtlStringFromGUID(iface->iid, &iid);
|
|
ok(status == STATUS_SUCCESS, "Failed to convert guid to string for %s, status %lx\n", iface->name, status);
|
|
if (myskip(NT_SUCCESS(status), "No guid string\n"))
|
|
continue;
|
|
|
|
result = RegOpenKeyExW(hKeyInterface, iid.Buffer, 0, KEY_QUERY_VALUE, &hKey);
|
|
if (iface->noreg)
|
|
{
|
|
ok(result == ERROR_FILE_NOT_FOUND, "RegOpenKeyEx returned %lu for %s\n", result, iface->name);
|
|
}
|
|
else
|
|
{
|
|
ok(result == NO_ERROR, "Failed to open key for %s, error %lu\n", iface->name, result);
|
|
(void)myskip(result == NO_ERROR, "No key\n");
|
|
}
|
|
RtlFreeUnicodeString(&iid);
|
|
if (result != NO_ERROR)
|
|
continue;
|
|
|
|
dataSize = sizeof(data);
|
|
result = RegQueryValueExW(hKey, NULL, NULL, &type, (PBYTE)data, &dataSize);
|
|
ok(result == NO_ERROR, "Failed to query value for %s, error %lu\n", iface->name, result);
|
|
if (!myskip(result == NO_ERROR, "No module name\n"))
|
|
{
|
|
ok(type == REG_SZ, "type %lu for %s\n", type, iface->name);
|
|
ok(dataSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dataSize, iface->name);
|
|
ok(dataSize <= sizeof(data), "size %lu for %s\n", dataSize, iface->name);
|
|
ok(data[dataSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", iface->name);
|
|
expectedName = wcschr(iface->wname, L'_');
|
|
if (expectedName)
|
|
expectedName++;
|
|
else
|
|
expectedName = iface->wname;
|
|
ok(!wcsicmp(data, expectedName), "Name is %ls, expected %ls\n", data, expectedName);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
RegCloseKey(hKeyInterface);
|
|
}
|
|
}
|
|
|
|
START_TEST(interfaces)
|
|
{
|
|
TestInterfaceRegistry(KnownInterfaces, KnownInterfaceCount);
|
|
}
|