[PATCH v4 2/4] mscoree: Add test for registration-less COM components

Fabian Maurer dark.shadow4 at web.de
Sat Aug 25 12:48:38 CDT 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270
Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
v4: Test hresult instead of interface
---
 dlls/mscoree/tests/Makefile.in          |   4 +
 dlls/mscoree/tests/comtest.c            | 331 ++++++++++++++++++++++++
 dlls/mscoree/tests/comtest.cs           |  23 ++
 dlls/mscoree/tests/comtest_dll.manifest |  16 ++
 dlls/mscoree/tests/comtest_exe.manifest |  11 +
 dlls/mscoree/tests/interfaces.idl       |  33 +++
 dlls/mscoree/tests/resource.rc          |  30 +++
 7 files changed, 448 insertions(+)
 create mode 100644 dlls/mscoree/tests/comtest.c
 create mode 100644 dlls/mscoree/tests/comtest.cs
 create mode 100644 dlls/mscoree/tests/comtest_dll.manifest
 create mode 100644 dlls/mscoree/tests/comtest_exe.manifest
 create mode 100644 dlls/mscoree/tests/interfaces.idl
 create mode 100644 dlls/mscoree/tests/resource.rc

diff --git a/dlls/mscoree/tests/Makefile.in b/dlls/mscoree/tests/Makefile.in
index 7c1ba5cb11..9e53b7c577 100644
--- a/dlls/mscoree/tests/Makefile.in
+++ b/dlls/mscoree/tests/Makefile.in
@@ -2,6 +2,10 @@ TESTDLL   = mscoree.dll
 IMPORTS   = ole32 shlwapi uuid
 
 C_SRCS = \
+	comtest.c \
 	debugging.c \
 	metahost.c \
 	mscoree.c
+
+RC_SRCS = resource.rc
+IDL_SRCS = interfaces.idl
diff --git a/dlls/mscoree/tests/comtest.c b/dlls/mscoree/tests/comtest.c
new file mode 100644
index 0000000000..e6048e051f
--- /dev/null
+++ b/dlls/mscoree/tests/comtest.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2018 Fabian Maurer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include <stdio.h>
+
+#include "windows.h"
+#include "ole2.h"
+#include "mscoree.h"
+#include "corerror.h"
+#include "shlwapi.h"
+
+#include "wine/test.h"
+
+#include "initguid.h"
+#include "interfaces.h"
+
+HMODULE hmscoree;
+
+static BOOL write_resource_file(const char *path_tmp, const char *name_res, const char *name_file, char *path_file)
+{
+    HRSRC rsrc;
+    void *rsrc_data;
+    DWORD rsrc_size;
+    BOOL ret;
+    HANDLE hfile;
+
+    rsrc = FindResourceA(GetModuleHandleA(NULL), name_res, (LPCSTR)RT_RCDATA);
+    if (!rsrc) return FALSE;
+
+    rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
+    if (!rsrc_data) return FALSE;
+
+    rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc);
+    if (!rsrc_size) return FALSE;
+
+    strcpy(path_file, path_tmp);
+    PathAppendA(path_file, name_file);
+    hfile = CreateFileA(path_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+    if (hfile == INVALID_HANDLE_VALUE) return FALSE;
+
+    ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
+
+    CloseHandle(hfile);
+    return ret;
+}
+
+static BOOL compile_cs_to_dll(char *source_path, char *dest_path)
+{
+    const char *path_csc = "C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe";
+    char cmdline[MAX_PATH];
+    PROCESS_INFORMATION pi;
+    STARTUPINFOA si = { 0 };
+    BOOL ret;
+
+    if (!PathFileExistsA(path_csc))
+    {
+        skip("Can't find csc.exe\n");
+        return FALSE;
+    }
+
+    sprintf(cmdline, "%s /t:library /out:\"%s\" \"%s\"", path_csc, dest_path, source_path);
+
+    si.cb = sizeof(si);
+    ret = CreateProcessA(path_csc, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+    ok(ret, "Could not create process: %u\n", GetLastError());
+
+    WaitForSingleObject(pi.hProcess, 5000);
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+
+    ret = PathFileExistsA(dest_path);
+    ok(ret, "Compilation failed\n");
+    return ret;
+}
+
+static void run_test(BOOL expect_success)
+{
+    typedef HRESULT (WINAPI *_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv);
+    ITest *test = NULL;
+    HRESULT hr;
+    _DllGetClassObject getClassObject;
+    IClassFactory *classFactory = NULL;
+    HRESULT result_expected = expect_success ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+    hr = CoCreateInstance(&CLSID_Test, NULL, CLSCTX_INPROC_SERVER, &IID_ITest, (void**)&test);
+    todo_wine
+    ok(hr == result_expected, "Expected %x, got %x\n", result_expected, hr);
+
+    if (hr == S_OK)
+    {
+        int i = 0;
+        hr = ITest_Func(test, &i);
+        ok(hr == S_OK, "Got %x\n", hr);
+        ok(i == 42, "Expected 42, got %d\n", i);
+        ITest_Release(test);
+    }
+
+    getClassObject = (_DllGetClassObject)GetProcAddress(hmscoree, "DllGetClassObject");
+    hr = getClassObject(&CLSID_Test, &IID_IClassFactory, (void **)&classFactory);
+    todo_wine_if(!expect_success)
+    ok(hr == result_expected, "Expected %x, got %x\n", result_expected, hr);
+
+    if (hr == S_OK)
+    {
+        ITest *test2 = NULL;
+        hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2);
+        todo_wine
+        ok(hr == S_OK, "Got %x\n", hr);
+
+        if (hr == S_OK)
+        {
+            int i = 0;
+            hr = ITest_Func(test2, &i);
+            ok(hr == S_OK, "Got %x\n", hr);
+            ok(i == 42, "Expected 42, got %d\n", i);
+            ITest_Release(test2);
+        }
+        IClassFactory_Release(classFactory);
+    }
+}
+
+/*
+ * run 0: Test dll in current working directory
+ * run 1: Test dll in exe directory
+ * run 2: Test dll in c:\windows\system32
+ */
+static void get_dll_path_for_run(char *path_dll, UINT path_dll_size, int run)
+{
+    char path_tmp[MAX_PATH] = {0};
+
+    GetTempPathA(MAX_PATH, path_tmp);
+
+    switch (run)
+    {
+    case 0:
+       strcpy(path_dll, path_tmp);
+       PathAppendA(path_dll, "comtest.dll");
+       break;
+    case 1:
+       GetModuleFileNameA(NULL, path_dll, path_dll_size);
+       PathRemoveFileSpecA(path_dll);
+       PathAppendA(path_dll, "comtest.dll");
+       break;
+    case 2:
+       GetSystemDirectoryA(path_dll, path_dll_size);
+       PathAppendA(path_dll, "comtest.dll");
+       break;
+    }
+}
+static void prepare_and_run_test(const char *dll_source, int run)
+{
+    char path_tmp[MAX_PATH] = {0};
+    char path_dll[MAX_PATH] = {0};
+    char path_dll_source[MAX_PATH] = {0};
+    char path_manifest_dll[MAX_PATH] = {0};
+    char path_manifest_exe[MAX_PATH] = {0};
+    BOOL success;
+    ACTCTXA context = {0};
+    ULONG_PTR cookie;
+    HANDLE handle_context = 0;
+
+    GetTempPathA(MAX_PATH, path_tmp);
+
+    if (!write_resource_file(path_tmp, dll_source, "comtest.cs", path_dll_source))
+    {
+        ok(0, "run: %d, Failed to create file for testing\n", run);
+        goto cleanup;
+    }
+
+    get_dll_path_for_run(path_dll, sizeof(path_dll), run);
+
+    if (!compile_cs_to_dll(path_dll_source, path_dll))
+        goto cleanup;
+
+    if (!write_resource_file(path_tmp, "comtest_exe.manifest", "exe.manifest", path_manifest_exe))
+    {
+        ok(0, "run: %d, Failed to create file for testing\n", run);
+        goto cleanup;
+    }
+
+    if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll))
+    {
+        ok(0, "run: %d, Failed to create file for testing\n", run);
+        goto cleanup;
+    }
+
+    context.cbSize = sizeof(ACTCTXA);
+    context.lpSource = path_manifest_exe;
+    context.lpAssemblyDirectory = path_tmp;
+    context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
+
+    handle_context = CreateActCtxA(&context);
+    ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "run: %d, CreateActCtxA failed: %d\n", run, GetLastError());
+
+    if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE)
+    {
+        ok(0, "run: %d, Failed to create activation context\n", run);
+        goto cleanup;
+    }
+
+    success = ActivateActCtx(handle_context, &cookie);
+    ok(success, "run: %d, ActivateActCtx failed: %d\n", run,  GetLastError());
+
+    if (run == 0)
+        SetCurrentDirectoryA(path_tmp);
+
+    run_test(run == 1);
+
+cleanup:
+     if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE)
+    {
+        success = DeactivateActCtx(0, cookie);
+        ok(success, "run: %d, DeactivateActCtx failed: %d\n", run, GetLastError());
+        ReleaseActCtx(handle_context);
+    }
+    if (*path_manifest_exe)
+    {
+        success = DeleteFileA(path_manifest_exe);
+        ok(success, "run: %d, DeleteFileA failed: %d\n", run, GetLastError());
+    }
+    if(*path_manifest_dll)
+    {
+        success = DeleteFileA(path_manifest_dll);
+        ok(success, "run: %d, DeleteFileA failed: %d\n", run, GetLastError());
+    }
+    if(*path_dll_source)
+    {
+        success = DeleteFileA(path_dll_source);
+        ok(success, "run: %d, DeleteFileA failed: %d\n", run, GetLastError());
+    }
+    /* dll cleanup is handled by the parent, because it might still be used by the child */
+}
+
+
+static void cleanup_test(int run)
+{
+    char path_dll[MAX_PATH] = {0};
+    BOOL success;
+
+    get_dll_path_for_run(path_dll, sizeof(path_dll), run);
+
+    if (!PathFileExistsA(path_dll))
+        return;
+
+    success = DeleteFileA(path_dll);
+    if (!success)
+    {
+        Sleep(500);
+        success = DeleteFileA(path_dll);
+    }
+    ok(success, "DeleteFileA failed: %d\n", GetLastError());
+}
+
+static void run_child_process(const char *dll_source, int run)
+{
+    char cmdline[MAX_PATH];
+    char exe[MAX_PATH];
+    char **argv;
+    PROCESS_INFORMATION pi;
+    STARTUPINFOA si = { 0 };
+    BOOL ret;
+
+    winetest_get_mainargs(&argv);
+
+    if (strstr(argv[0], ".exe"))
+        sprintf(exe, "%s", argv[0]);
+    else
+        sprintf(exe, "%s.exe", argv[0]);
+    sprintf(cmdline, "\"%s\" %s %s %d", argv[0], argv[1], dll_source, run);
+
+    si.cb = sizeof(si);
+    ret = CreateProcessA(exe, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+    ok(ret, "Could not create process: %u\n", GetLastError());
+
+    winetest_wait_child_process(pi.hProcess);
+
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+
+    /* Cleanup dll, because it might still have been used by the child */
+    cleanup_test(run);
+}
+
+START_TEST(comtest)
+{
+    int argc;
+    char **argv;
+
+    CoInitialize(NULL);
+
+    hmscoree = LoadLibraryA("mscoree.dll");
+    if (!hmscoree)
+    {
+        skip(".NET or mono not available\n");
+        return;
+    }
+
+    argc = winetest_get_mainargs(&argv);
+    if (argc > 2)
+    {
+        const char *dll_source = argv[2];
+        int run = atoi(argv[3]);
+        prepare_and_run_test(dll_source, run);
+
+        goto cleanup;
+    }
+
+    run_child_process("comtest.cs", 0);
+    run_child_process("comtest.cs", 1);
+    run_child_process("comtest.cs", 2);
+
+cleanup:
+    FreeLibrary(hmscoree);
+    CoUninitialize();
+}
diff --git a/dlls/mscoree/tests/comtest.cs b/dlls/mscoree/tests/comtest.cs
new file mode 100644
index 0000000000..4fe2a718b2
--- /dev/null
+++ b/dlls/mscoree/tests/comtest.cs
@@ -0,0 +1,23 @@
+/* Compile with
+    csc /target:library /out:dll.dll comtest.cs
+*/
+
+using System.Runtime.InteropServices;
+
+namespace DLL
+{
+    [Guid("1dbc4491-080d-45c5-a15d-1e3c4610bdd9"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+    public interface ITest
+    {
+        void Func(ref int i);
+    }
+
+    [Guid("2e106e50-e7a4-4489-8538-83643f100fdc"), ComVisible(true), ClassInterface(ClassInterfaceType.None)]
+    public class Test : ITest
+    {
+        public void Func(ref int i)
+        {
+            i = 42;
+        }
+    }
+}
diff --git a/dlls/mscoree/tests/comtest_dll.manifest b/dlls/mscoree/tests/comtest_dll.manifest
new file mode 100644
index 0000000000..ef6924de9e
--- /dev/null
+++ b/dlls/mscoree/tests/comtest_dll.manifest
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+    <assemblyIdentity
+        name="comtest"
+        version="1.0.0.0"
+        type="win32"
+    />
+    <clrClass
+        clsid="{2e106e50-e7a4-4489-8538-83643f100fdc}"
+        threadingModel="Both"
+        name="DLL.Test"
+        runtimeVersion="v4.0.0.0">
+    </clrClass>
+    <file name="comtest.dll">
+    </file>
+</assembly>
diff --git a/dlls/mscoree/tests/comtest_exe.manifest b/dlls/mscoree/tests/comtest_exe.manifest
new file mode 100644
index 0000000000..bc9ce4c045
--- /dev/null
+++ b/dlls/mscoree/tests/comtest_exe.manifest
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+    <dependency>
+        <dependentAssembly>
+            <assemblyIdentity
+                name="comtest"
+                version="1.0.0.0"
+                type="win32"/>
+        </dependentAssembly>
+    </dependency>
+</assembly>
diff --git a/dlls/mscoree/tests/interfaces.idl b/dlls/mscoree/tests/interfaces.idl
new file mode 100644
index 0000000000..9e64988197
--- /dev/null
+++ b/dlls/mscoree/tests/interfaces.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 Fabian Maurer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "unknwn.idl"
+
+[
+    object,
+    uuid(1dbc4491-080d-45c5-a15d-1e3c4610bdd9),
+	local
+]
+interface ITest : IUnknown {
+    HRESULT Func([in, out] int *i);
+};
+
+[
+    uuid(2e106e50-e7a4-4489-8538-83643f100fdc),
+]
+coclass Test { interface ITest; };
diff --git a/dlls/mscoree/tests/resource.rc b/dlls/mscoree/tests/resource.rc
new file mode 100644
index 0000000000..9a1b89f656
--- /dev/null
+++ b/dlls/mscoree/tests/resource.rc
@@ -0,0 +1,30 @@
+/*
+ * Resources for mscoree test suite.
+ *
+ * Copyright 2018 Fabian Maurer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+
+/* @makedep: comtest.cs */
+comtest.cs RCDATA comtest.cs
+
+/* @makedep: comtest_exe.manifest */
+comtest_exe.manifest RCDATA comtest_exe.manifest
+
+/* @makedep: comtest_dll.manifest */
+comtest_dll.manifest RCDATA comtest_dll.manifest
-- 
2.18.0




More information about the wine-devel mailing list