[PATCH 1/6] mscoree: Add test for registration-less COM components

Vincent Povirk vincent at codeweavers.com
Thu Aug 16 12:35:07 CDT 2018


The run_test function leaks COM objects.

The prepare_and_run_test function has several skips that look like
failures. This should result in a test failure or at least a win_skip.

I'm not clear on what the run number is for. It doesn't seem to be
used now, and the system doesn't seem to be designed for reuse
otherwise.
On Tue, Aug 7, 2018 at 12:45 PM Fabian Maurer <dark.shadow4 at web.de> wrote:
>
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270
> Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
> ---
> v2:
> Fix test not working when not in root folder
> Fix cleanup sometimes failing due to race condition
>
> v3:
> Build c# dll during test
> ---
>  dlls/mscoree/tests/Makefile.in          |   4 +
>  dlls/mscoree/tests/comtest.c            | 299 ++++++++++++++++++++++++
>  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, 416 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..687149cf57
> --- /dev/null
> +++ b/dlls/mscoree/tests/comtest.c
> @@ -0,0 +1,299 @@
> +/*
> + * 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;
> +}
> +
> +typedef HRESULT (WINAPI *_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv);
> +
> +static void run_test(int run)
> +{
> +    ITest *test = NULL;
> +    HRESULT hr;
> +    _DllGetClassObject getClassObject;
> +    IClassFactory *classFactory = NULL;
> +
> +    hr = CoCreateInstance(&CLSID_Test, NULL, CLSCTX_INPROC_SERVER, &IID_ITest, (void**)&test);
> +    todo_wine
> +    ok(hr == S_OK, "Got %x\n", hr);
> +
> +    if (test)
> +    {
> +        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);
> +    }
> +
> +    getClassObject = (_DllGetClassObject)GetProcAddress(hmscoree, "DllGetClassObject");
> +    hr = getClassObject(&CLSID_Test, &IID_IClassFactory, (void **)&classFactory);
> +    ok(hr == S_OK, "Got %x\n", hr);
> +
> +    if (classFactory)
> +    {
> +        ITest *test2 = NULL;
> +        hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2);
> +        todo_wine
> +        ok(hr == S_OK, "Got %x\n", hr);
> +
> +        if (test2)
> +        {
> +            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);
> +        }
> +    }
> +}
> +
> +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 prepare_and_run_test(int run, const char *dll_source)
> +{
> +    char path_tmp[MAX_PATH] = {0};
> +    char path_dll[MAX_PATH] = {0};
> +    char path_dll_source[MAX_PATH] = {0};
> +    char path_current[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;
> +
> +    GetCurrentDirectoryA(MAX_PATH, path_current);
> +    GetTempPathA(MAX_PATH, path_tmp);
> +
> +    if (!write_resource_file(path_tmp, dll_source, "comtest.cs", path_dll_source))
> +    {
> +        skip("run %d: Failed to create file for testing\n", run);
> +        goto cleanup;
> +    }
> +
> +    strcpy(path_dll, path_current);
> +    PathAppendA(path_dll, "comtest.dll");
> +
> +    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))
> +    {
> +        skip("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))
> +    {
> +        skip("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);
> +    todo_wine
> +    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)
> +    {
> +        skip("Failed to create activation context\n");
> +        goto cleanup;
> +    }
> +
> +    success = ActivateActCtx(handle_context, &cookie);
> +    ok(success, "run %d: ActivateActCtx failed: %d\n", run, GetLastError());
> +
> +    run_test(run);
> +
> +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;
> +
> +    GetCurrentDirectoryA(MAX_PATH, path_dll);
> +    PathAppendA(path_dll, "comtest.dll");
> +
> +    if (!PathFileExistsA(path_dll))
> +        return;
> +
> +    success = DeleteFileA(path_dll);
> +    if (!success)
> +    {
> +        Sleep(500);
> +        success = DeleteFileA(path_dll);
> +    }
> +    ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
> +}
> +
> +static void run_child_process(int run, const char *dll_source)
> +{
> +    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 %d %s", argv[0], argv[1], run, dll_source);
> +
> +    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)
> +    {
> +        int run = atoi(argv[2]);
> +        const char *dll_source = argv[3];
> +        prepare_and_run_test(run, dll_source);
> +
> +        goto cleanup;
> +    }
> +
> +    run_child_process(1, "comtest.cs");
> +
> +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