[COM_APITEST]
authorThomas Faber <thomas.faber@reactos.org>
Sun, 7 Jul 2013 09:10:31 +0000 (09:10 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sun, 7 Jul 2013 09:10:31 +0000 (09:10 +0000)
- Add a test verifying the interfaces exposed by various COM classes, grouped by server dll
ROSTESTS-98

svn path=/trunk/; revision=59442

rostests/apitests/CMakeLists.txt
rostests/apitests/com/CMakeLists.txt [new file with mode: 0644]
rostests/apitests/com/browseui.c [new file with mode: 0644]
rostests/apitests/com/com_apitest.c [new file with mode: 0644]
rostests/apitests/com/com_apitest.h [new file with mode: 0644]
rostests/apitests/com/ieframe.c [new file with mode: 0644]
rostests/apitests/com/shdocvw.c [new file with mode: 0644]
rostests/apitests/com/shell32.c [new file with mode: 0644]
rostests/apitests/com/testlist.c [new file with mode: 0644]

index 1c0a6d8..a28fa47 100644 (file)
@@ -3,6 +3,7 @@ add_library(apitest apitest.c)
 
 add_subdirectory(advapi32)
 add_subdirectory(browseui)
+add_subdirectory(com)
 add_subdirectory(crt)
 add_subdirectory(dciman32)
 add_subdirectory(gdi32)
diff --git a/rostests/apitests/com/CMakeLists.txt b/rostests/apitests/com/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1c9c212
--- /dev/null
@@ -0,0 +1,17 @@
+
+add_definitions(-DWINE_NO_UNICODE_MACROS)
+
+list(APPEND SOURCE
+    browseui.c
+    ieframe.c
+    shdocvw.c
+    shell32.c
+    com_apitest.c
+    testlist.c)
+
+add_executable(com_apitest ${SOURCE})
+target_link_libraries(com_apitest wine uuid)
+set_module_type(com_apitest win32cui)
+add_importlibs(com_apitest advapi32 ole32 shlwapi shell32 msvcrt kernel32 ntdll)
+
+add_cd_file(TARGET com_apitest DESTINATION reactos/bin FOR all)
diff --git a/rostests/apitests/com/browseui.c b/rostests/apitests/com/browseui.c
new file mode 100644 (file)
index 0000000..5bff33e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test for browseui classes
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include "com_apitest.h"
+
+#define NDEBUG
+#include <debug.h>
+
+static const CLASS_AND_INTERFACES ExpectedInterfaces[] =
+{
+    {
+        ID_NAME(CLSID_RebarBandSite),
+        {
+            {    0x0,       &IID_IUnknown },
+            {    0xc,   &IID_IBandSite },
+            {   0x10,   &IID_IInputObjectSite },
+            {   0x14,   &IID_IInputObject },
+            {   0x18,   &IID_IDeskBarClient },
+            {   0x18,       &IID_IOleWindow },
+            {   0x1c,   &IID_IWinEventHandler },
+            {   0x20,   &IID_IPersistStream },
+            {   0x20,       &IID_IPersist },
+            {   0x24,   &IID_IDropTarget },
+            {   0x28,   &IID_IServiceProvider },
+            {   0x2c,   &IID_IBandSiteHelper },
+            {   0x30,   &IID_IOleCommandTarget },
+        }
+    },
+    {
+        ID_NAME(CLSID_SH_AddressBand),
+        {
+            {    0x0,   &IID_IDeskBand },
+            {    0x0,       &IID_IDockingWindow },
+            {    0x0,           &IID_IOleWindow },
+            {    0x0,               &IID_IUnknown },
+            {    0x4,   &IID_IObjectWithSite },
+            {    0xc,   &IID_IInputObject },
+            {   0x10,   &IID_IPersistStream },
+            {   0x10,       &IID_IPersist },
+            {   0x14,   &IID_IOleCommandTarget },
+            {   0x18,   &IID_IServiceProvider },
+            {   0x30,   &IID_IWinEventHandler },
+            {   0x34,   &IID_IAddressBand },
+            {   0x38,   &IID_IInputObjectSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellSearchExt),
+        {
+            {    0x0,   &IID_IContextMenu },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IObjectWithSite },
+        }
+    },
+};
+static const INT ExpectedInterfaceCount = RTL_NUMBER_OF(ExpectedInterfaces);
+
+START_TEST(browseui)
+{
+    TestClasses(L"browseui", ExpectedInterfaces, ExpectedInterfaceCount);
+}
diff --git a/rostests/apitests/com/com_apitest.c b/rostests/apitests/com/com_apitest.c
new file mode 100644 (file)
index 0000000..3609c4b
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include "com_apitest.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;
+} KNOWN_INTERFACE;
+typedef const KNOWN_INTERFACE *PCKNOWN_INTERFACE;
+
+#undef ID_NAME
+#define ID_NAME(c) { &c, #c }
+static KNOWN_INTERFACE KnownInterfaces[] =
+{
+    ID_NAME(IID_IACList),
+    ID_NAME(IID_IACList2),
+    ID_NAME(IID_IAccessible),
+    ID_NAME(IID_IAddressBand),
+    ID_NAME(IID_IAddressEditBox),
+    ID_NAME(IID_IBandNavigate),
+    ID_NAME(IID_IBandProxy),
+    ID_NAME(IID_IBandSite),
+    ID_NAME(IID_IBandSiteHelper),
+    ID_NAME(IID_IBanneredBar),
+    ID_NAME(IID_IBindCtx),
+    ID_NAME(IID_IBrowserService),
+    ID_NAME(IID_IBrowserService2),
+    ID_NAME(IID_IClassFactory),
+    ID_NAME(IID_IClassFactory2),
+    ID_NAME(IID_IClassFactory3),
+    ID_NAME(IID_IClientSecurity),
+    ID_NAME(IID_IComThreadingInfo),
+    ID_NAME(IID_IContextMenu),
+    ID_NAME(IID_IContextMenu2),
+    ID_NAME(IID_IContextMenu3),
+    ID_NAME(IID_IContextMenuCB),
+    ID_NAME(IID_IContextMenuSite),
+    ID_NAME(IID_IContinue),
+    ID_NAME(IID_IDataObject),
+    ID_NAME(IID_IDefViewFrame),
+    ID_NAME(IID_IDeskBand),
+    ID_NAME(IID_IDeskBar),
+    ID_NAME(IID_IDeskBarClient),
+    ID_NAME(IID_IDispatch),
+    ID_NAME(IID_IDockingWindow),
+    ID_NAME(IID_IDockingWindowFrame),
+    ID_NAME(IID_IDockingWindowSite),
+    ID_NAME(IID_IDocViewSite),
+    ID_NAME(IID_IDragSourceHelper),
+    ID_NAME(IID_IDropSource),
+    ID_NAME(IID_IDropTarget),
+    ID_NAME(IID_IDropTargetHelper),
+    ID_NAME(IID_IEnumExtraSearch),
+    ID_NAME(IID_IEnumGUID),
+    ID_NAME(IID_IEnumIDList),
+    ID_NAME(IID_IEnumShellItems),
+    ID_NAME(IID_IEnumString),
+    ID_NAME(IID_IEnumUnknown),
+    ID_NAME(IID_IErrorLog),
+    ID_NAME(IID_IExplorerToolbar),
+    ID_NAME(IID_IExtractIconA),
+    ID_NAME(IID_IExtractIconW),
+    ID_NAME(IID_IExtractImage),
+    ID_NAME(IID_IExtractImage2),
+    ID_NAME(IID_IFileDialog),
+    ID_NAME(IID_IFileDialog2),
+    ID_NAME(IID_IFileSearchBand),
+    ID_NAME(IID_IFolderBandPriv),
+    ID_NAME(IID_IFolderView),
+    ID_NAME(IID_IFolderView2),
+    ID_NAME(IID_IFolderViewOC),
+    ID_NAME(IID_IFolderViewSettings),
+    ID_NAME(IID_IGlobalFolderSettings),
+    ID_NAME(IID_IInitializeObject),
+    ID_NAME(IID_IInputObject),
+    ID_NAME(IID_IInputObjectSite),
+    ID_NAME(IID_IInternalUnknown),
+    ID_NAME(IID_IMarshal),
+    ID_NAME(IID_IMenuBand),
+    ID_NAME(IID_IMenuPopup),
+    ID_NAME(IID_IMoniker),
+    ID_NAME(IID_IMultiQI),
+    ID_NAME(IID_INamespaceProxy),
+    ID_NAME(IID_INameSpaceTreeControl),
+    ID_NAME(IID_INSCTree),
+    ID_NAME(IID_INSCTree2),
+    ID_NAME(IID_IObjMgr),
+    ID_NAME(IID_IObjectSafety),
+    ID_NAME(IID_IObjectWithSite),
+    ID_NAME(IID_IOleCommandTarget),
+    ID_NAME(IID_IOleInPlaceActiveObject),
+    ID_NAME(IID_IOleInPlaceFrame),
+    ID_NAME(IID_IOleInPlaceObject),
+    ID_NAME(IID_IOleInPlaceObjectWindowless),
+    ID_NAME(IID_IOleInPlaceSite),
+    ID_NAME(IID_IOleInPlaceSiteEx),
+    ID_NAME(IID_IOleInPlaceSiteWindowless),
+    ID_NAME(IID_IOleInPlaceUIWindow),
+    ID_NAME(IID_IOleObject),
+    ID_NAME(IID_IOleWindow),
+    ID_NAME(IID_IPersist),
+    ID_NAME(IID_IPersistFile),
+    ID_NAME(IID_IPersistFolder),
+    ID_NAME(IID_IPersistFolder2),
+    ID_NAME(IID_IPersistFolder3),
+    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_IProgressDialog),
+    ID_NAME(IID_IPropertyBag),
+    ID_NAME(IID_IPropertyBag2),
+    ID_NAME(IID_IQueryAssociations),
+    ID_NAME(IID_IQueryInfo),
+    ID_NAME(IID_IRegTreeOptions),
+    ID_NAME(IID_IRunnableObject),
+    ID_NAME(IID_IServerSecurity),
+    ID_NAME(IID_IServiceProvider),
+    ID_NAME(IID_IShellBrowser),
+    ID_NAME(IID_IShellBrowserService),
+    ID_NAME(IID_IShellChangeNotify),
+    ID_NAME(IID_IShellDesktopTray),
+    ID_NAME(IID_IShellDispatch),
+    ID_NAME(IID_IShellDispatch2),
+    ID_NAME(IID_IShellDispatch3),
+    ID_NAME(IID_IShellDispatch4),
+    ID_NAME(IID_IShellDispatch5),
+    ID_NAME(IID_IShellIconOverlayIdentifier),
+    ID_NAME(IID_IShellFolder),
+    ID_NAME(IID_IShellFolder2),
+    ID_NAME(IID_IShellFolderBand),
+    ID_NAME(IID_IShellFolderView),
+    ID_NAME(IID_IShellFolderViewCB),
+    ID_NAME(IID_IShellFolderViewDual),
+    ID_NAME(IID_IShellFolderViewDual2),
+    ID_NAME(IID_IShellIcon),
+    ID_NAME(IID_IShellItem),
+    ID_NAME(IID_IShellItem2),
+    ID_NAME(IID_IShellItemArray),
+    ID_NAME(IID_IShellItemFilter),
+    ID_NAME(IID_IShellLinkA),
+    ID_NAME(IID_IShellLinkDual),
+    ID_NAME(IID_IShellLinkDual2),
+    ID_NAME(IID_IShellLinkW),
+    ID_NAME(IID_IShellMenu),
+    ID_NAME(IID_IShellMenu2),
+    ID_NAME(IID_IShellMenuAcc),
+    ID_NAME(IID_IShellMenuCallback),
+    ID_NAME(IID_IShellService),
+    ID_NAME(IID_IShellView),
+    ID_NAME(IID_IShellView2),
+    ID_NAME(IID_IShellView3),
+    ID_NAME(IID_IShellWindows),
+    ID_NAME(IID_IStream),
+    ID_NAME(IID_ISurrogate),
+    ID_NAME(IID_ISynchronize),
+    ID_NAME(IID_ISynchronizeContainer),
+    ID_NAME(IID_ISynchronizeEvent),
+    ID_NAME(IID_ISynchronizeHandle),
+    ID_NAME(IID_ITaskbarList),
+    ID_NAME(IID_ITaskbarList2),
+    ID_NAME(IID_ITrackShellMenu),
+    ID_NAME(IID_ITrayPriv),
+    ID_NAME(IID_ITrayPriv2),
+    ID_NAME(IID_IUnknown),
+    ID_NAME(IID_IViewObject),
+    ID_NAME(IID_IViewObject2),
+    ID_NAME(IID_IWinEventHandler),
+
+    ID_NAME(IID_DFConstraint),
+    ID_NAME(DIID_DShellFolderViewEvents),
+
+    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),
+};
+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: { %s%x,   &%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 = RegOpenKeyEx(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 dllName[100];
+            DWORD dllNameSize;
+
+            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 = RegOpenKeyEx(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 = RegOpenKeyEx(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;
+
+            dllNameSize = sizeof(dllName);
+            result = RegQueryValueEx(hKeyServer, NULL, NULL, &type, (PBYTE)dllName, &dllNameSize);
+            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(dllNameSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dllNameSize, class->name);
+                ok(dllNameSize <= sizeof(dllName), "size %lu for %s\n", dllNameSize, class->name);
+                ok(dllName[dllNameSize / 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(dllName);
+                PathRemoveExtensionW(dllName);
+                ok(!wcsicmp(dllName, ModuleName), "Server is %ls, expected %ls for %s\n", dllName, ModuleName, class->name);
+            }
+
+            dllNameSize = sizeof(dllName);
+            result = RegQueryValueEx(hKeyServer, L"ThreadingModel", NULL, &type, (PBYTE)dllName, &dllNameSize);
+            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(dllNameSize % sizeof(WCHAR) == 0, "size %lu for %s\n", dllNameSize, class->name);
+                ok(dllNameSize <= sizeof(dllName), "size %lu for %s\n", dllNameSize, class->name);
+                ok(dllName[dllNameSize / sizeof(WCHAR) - 1] == UNICODE_NULL, "Not null terminated for %s\n", class->name);
+                ok(!wcsicmp(dllName, L"Apartment"), "Server is %ls, expected %ls for %s\n", dllName, L"Apartment", 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(GetModuleHandle(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 (SUCCEEDED(hr))
+            {
+                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();
+}
diff --git a/rostests/apitests/com/com_apitest.h b/rostests/apitests/com/com_apitest.h
new file mode 100644 (file)
index 0000000..bcaf19f
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#pragma once
+
+/* Define this if you're adding new classes - the test will auto-generate the
+ * interface table entries for you ;) */
+//#define GENERATE_TABLE_ENTRIES
+
+/* Define this to make wrong interface offsets count as test failures...
+ * we usually don't want to be that strict */
+//#define FAIL_WRONG_OFFSET
+
+#define COBJMACROS
+#define WIN32_NO_STATUS
+#define UNICODE
+#include <wine/test.h>
+#include <objbase.h>
+#include <objsafe.h>
+#include <oleacc.h>
+#include <oaidl.h>
+#include <mshtmhst.h>
+#include <perhist.h>
+#include <shlguid.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <shldisp.h>
+#include <shdeprecated.h>
+#include <shlobj_undoc.h>
+#include <shlguid_undoc.h>
+#include <shlwapi.h>
+#include <ndk/rtlfuncs.h>
+#include <initguid.h>
+
+#define RTL_NUMBER_OF(x) (sizeof(x) / sizeof(x[0]))
+typedef IUnknown *PUNKNOWN;
+
+typedef struct _CLASS_AND_INTERFACES
+{
+    const CLSID *clsid;
+    PCSTR name;
+    struct
+    {
+        LONG offset;
+        const IID *iid;
+    } ifaces[80];
+} CLASS_AND_INTERFACES;
+typedef const CLASS_AND_INTERFACES *PCCLASS_AND_INTERFACES;
+
+#define ID_NAME(c) &c, #c
+
+VOID
+TestClasses(
+    _In_ PCWSTR ModuleName,
+    _In_ PCCLASS_AND_INTERFACES ExpectedInterfaces,
+    _In_ INT ExpectedInterfaceCount);
+
+/* Indicate that the interface is implemented in another (probably aggregate) object,
+ * so its offset varies and is "far away" */
+#define FARAWY (-65535)
+
+// TODO: fix our headers... we really shouldn't need these here
+DEFINE_GUID(CLSID_CopyToMenu,              0xC2FBB630, 0x2971, 0x11D1, 0xA1, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13);
+DEFINE_GUID(CLSID_DeskMovr,                0x72267F6A, 0xA6F9, 0x11D0, 0xBC, 0x94, 0x00, 0xC0, 0x4F, 0xB6, 0x78, 0x63);
+DEFINE_GUID(CLSID_FadeTask,                0x7EB5FBE4, 0x2100, 0x49E6, 0x85, 0x93, 0x17, 0xE1, 0x30, 0x12, 0x2F, 0x91);
+DEFINE_GUID(CLSID_FileSearchBand,          0xc4ee31f3, 0x4768, 0x11d2, 0xbe, 0x5c, 0x00, 0xa0, 0xc9, 0xa8, 0x3d, 0xa1);
+DEFINE_GUID(CLSID_FolderItem,              0xfef10fa2, 0x355e, 0x4e06, 0x93, 0x81, 0x9b, 0x24, 0xd7, 0xf7, 0xcc, 0x88);
+DEFINE_GUID(CLSID_FolderItemsFDF,          0x53c74826, 0xab99, 0x4d33, 0xac, 0xa4, 0x31, 0x17, 0xf5, 0x1d, 0x37, 0x88);
+DEFINE_GUID(CLSID_FolderViewHost,          0x20b1cb23, 0x6968, 0x4eb9, 0xb7, 0xd4, 0xa6, 0x6d, 0x00, 0xd0, 0x7c, 0xee);
+DEFINE_GUID(CLSID_ISFBand,                 0xD82BE2B0, 0x5764, 0x11D0, 0xA9, 0x6E, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2);
+DEFINE_GUID(CLSID_MenuDeskBar,             0xECD4FC4F, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1);
+DEFINE_GUID(CLSID_MenuToolbarBase,         0x40b96610, 0xb522, 0x11d1, 0xb3, 0xb4, 0x00, 0xaa, 0x00, 0x6e, 0xfd, 0xe7);
+DEFINE_GUID(CLSID_MoveToMenu,              0xC2FBB631, 0x2971, 0x11D1, 0xA1, 0x8C, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13);
+DEFINE_GUID(CLSID_QuickLinks,              0x0E5CBF21, 0xD15F, 0x11D0, 0x83, 0x01, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83);
+DEFINE_GUID(CLSID_SendToMenu,              0x7BA4C740, 0x9E81, 0x11CF, 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37);
+DEFINE_GUID(CLSID_ShellFolderView,         0x62112aa1, 0xebe4, 0x11cf, 0xa5, 0xfb, 0x00, 0x20, 0xaf, 0xe7, 0x29, 0x2d);
+DEFINE_GUID(CLSID_ShellLinkObject,         0x11219420, 0x1768, 0x11d1, 0x95, 0xbe, 0x00, 0x60, 0x97, 0x97, 0xea, 0x4f);
+DEFINE_GUID(CLSID_StartMenuPin,            0xa2a9545d, 0xa0c2, 0x42b4, 0x97, 0x08, 0xa0, 0xb2, 0xba, 0xdd, 0x77, 0xc8);
+DEFINE_GUID(CLSID_TrackShellMenu,          0x8278F931, 0x2A3E, 0x11d2, 0x83, 0x8F, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0);
+
+DEFINE_GUID(IID_IDefViewFrame,             0x710EB7A0, 0x45ED, 0x11D0, 0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D);
+DEFINE_GUID(IID_IDocViewSite,              0x87D605E0, 0xC511, 0x11CF, 0x89, 0xA9, 0x00, 0xA0, 0xC9, 0x05, 0x41, 0x29);
+DEFINE_GUID(IID_IExtractImage,             0xbb2e617c, 0x0920, 0x11d1, 0x9a, 0x0b, 0x00, 0xc0, 0x4f, 0xc2, 0xd6, 0xc1);
+DEFINE_GUID(IID_IExtractImage2,            0x953bb1ee, 0x93b4, 0x11d1, 0x98, 0xa3, 0x00, 0xc0, 0x4f, 0xb6, 0x87, 0xda);
+DEFINE_GUID(IID_IFileSearchBand,           0x2d91eea1, 0x9932, 0x11d2, 0xbe, 0x86, 0x00, 0xa0, 0xc9, 0xa8, 0x3d, 0xa1);
+DEFINE_GUID(IID_IFolderBandPriv,           0x47c01f95, 0xe185, 0x412c, 0xb5, 0xc5, 0x4f, 0x27, 0xdf, 0x96, 0x5a, 0xea);
+DEFINE_GUID(IID_IFolderView2,              0x1af3a467, 0x214f, 0x4298, 0x90, 0x8e, 0x06, 0xb0, 0x3e, 0x0b, 0x39, 0xf9);
+DEFINE_GUID(IID_IFolderViewSettings,       0xae8c987d, 0x8797, 0x4ed3, 0xbe, 0x72, 0x2a, 0x47, 0xdd, 0x93, 0x8d, 0xb0);
+DEFINE_GUID(IID_IShellDispatch3,           0x177160ca, 0xbb5a, 0x411c, 0x84, 0x1d, 0xbd, 0x38, 0xfa, 0xcd, 0xea, 0xa0);
+DEFINE_GUID(IID_IShellDispatch4,           0xefd84b2d, 0x4bcf, 0x4298, 0xbe, 0x25, 0xeb, 0x54, 0x2a, 0x59, 0xfb, 0xda);
+DEFINE_GUID(IID_IShellDispatch5,           0x866738b9, 0x6cf2, 0x4de8, 0x87, 0x67, 0xf7, 0x94, 0xeb, 0xe7, 0x4f, 0x4e);
+DEFINE_GUID(IID_IContextMenuSite,          0x0811aebe, 0x0b87, 0x4c54, 0x9e, 0x72, 0x54, 0x8c, 0xf6, 0x49, 0x01, 0x6b);
+DEFINE_GUID(IID_IShellDesktopTray,         0x213e2df9, 0x9a14, 0x4328, 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9);
+DEFINE_GUID(IID_IShellFolderBand,          0x7fe80cc8, 0xc247, 0x11d0, 0xb9, 0x3a, 0x00, 0xa0, 0xc9, 0x03, 0x12, 0xe1);
+DEFINE_GUID(IID_IShellFolderViewDual,      0xe7a1af80, 0x4d96, 0x11cf, 0x96, 0x0c, 0x00, 0x80, 0xc7, 0xf4, 0xee, 0x85);
+DEFINE_GUID(IID_IShellFolderViewDual2,     0x31c147b6, 0x0ade, 0x4a3c, 0xb5, 0x14, 0xdd, 0xf9, 0x32, 0xef, 0x6d, 0x17);
+DEFINE_GUID(IID_IShellLinkDual,            0x88a05c00, 0xf000, 0x11ce, 0x83, 0x50, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
+DEFINE_GUID(IID_IShellLinkDual2,           0x317ee249, 0xf12e, 0x11d2, 0xb1, 0xe4, 0x00, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e);
+DEFINE_GUID(IID_IShellView3,               0xec39fa88, 0xf8af, 0x41c5, 0x84, 0x21, 0x38, 0xbe, 0xd2, 0x8f, 0x46, 0x73);
+
+DEFINE_GUID(IID_DFConstraint,              0x403df050, 0x23bd, 0x11d2, 0x93, 0x9f, 0x00, 0xa0, 0xc9, 0x1e, 0xed, 0xba);
+
+DEFINE_GUID(IID_FolderItems2,              0xc94f0ad0, 0xf363, 0x11d2, 0xa3, 0x27, 0x00, 0xc0, 0x4f, 0x8e, 0xec, 0x7f);
+DEFINE_GUID(IID_FolderItems3,              0xeaa7c309, 0xbbec, 0x49d5, 0x82, 0x1d, 0x64, 0xd9, 0x66, 0xcb, 0x66, 0x7f);
diff --git a/rostests/apitests/com/ieframe.c b/rostests/apitests/com/ieframe.c
new file mode 100644 (file)
index 0000000..f8aacba
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test for ieframe classes
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include "com_apitest.h"
+
+#define NDEBUG
+#include <debug.h>
+
+static const CLASS_AND_INTERFACES ExpectedInterfaces[] =
+{
+    {
+        ID_NAME(CLSID_ShellWindows),
+        {
+            {  -0xa0,       &IID_IMarshal },
+            {  -0x20,       &IID_IClientSecurity },
+            {    0x0,       &IID_IMultiQI },
+            {    0x0,           &IID_IUnknown },
+            { FARAWY,       &IID_IShellWindows },
+            { FARAWY,       &IID_IDispatch },
+        }
+    },
+};
+static const INT ExpectedInterfaceCount = RTL_NUMBER_OF(ExpectedInterfaces);
+
+START_TEST(ieframe)
+{
+    TestClasses(L"ieframe", ExpectedInterfaces, ExpectedInterfaceCount);
+}
diff --git a/rostests/apitests/com/shdocvw.c b/rostests/apitests/com/shdocvw.c
new file mode 100644 (file)
index 0000000..62dfe32
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test for shdocvw classes
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include "com_apitest.h"
+
+#define NDEBUG
+#include <debug.h>
+
+static const CLASS_AND_INTERFACES ExpectedInterfaces[] =
+{
+    {
+        ID_NAME(CLSID_FontsFolderShortcut),
+        {
+            {    0x0,   &IID_IShellFolder2 },
+            {    0x0,       &IID_IShellFolder },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IPersistFolder3 },
+            {    0x4,       &IID_IPersistFolder2 },
+            {    0x4,           &IID_IPersistFolder },
+            {    0x4,               &IID_IPersist },
+            {    0x8,   &IID_IShellLinkA },
+            {    0xc,   &IID_IShellLinkW },
+            {   0x10,   &IID_IPersistFile },
+            {   0x14,   &IID_IExtractIconW },
+            {   0x18,   &IID_IQueryInfo },
+            {   0x20,   &IID_IPersistStream },
+            {   0x20,   &IID_IPersistStreamInit },
+            {   0x24,   &IID_IPersistPropertyBag },
+        }
+    },
+#if 0 // E_OUTOFMEMORY?
+    {
+        ID_NAME(CLSID_ShellDispatchInproc),
+        {
+            {    0x0,                       &IID_IUnknown },
+        }
+    },
+#endif
+    {
+        ID_NAME(CLSID_TaskbarList),
+        {
+            {    0x0,   &IID_ITaskbarList2 },
+            {    0x0,       &IID_ITaskbarList },
+            {    0x0,           &IID_IUnknown },
+        }
+    },
+};
+static const INT ExpectedInterfaceCount = RTL_NUMBER_OF(ExpectedInterfaces);
+
+START_TEST(shdocvw)
+{
+    TestClasses(L"shdocvw", ExpectedInterfaces, ExpectedInterfaceCount);
+}
diff --git a/rostests/apitests/com/shell32.c b/rostests/apitests/com/shell32.c
new file mode 100644 (file)
index 0000000..c943a06
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         COM interface test for shell32 classes
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include "com_apitest.h"
+
+#define NDEBUG
+#include <debug.h>
+
+static const CLASS_AND_INTERFACES ExpectedInterfaces[] =
+{
+    {
+        ID_NAME(CLSID_CopyToMenu),
+        {
+            {    0x0,   &IID_IContextMenu3 },
+            {    0x0,       &IID_IContextMenu2 },
+            {    0x0,           &IID_IContextMenu },
+            {    0x0,               &IID_IUnknown },
+            {    0x8,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_DeskMovr),
+        {
+            {    0x0,   &IID_IUnknown },
+            {   0x74,   &IID_IOleObject },
+            {   0x78,   &IID_IPersistPropertyBag },
+            {   0x80,   &IID_IOleInPlaceActiveObject },
+            {   0x84,   &IID_IViewObject2 },
+            {   0x84,       &IID_IViewObject },
+            {   0x88,   &IID_IOleWindow },
+            {   0x88,       &IID_IOleInPlaceObject },
+            {   0x88,           &IID_IOleInPlaceObjectWindowless },
+        }
+    },
+    {
+        ID_NAME(CLSID_DragDropHelper),
+        {
+            {    0x0,   &IID_IDragSourceHelper },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IDropTargetHelper },
+        }
+    },
+    {
+        ID_NAME(CLSID_FadeTask),
+        {
+            {    0x0,   &IID_IUnknown },
+        }
+    },
+    {
+        ID_NAME(CLSID_FileSearchBand),
+        {
+            {    0x0,   &IID_IFileSearchBand },
+            {    0x0,       &IID_IDispatch },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IObjectWithSite },
+            {    0x8,   &IID_IPersistStream },
+            {    0x8,       &IID_IPersist },
+            {    0xc,   &IID_IDeskBand },
+            {    0xc,       &IID_IDockingWindow },
+            {    0xc,           &IID_IOleWindow },
+            {   0x10,   &IID_IInputObject },
+            {   0x18,   &IID_IOleInPlaceSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_FolderItem),
+        {
+            //{    0x0,   &CLSID_ShellFolderItem }, // broken QueryInterface that doesn't add a reference
+            {    0x0,       &IID_FolderItem2 },
+            {    0x0,           &IID_FolderItem },
+            {    0x0,               &IID_IDispatch },
+            {    0x0,                   &IID_IUnknown },
+            {    0x4,   &IID_IPersistFolder2 },
+            {    0x4,       &IID_IPersistFolder },
+            {    0x4,           &IID_IPersist },
+            {    0x8,   &IID_IObjectSafety },
+        }
+    },
+    {
+        ID_NAME(CLSID_FolderItemsFDF),
+        {
+            {    0x0,   &IID_FolderItems3 },
+            //{    0x0,       &IID_FolderItems2 }, ????
+            {    0x0,           &IID_FolderItems },
+            {    0x0,               &IID_IDispatch },
+            {    0x0,                   &IID_IUnknown },
+            {    0x4,   &IID_IPersistFolder },
+            {    0x8,   &IID_IObjectSafety },
+        }
+    },
+    {
+        ID_NAME(CLSID_FolderShortcut),
+        {
+            {    0x0,   &IID_IShellFolder2 },
+            {    0x0,       &IID_IShellFolder },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IPersistFolder3 },
+            {    0x4,       &IID_IPersistFolder2 },
+            {    0x4,           &IID_IPersistFolder },
+            {    0x4,               &IID_IPersist },
+            {    0x8,   &IID_IShellLinkA },
+            {    0xc,   &IID_IShellLinkW },
+            {   0x10,   &IID_IPersistFile },
+            {   0x14,   &IID_IExtractIconW },
+            {   0x18,   &IID_IQueryInfo },
+            {   0x20,   &IID_IPersistStream },
+            {   0x20,   &IID_IPersistStreamInit },
+            {   0x24,   &IID_IPersistPropertyBag },
+        }
+    },
+    {
+        ID_NAME(CLSID_FolderViewHost),
+        {
+            {    0x0,   &IID_IUnknown },
+            {    0x4,   &IID_IServiceProvider },
+            {    0x8,   &IID_IOleWindow },
+            {    0xc,   &IID_IFolderView },
+            {   0x10,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_ISFBand),
+        {
+            {  -0xac,   &IID_IDeskBand },
+            {  -0xac,       &IID_IDockingWindow },
+            {  -0xac,           &IID_IOleWindow },
+            {  -0xa8,   &IID_IObjectWithSite },
+            {  -0xa0,   &IID_IInputObject },
+            {  -0x9c,   &IID_IPersistStream },
+            {  -0x9c,       &IID_IPersist },
+            {  -0x98,   &IID_IOleCommandTarget },
+            {  -0x94,   &IID_IServiceProvider },
+            {  -0x78,   &IID_IWinEventHandler },
+            {  -0x74,   &IID_IShellChangeNotify },
+            {  -0x70,   &IID_IDropTarget },
+            {   -0x4,   &IID_IContextMenu },
+            {    0x0,   &IID_IShellFolderBand },
+            {    0x0,       &IID_IUnknown },
+            {   0x94,   &IID_IFolderBandPriv },
+        }
+    },
+    {
+        ID_NAME(CLSID_MenuBand),
+        {
+            {  -0x30,   &IID_IDeskBand },
+            {  -0x30,       &IID_IDockingWindow },
+            {  -0x30,           &IID_IOleWindow },
+            {  -0x2c,   &IID_IObjectWithSite },
+            {  -0x24,   &IID_IInputObject },
+            {  -0x20,   &IID_IPersistStream },
+            {  -0x20,       &IID_IPersist },
+            {  -0x1c,   &IID_IOleCommandTarget },
+            {  -0x18,   &IID_IServiceProvider },
+            {    0x0,   &IID_IMenuPopup },
+            {    0x0,       &IID_IDeskBar },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IMenuBand },
+            {    0x8,   &IID_IShellMenu2 },
+            {    0x8,       &IID_IShellMenu },
+            {    0xc,   &IID_IWinEventHandler },
+            {   0x10,   &IID_IShellMenuAcc },
+        }
+    },
+    {
+        ID_NAME(CLSID_MenuBandSite),
+        {
+            {    0x0,   &IID_IBandSite },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IDeskBarClient },
+            {    0x4,       &IID_IOleWindow },
+            {    0x8,   &IID_IOleCommandTarget },
+            {    0xc,   &IID_IInputObject },
+            {   0x10,   &IID_IInputObjectSite },
+            {   0x14,   &IID_IWinEventHandler },
+            {   0x18,   &IID_IServiceProvider },
+        }
+    },
+    {
+        ID_NAME(CLSID_MenuDeskBar),
+        {
+            {  -0x48,   &IID_IOleCommandTarget },
+            {  -0x44,   &IID_IServiceProvider },
+            {  -0x40,   &IID_IDeskBar },
+            {  -0x40,       &IID_IOleWindow },
+            {  -0x3c,   &IID_IInputObjectSite },
+            {  -0x38,   &IID_IInputObject },
+            {    0x0,   &IID_IMenuPopup },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IObjectWithSite },
+            {    0x8,   &IID_IBanneredBar },
+            {    0xc,   &IID_IInitializeObject },
+        }
+    },
+#if 0 // This is registered to shell32, but can't be instanciated
+    {
+        ID_NAME(CLSID_MenuToolbarBase),
+        {
+            {    0x0,   &IID_IUnknown },
+        }
+    },
+#endif
+    {
+        ID_NAME(CLSID_MoveToMenu),
+        {
+            {    0x0,   &IID_IContextMenu3 },
+            {    0x0,       &IID_IContextMenu2 },
+            {    0x0,           &IID_IContextMenu },
+            {    0x0,               &IID_IUnknown },
+            {    0x8,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_NewMenu),
+        {
+            {   -0xc,   &IID_IObjectWithSite },
+            {   -0x4,   &IID_IContextMenu3 },
+            {   -0x4,       &IID_IContextMenu2 },
+            {   -0x4,           &IID_IContextMenu },
+            {    0x0,   &IID_IUnknown },
+        }
+    },
+    {
+        ID_NAME(CLSID_PersonalStartMenu),
+        {
+            {  -0x30,   &IID_IDeskBand },
+            {  -0x30,       &IID_IDockingWindow },
+            {  -0x30,           &IID_IOleWindow },
+            {  -0x2c,   &IID_IObjectWithSite },
+            {  -0x24,   &IID_IInputObject },
+            {  -0x20,   &IID_IPersistStream },
+            {  -0x20,       &IID_IPersist },
+            {  -0x1c,   &IID_IOleCommandTarget },
+            {  -0x18,   &IID_IServiceProvider },
+            {    0x0,   &IID_IMenuPopup },
+            {    0x0,       &IID_IDeskBar },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IMenuBand },
+            {    0x8,   &IID_IShellMenu2 },
+            {    0x8,       &IID_IShellMenu },
+            {    0xc,   &IID_IWinEventHandler },
+            {   0x10,   &IID_IShellMenuAcc },
+        }
+    },
+    {
+        ID_NAME(CLSID_QuickLinks),
+        {
+            {  -0xac,   &IID_IDeskBand },
+            {  -0xac,       &IID_IDockingWindow },
+            {  -0xac,           &IID_IOleWindow },
+            {  -0xa8,   &IID_IObjectWithSite },
+            {  -0xa0,   &IID_IInputObject },
+            {  -0x9c,   &IID_IPersistStream },
+            {  -0x9c,       &IID_IPersist },
+            {  -0x98,   &IID_IOleCommandTarget },
+            {  -0x94,   &IID_IServiceProvider },
+            {  -0x78,   &IID_IWinEventHandler },
+            {  -0x74,   &IID_IShellChangeNotify },
+            {  -0x70,   &IID_IDropTarget },
+            {   -0x4,   &IID_IContextMenu },
+            {    0x0,   &IID_IShellFolderBand },
+            {    0x0,       &IID_IUnknown },
+            {   0x94,   &IID_IFolderBandPriv },
+        }
+    },
+    {
+        ID_NAME(CLSID_SendToMenu),
+        {
+            {   -0x4,   &IID_IContextMenu3 },
+            {   -0x4,       &IID_IContextMenu2 },
+            {   -0x4,           &IID_IContextMenu },
+            {    0x0,   &IID_IUnknown },
+            {    0x4,   &IID_IOleWindow },
+        }
+    },
+    {
+        ID_NAME(CLSID_Shell),
+        {
+            {    0x0,   &IID_IShellDispatch4 },
+            {    0x0,       &IID_IShellDispatch3 },
+            {    0x0,           &IID_IShellDispatch2 },
+            {    0x0,               &IID_IShellDispatch },
+            {    0x0,                   &IID_IDispatch },
+            {    0x0,                       &IID_IUnknown },
+            {    0x4,   &IID_IObjectSafety },
+            {   0x20,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellDesktop),
+        {
+            {   -0x8,   &IID_IObjectWithSite },
+            {    0x0,   &IID_IUnknown },
+            {    0x8,   &IID_IPersistFolder2 },
+            {    0x8,       &IID_IPersistFolder },
+            {    0x8,           &IID_IPersist },
+            {    0xc,   &IID_IShellIcon },
+            {   0x14,   &IID_IContextMenuCB },
+            {   0x20,   &IID_IOleCommandTarget },
+            { FARAWY,   &IID_IShellFolder2 },
+            { FARAWY,       &IID_IShellFolder },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellFSFolder),
+        {
+            {    0x0,   &IID_IUnknown },
+            {    0xc,   &IID_IShellFolder2 },
+            {    0xc,       &IID_IShellFolder },
+            {   0x10,   &IID_IShellIcon },
+            {   0x18,   &IID_IPersistFolder3 },
+            {   0x18,       &IID_IPersistFolder2 },
+            {   0x18,           &IID_IPersistFolder },
+            {   0x18,               &IID_IPersist },
+            {   0x2c,   &IID_IContextMenuCB },
+            {   0x34,   &IID_IOleCommandTarget },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellFldSetExt),
+        {
+            {    0x0,   &IID_IUnknown },
+            {    0x8,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellFolderView),
+        {
+            {    0x0,   &IID_IShellFolderViewDual2 },
+            {    0x0,       &IID_IShellFolderViewDual },
+            {    0x0,           &IID_IDispatch },
+            {    0x0,               &IID_IUnknown },
+            {    0x4,   &IID_IShellService },
+            {    0x8,   &IID_IServiceProvider },
+            {    0xc,   &IID_IObjectSafety },
+            {   0x14,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellFolderViewOC),
+        {
+            {    0x0,   &IID_IFolderViewOC },
+            {    0x0,       &IID_IDispatch },
+            {    0x0,           &IID_IUnknown },
+            {    0x8,   &IID_IObjectSafety },
+            {   0x88,   &IID_IPersistStreamInit },
+            {   0x88,       &IID_IPersist },
+            {   0x90,   &IID_IOleObject },
+            {   0x94,   &IID_IOleInPlaceActiveObject },
+            {   0x98,   &IID_IOleInPlaceObjectWindowless },
+            {   0x98,       &IID_IOleInPlaceObject },
+            {   0x98,           &IID_IOleWindow },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellItem),
+        {
+            {    0x0,   &IID_IShellItem },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IPersistIDList },
+        }
+    },
+    {
+        ID_NAME(CLSID_ShellLink),
+        {
+            {    0x0,   &IID_IShellLinkA },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IShellLinkW },
+            {    0x8,   &IID_IPersistStream },
+            {    0xc,   &IID_IPersistFile },
+            {   0x14,   &IID_IContextMenu3 },
+            {   0x14,       &IID_IContextMenu2 },
+            {   0x14,           &IID_IContextMenu },
+            {   0x18,   &IID_IDropTarget },
+            {   0x1c,   &IID_IQueryInfo },
+            {   0x24,   &IID_IExtractIconA },
+            {   0x28,   &IID_IExtractIconW },
+            {   0x2c,   &IID_IExtractImage2 },
+            {   0x2c,       &IID_IExtractImage },
+            {   0x30,   &IID_IPersistPropertyBag },
+            {   0x34,   &IID_IServiceProvider },
+            {   0x3c,   &IID_IObjectWithSite },
+        }
+    },
+#if 0 // Apparently we can only get this through Folder.Items().GetLink
+    {
+        ID_NAME(CLSID_ShellLinkObject),
+        {
+            {    0x0,       &IID_IUnknown },
+        }
+    },
+#endif
+    {
+        ID_NAME(CLSID_StartMenu),
+        {
+            {  -0x48,   &IID_IOleCommandTarget },
+            {  -0x44,   &IID_IServiceProvider },
+            {  -0x40,   &IID_IDeskBar },
+            {  -0x40,       &IID_IOleWindow },
+            {  -0x3c,   &IID_IInputObjectSite },
+            {  -0x38,   &IID_IInputObject },
+            {    0x0,   &IID_IMenuPopup },
+            {    0x0,       &IID_IUnknown },
+            {    0x4,   &IID_IObjectWithSite },
+            {    0x8,   &IID_IBanneredBar },
+            {    0xc,   &IID_IInitializeObject },
+        }
+    },
+    {
+        ID_NAME(CLSID_StartMenuPin),
+        {
+            {    0x0,   &IID_IUnknown },
+            {    0x4,   &IID_IContextMenu },
+            {    0xc,   &IID_IObjectWithSite },
+        }
+    },
+    {
+        ID_NAME(CLSID_TrackShellMenu),
+        {
+            {    0x0,   &IID_ITrackShellMenu },
+            {    0x0,       &IID_IShellMenu },
+            {    0x0,           &IID_IUnknown },
+            {    0x4,   &IID_IShellMenu2 },
+            {    0x8,   &IID_IObjectWithSite },
+            {    0xc,   &IID_IServiceProvider },
+        }
+    },
+};
+static const INT ExpectedInterfaceCount = RTL_NUMBER_OF(ExpectedInterfaces);
+
+START_TEST(shell32)
+{
+    TestClasses(L"shell32", ExpectedInterfaces, ExpectedInterfaceCount);
+}
diff --git a/rostests/apitests/com/testlist.c b/rostests/apitests/com/testlist.c
new file mode 100644 (file)
index 0000000..941a991
--- /dev/null
@@ -0,0 +1,21 @@
+#define WIN32_LEAN_AND_MEAN
+#define __ROS_LONG64__
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_browseui(void);
+extern void func_ieframe(void);
+extern void func_shdocvw(void);
+extern void func_shell32(void);
+
+const struct test winetest_testlist[] =
+{
+    { "browseui", func_browseui },
+    { "ieframe", func_ieframe },
+    { "shdocvw", func_shdocvw },
+    { "shell32", func_shell32 },
+
+    { 0, 0 }
+};