mscoree: Add test for registration-less COM components.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer <dark.shadow4@web.de> Signed-off-by: Vincent Povirk <vincent@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b3252feb3f
commit
ef19a46161
|
@ -1,7 +1,11 @@
|
|||
TESTDLL = mscoree.dll
|
||||
IMPORTS = ole32 shlwapi uuid
|
||||
IMPORTS = ole32 shlwapi uuid shell32
|
||||
|
||||
C_SRCS = \
|
||||
comtest.c \
|
||||
debugging.c \
|
||||
metahost.c \
|
||||
mscoree.c
|
||||
|
||||
RC_SRCS = resource.rc
|
||||
IDL_SRCS = interfaces.idl
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* 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 "shlobj.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
|
||||
#include "initguid.h"
|
||||
#include "interfaces.h"
|
||||
|
||||
HMODULE hmscoree;
|
||||
|
||||
typedef enum _run_type
|
||||
{
|
||||
run_type_current_working_directory = 0,
|
||||
run_type_exe_directory,
|
||||
run_type_system32,
|
||||
} run_type;
|
||||
|
||||
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];
|
||||
char path_temp[MAX_PATH];
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOA si = { 0 };
|
||||
BOOL ret;
|
||||
|
||||
if (!PathFileExistsA(path_csc))
|
||||
{
|
||||
skip("Can't find csc.exe\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GetTempPathA(MAX_PATH, path_temp);
|
||||
PathAppendA(path_temp, "comtest.dll");
|
||||
|
||||
sprintf(cmdline, "%s /t:library /out:\"%s\" \"%s\"", path_csc, path_temp, 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(path_temp);
|
||||
ok(ret, "Compilation failed\n");
|
||||
|
||||
ret = MoveFileA(path_temp, dest_path);
|
||||
ok(ret, "Moving temporary file 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_dll_path_for_run(char *path_dll, UINT path_dll_size, run_type run)
|
||||
{
|
||||
char path_tmp[MAX_PATH];
|
||||
|
||||
GetTempPathA(MAX_PATH, path_tmp);
|
||||
|
||||
switch (run)
|
||||
{
|
||||
case run_type_current_working_directory:
|
||||
strcpy(path_dll, path_tmp);
|
||||
PathAppendA(path_dll, "comtest.dll");
|
||||
break;
|
||||
case run_type_exe_directory:
|
||||
GetModuleFileNameA(NULL, path_dll, path_dll_size);
|
||||
PathRemoveFileSpecA(path_dll);
|
||||
PathAppendA(path_dll, "comtest.dll");
|
||||
break;
|
||||
case run_type_system32:
|
||||
GetSystemDirectoryA(path_dll, path_dll_size);
|
||||
PathAppendA(path_dll, "comtest.dll");
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void prepare_and_run_test(const char *dll_source, run_type run)
|
||||
{
|
||||
char path_tmp[MAX_PATH];
|
||||
char path_tmp_manifest[MAX_PATH];
|
||||
char path_dll[MAX_PATH];
|
||||
char path_dll_source[MAX_PATH];
|
||||
char path_manifest_dll[MAX_PATH];
|
||||
char path_manifest_exe[MAX_PATH];
|
||||
BOOL success;
|
||||
ACTCTXA context = {0};
|
||||
ULONG_PTR cookie;
|
||||
HANDLE handle_context = 0;
|
||||
|
||||
GetTempPathA(MAX_PATH, path_tmp);
|
||||
GetTempPathA(MAX_PATH, path_tmp_manifest);
|
||||
PathAppendA(path_tmp_manifest, "manifests");
|
||||
|
||||
CreateDirectoryA(path_tmp_manifest, NULL);
|
||||
|
||||
if (run == run_type_system32)
|
||||
{
|
||||
if (!IsUserAnAdmin())
|
||||
{
|
||||
skip("Can't test dll in system32 due to user not being admin.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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_manifest, "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_manifest, "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_manifest;
|
||||
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 == run_type_current_working_directory)
|
||||
SetCurrentDirectoryA(path_tmp);
|
||||
|
||||
run_test(run == run_type_exe_directory);
|
||||
|
||||
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());
|
||||
}
|
||||
RemoveDirectoryA(path_tmp_manifest);
|
||||
/* dll cleanup is handled by the parent, because it might still be used by the child */
|
||||
}
|
||||
|
||||
|
||||
static void cleanup_test(run_type run)
|
||||
{
|
||||
char path_dll[MAX_PATH];
|
||||
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, run_type 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];
|
||||
run_type run = atoi(argv[3]);
|
||||
prepare_and_run_test(dll_source, run);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
run_child_process("comtest.cs", run_type_current_working_directory);
|
||||
run_child_process("comtest.cs", run_type_exe_directory);
|
||||
run_child_process("comtest.cs", run_type_system32);
|
||||
|
||||
cleanup:
|
||||
FreeLibrary(hmscoree);
|
||||
CoUninitialize();
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma makedep header
|
||||
|
||||
#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; };
|
|
@ -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
|
Loading…
Reference in New Issue