mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-29 18:53:55 +02:00
599 lines
21 KiB
C
599 lines
21 KiB
C
/*
|
|
* Copyright (c) 2018 Alistair Leslie-Hughes
|
|
*
|
|
* 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 <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winerror.h"
|
|
#include "winstring.h"
|
|
#include "winternl.h"
|
|
|
|
#include "initguid.h"
|
|
#include "roapi.h"
|
|
#include "roerrorapi.h"
|
|
|
|
#include "wine/test.h"
|
|
|
|
#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
|
|
static void _expect_ref(IUnknown* obj, ULONG ref, int line)
|
|
{
|
|
ULONG rc;
|
|
IUnknown_AddRef(obj);
|
|
rc = IUnknown_Release(obj);
|
|
ok_(__FILE__,line)(rc == ref, "expected refcount %ld, got %ld\n", ref, rc);
|
|
}
|
|
|
|
static void flush_events(void)
|
|
{
|
|
int diff = 200;
|
|
DWORD time;
|
|
MSG msg;
|
|
|
|
time = GetTickCount() + diff;
|
|
while (diff > 0)
|
|
{
|
|
if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
|
|
break;
|
|
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
|
|
DispatchMessageA(&msg);
|
|
diff = time - GetTickCount();
|
|
}
|
|
}
|
|
|
|
static void load_resource(const WCHAR *filename)
|
|
{
|
|
DWORD written;
|
|
HANDLE file;
|
|
HRSRC res;
|
|
void *ptr;
|
|
|
|
file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
|
|
ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError());
|
|
|
|
res = FindResourceW(NULL, filename, L"TESTDLL");
|
|
ok(res != 0, "couldn't find resource\n");
|
|
ptr = LockResource(LoadResource(GetModuleHandleW(NULL), res));
|
|
WriteFile(file, ptr, SizeofResource(GetModuleHandleW(NULL), res), &written, NULL);
|
|
ok(written == SizeofResource(GetModuleHandleW(NULL), res), "couldn't write resource\n");
|
|
CloseHandle(file);
|
|
}
|
|
|
|
static void test_ActivationFactories(void)
|
|
{
|
|
HRESULT hr;
|
|
HSTRING str, str2;
|
|
IActivationFactory *factory = NULL;
|
|
IInspectable *inspect = NULL;
|
|
ULONG ref;
|
|
|
|
hr = WindowsCreateString(L"Windows.Data.Xml.Dom.XmlDocument",
|
|
ARRAY_SIZE(L"Windows.Data.Xml.Dom.XmlDocument") - 1, &str);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = WindowsCreateString(L"Does.Not.Exist", ARRAY_SIZE(L"Does.Not.Exist") - 1, &str2);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = RoInitialize(RO_INIT_MULTITHREADED);
|
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = RoGetActivationFactory(str2, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
|
if(factory)
|
|
IActivationFactory_Release(factory);
|
|
|
|
hr = RoActivateInstance(str2, &inspect);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "Unexpected hr %#lx.\n", hr);
|
|
|
|
hr = RoActivateInstance(str, &inspect);
|
|
todo_wine ok(hr == S_OK, "UNexpected hr %#lx.\n", hr);
|
|
if(inspect)
|
|
IInspectable_Release(inspect);
|
|
|
|
WindowsDeleteString(str2);
|
|
WindowsDeleteString(str);
|
|
|
|
hr = WindowsCreateString(L"Wine.Test.Missing", ARRAY_SIZE(L"Wine.Test.Missing") - 1, &str);
|
|
ok(hr == S_OK, "WindowsCreateString returned %#lx.\n", hr);
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "RoGetActivationFactory returned %#lx.\n", hr);
|
|
ok(factory == NULL, "got factory %p.\n", factory);
|
|
WindowsDeleteString(str);
|
|
hr = WindowsCreateString(L"Wine.Test.Class", ARRAY_SIZE(L"Wine.Test.Class") - 1, &str);
|
|
ok(hr == S_OK, "WindowsCreateString returned %#lx.\n", hr);
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
todo_wine
|
|
ok(hr == E_NOTIMPL || broken(hr == REGDB_E_CLASSNOTREG) /* <= w1064v1809 */,
|
|
"RoGetActivationFactory returned %#lx.\n", hr);
|
|
todo_wine
|
|
ok(factory == NULL, "got factory %p.\n", factory);
|
|
if (factory) IActivationFactory_Release(factory);
|
|
WindowsDeleteString(str);
|
|
hr = WindowsCreateString(L"Wine.Test.Trusted", ARRAY_SIZE(L"Wine.Test.Trusted") - 1, &str);
|
|
ok(hr == S_OK, "WindowsCreateString returned %#lx.\n", hr);
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* <= w1064v1809 */,
|
|
"RoGetActivationFactory returned %#lx.\n", hr);
|
|
if (hr == REGDB_E_CLASSNOTREG)
|
|
ok(!factory, "got factory %p.\n", factory);
|
|
else
|
|
ok(!!factory, "got factory %p.\n", factory);
|
|
if (!factory) ref = 0;
|
|
else ref = IActivationFactory_Release(factory);
|
|
ok(ref == 0, "Release returned %lu\n", ref);
|
|
WindowsDeleteString(str);
|
|
|
|
RoUninitialize();
|
|
}
|
|
|
|
static APTTYPE check_thread_apttype;
|
|
static APTTYPEQUALIFIER check_thread_aptqualifier;
|
|
static HRESULT check_thread_hr;
|
|
|
|
static DWORD WINAPI check_apartment_thread(void *dummy)
|
|
{
|
|
check_thread_apttype = 0xdeadbeef;
|
|
check_thread_aptqualifier = 0xdeadbeef;
|
|
check_thread_hr = CoGetApartmentType(&check_thread_apttype, &check_thread_aptqualifier);
|
|
return 0;
|
|
}
|
|
|
|
#define check_thread_apartment(a) check_thread_apartment_(__LINE__, FALSE, a)
|
|
#define check_thread_apartment_broken(a) check_thread_apartment_(__LINE__, TRUE, a)
|
|
static void check_thread_apartment_(unsigned int line, BOOL broken_fail, HRESULT expected_hr_thread)
|
|
{
|
|
HANDLE thread;
|
|
|
|
check_thread_hr = 0xdeadbeef;
|
|
thread = CreateThread(NULL, 0, check_apartment_thread, NULL, 0, NULL);
|
|
WaitForSingleObject(thread, INFINITE);
|
|
CloseHandle(thread);
|
|
ok_(__FILE__, line)(check_thread_hr == expected_hr_thread
|
|
|| broken(broken_fail && expected_hr_thread == S_OK && check_thread_hr == CO_E_NOTINITIALIZED),
|
|
"got %#lx, expected %#lx.\n", check_thread_hr, expected_hr_thread);
|
|
if (SUCCEEDED(check_thread_hr))
|
|
{
|
|
ok_(__FILE__, line)(check_thread_apttype == APTTYPE_MTA, "got %d.\n", check_thread_apttype);
|
|
ok_(__FILE__, line)(check_thread_aptqualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d.\n", check_thread_aptqualifier);
|
|
}
|
|
}
|
|
|
|
static HANDLE mta_init_thread_init_done_event, mta_init_thread_done_event;
|
|
|
|
static DWORD WINAPI mta_init_thread(void *dummy)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
SetEvent(mta_init_thread_init_done_event);
|
|
|
|
WaitForSingleObject(mta_init_thread_done_event, INFINITE);
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
static DWORD WINAPI mta_init_implicit_thread(void *dummy)
|
|
{
|
|
IActivationFactory *factory;
|
|
HSTRING str;
|
|
HRESULT hr;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
|
|
hr = WindowsCreateString(L"Does.Not.Exist", ARRAY_SIZE(L"Does.Not.Exist") - 1, &str);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr);
|
|
WindowsDeleteString(str);
|
|
|
|
SetEvent(mta_init_thread_init_done_event);
|
|
WaitForSingleObject(mta_init_thread_done_event, INFINITE);
|
|
|
|
/* No CoUninitialize(), testing cleanup on thread exit. */
|
|
return 0;
|
|
}
|
|
|
|
enum oletlsflags
|
|
{
|
|
OLETLS_UUIDINITIALIZED = 0x2,
|
|
OLETLS_DISABLE_OLE1DDE = 0x40,
|
|
OLETLS_APARTMENTTHREADED = 0x80,
|
|
OLETLS_MULTITHREADED = 0x100,
|
|
};
|
|
|
|
struct oletlsdata
|
|
{
|
|
void *threadbase;
|
|
void *smallocator;
|
|
DWORD id;
|
|
DWORD flags;
|
|
};
|
|
|
|
static DWORD get_oletlsflags(void)
|
|
{
|
|
struct oletlsdata *data = NtCurrentTeb()->ReservedForOle;
|
|
return data ? data->flags : 0;
|
|
}
|
|
|
|
static void test_implicit_mta(void)
|
|
{
|
|
static const struct
|
|
{
|
|
BOOL ro_init;
|
|
BOOL mta;
|
|
}
|
|
tests[] =
|
|
{
|
|
{ FALSE, FALSE },
|
|
{ FALSE, TRUE },
|
|
{ TRUE, FALSE },
|
|
{ TRUE, TRUE },
|
|
};
|
|
APTTYPEQUALIFIER aptqualifier;
|
|
IActivationFactory *factory;
|
|
APTTYPE apttype;
|
|
unsigned int i;
|
|
HANDLE thread;
|
|
HSTRING str;
|
|
HRESULT hr;
|
|
|
|
hr = WindowsCreateString(L"Does.Not.Exist", ARRAY_SIZE(L"Does.Not.Exist") - 1, &str);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
/* RoGetActivationFactory doesn't implicitly initialize COM. */
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == CO_E_NOTINITIALIZED, "got %#lx.\n", hr);
|
|
|
|
check_thread_apartment(CO_E_NOTINITIALIZED);
|
|
|
|
/* RoGetActivationFactory initializes implicit MTA. */
|
|
for (i = 0; i < ARRAY_SIZE(tests); ++i)
|
|
{
|
|
winetest_push_context("test %u", i);
|
|
if (tests[i].ro_init)
|
|
{
|
|
DWORD flags = tests[i].mta ? OLETLS_MULTITHREADED : OLETLS_APARTMENTTHREADED;
|
|
|
|
hr = RoInitialize(tests[i].mta ? RO_INIT_MULTITHREADED : RO_INIT_SINGLETHREADED);
|
|
|
|
flags |= OLETLS_DISABLE_OLE1DDE;
|
|
ok((get_oletlsflags() & flags) == flags, "get_oletlsflags() = %lx\n", get_oletlsflags());
|
|
}
|
|
else
|
|
hr = CoInitializeEx(NULL, tests[i].mta ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
check_thread_apartment(tests[i].mta ? S_OK : CO_E_NOTINITIALIZED);
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr);
|
|
check_thread_apartment_broken(S_OK); /* Broken on Win8. */
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr);
|
|
check_thread_apartment_broken(S_OK); /* Broken on Win8. */
|
|
if (tests[i].ro_init)
|
|
RoUninitialize();
|
|
else
|
|
CoUninitialize();
|
|
check_thread_apartment(CO_E_NOTINITIALIZED);
|
|
winetest_pop_context();
|
|
}
|
|
|
|
mta_init_thread_init_done_event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
mta_init_thread_done_event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
|
|
/* RoGetActivationFactory references implicit MTA in a current thread
|
|
* even if implicit MTA was already initialized: check with STA init
|
|
* after RoGetActivationFactory(). */
|
|
thread = CreateThread(NULL, 0, mta_init_thread, NULL, 0, NULL);
|
|
ok(!!thread, "failed.\n");
|
|
WaitForSingleObject(mta_init_thread_init_done_event, INFINITE);
|
|
check_thread_apartment(S_OK);
|
|
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr);
|
|
check_thread_apartment(S_OK);
|
|
|
|
hr = CoGetApartmentType(&apttype, &aptqualifier);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(apttype == APTTYPE_MTA, "got %d.\n", apttype);
|
|
ok(aptqualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d.\n", aptqualifier);
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
|
|
hr = CoGetApartmentType(&apttype, &aptqualifier);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
ok(apttype == APTTYPE_MAINSTA, "got %d.\n", apttype);
|
|
ok(aptqualifier == APTTYPEQUALIFIER_NONE, "got %d.\n", aptqualifier);
|
|
|
|
SetEvent(mta_init_thread_done_event);
|
|
WaitForSingleObject(thread, INFINITE);
|
|
CloseHandle(thread);
|
|
check_thread_apartment_broken(S_OK); /* Broken on Win8. */
|
|
CoUninitialize();
|
|
check_thread_apartment(CO_E_NOTINITIALIZED);
|
|
|
|
/* RoGetActivationFactory references implicit MTA in a current thread
|
|
* even if implicit MTA was already initialized: check with STA init
|
|
* before RoGetActivationFactory(). */
|
|
thread = CreateThread(NULL, 0, mta_init_thread, NULL, 0, NULL);
|
|
ok(!!thread, "failed.\n");
|
|
WaitForSingleObject(mta_init_thread_init_done_event, INFINITE);
|
|
check_thread_apartment(S_OK);
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
ok(hr == S_OK, "got %#lx.\n", hr);
|
|
|
|
hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory);
|
|
ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr);
|
|
check_thread_apartment(S_OK);
|
|
|
|
SetEvent(mta_init_thread_done_event);
|
|
WaitForSingleObject(thread, INFINITE);
|
|
CloseHandle(thread);
|
|
check_thread_apartment_broken(S_OK); /* Broken on Win8. */
|
|
CoUninitialize();
|
|
check_thread_apartment(CO_E_NOTINITIALIZED);
|
|
|
|
/* Test implicit MTA apartment thread exit. */
|
|
thread = CreateThread(NULL, 0, mta_init_implicit_thread, NULL, 0, NULL);
|
|
ok(!!thread, "failed.\n");
|
|
WaitForSingleObject(mta_init_thread_init_done_event, INFINITE);
|
|
check_thread_apartment_broken(S_OK); /* Broken on Win8. */
|
|
SetEvent(mta_init_thread_done_event);
|
|
WaitForSingleObject(thread, INFINITE);
|
|
CloseHandle(thread);
|
|
check_thread_apartment(CO_E_NOTINITIALIZED);
|
|
|
|
CloseHandle(mta_init_thread_init_done_event);
|
|
CloseHandle(mta_init_thread_done_event);
|
|
WindowsDeleteString(str);
|
|
}
|
|
|
|
struct unk_impl
|
|
{
|
|
IUnknown IUnknown_iface;
|
|
LONG ref;
|
|
};
|
|
|
|
static inline struct unk_impl *impl_from_IUnknown(IUnknown *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct unk_impl, IUnknown_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI unk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
|
|
{
|
|
if (IsEqualGUID(riid, &IID_IUnknown))
|
|
{
|
|
*ppv = iface;
|
|
IUnknown_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static HRESULT WINAPI unk_no_marshal_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
|
|
{
|
|
if (IsEqualGUID(riid, &IID_IUnknown)
|
|
|| IsEqualGUID(riid, &IID_INoMarshal))
|
|
{
|
|
*ppv = iface;
|
|
IUnknown_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI unk_AddRef(IUnknown *iface)
|
|
{
|
|
struct unk_impl *impl = impl_from_IUnknown(iface);
|
|
return InterlockedIncrement(&impl->ref);
|
|
}
|
|
|
|
static ULONG WINAPI unk_Release(IUnknown *iface)
|
|
{
|
|
struct unk_impl *impl = impl_from_IUnknown(iface);
|
|
return InterlockedDecrement(&impl->ref);
|
|
}
|
|
|
|
static const IUnknownVtbl unk_vtbl =
|
|
{
|
|
unk_QueryInterface,
|
|
unk_AddRef,
|
|
unk_Release
|
|
};
|
|
|
|
static const IUnknownVtbl unk_no_marshal_vtbl =
|
|
{
|
|
unk_no_marshal_QueryInterface,
|
|
unk_AddRef,
|
|
unk_Release
|
|
};
|
|
|
|
struct test_RoGetAgileReference_thread_param
|
|
{
|
|
enum AgileReferenceOptions option;
|
|
RO_INIT_TYPE from_type;
|
|
RO_INIT_TYPE to_type;
|
|
IAgileReference *agile_reference;
|
|
IUnknown *unk_obj;
|
|
};
|
|
|
|
static DWORD CALLBACK test_RoGetAgileReference_thread_proc(void *arg)
|
|
{
|
|
struct test_RoGetAgileReference_thread_param *param = (struct test_RoGetAgileReference_thread_param *)arg;
|
|
IUnknown *unknown;
|
|
HRESULT hr;
|
|
|
|
winetest_push_context("%d %d %d", param->option, param->from_type, param->to_type);
|
|
|
|
RoInitialize(param->to_type);
|
|
|
|
unknown = NULL;
|
|
hr = IAgileReference_Resolve(param->agile_reference, &IID_IUnknown, (void **)&unknown);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
ok(!!unknown, "Expected pointer not NULL.\n");
|
|
if (param->from_type == RO_INIT_MULTITHREADED && param->to_type == RO_INIT_MULTITHREADED)
|
|
{
|
|
ok(unknown == param->unk_obj, "Expected the same object.\n");
|
|
todo_wine_if(param->option == AGILEREFERENCE_DEFAULT)
|
|
EXPECT_REF(param->unk_obj, param->option == AGILEREFERENCE_DEFAULT ? 5 : 6);
|
|
}
|
|
else
|
|
{
|
|
ok(unknown != param->unk_obj, "Expected a different object pointer.\n");
|
|
todo_wine_if(param->option == AGILEREFERENCE_DEFAULT)
|
|
EXPECT_REF(param->unk_obj, param->option == AGILEREFERENCE_DEFAULT ? 4 : 5);
|
|
EXPECT_REF(unknown, 1);
|
|
}
|
|
IUnknown_Release(unknown);
|
|
|
|
RoUninitialize();
|
|
winetest_pop_context();
|
|
return 0;
|
|
}
|
|
|
|
static void test_RoGetAgileReference(void)
|
|
{
|
|
struct test_RoGetAgileReference_thread_param param;
|
|
struct unk_impl unk_no_marshal_obj = {{&unk_no_marshal_vtbl}, 1};
|
|
struct unk_impl unk_obj = {{&unk_vtbl}, 1};
|
|
enum AgileReferenceOptions option;
|
|
IAgileReference *agile_reference;
|
|
RO_INIT_TYPE from_type, to_type;
|
|
IUnknown *unknown, *unknown2;
|
|
IAgileObject *agile_object;
|
|
HANDLE thread;
|
|
HRESULT hr;
|
|
DWORD ret;
|
|
|
|
for (option = AGILEREFERENCE_DEFAULT; option <= AGILEREFERENCE_DELAYEDMARSHAL; option++)
|
|
{
|
|
for (from_type = RO_INIT_SINGLETHREADED; from_type <= RO_INIT_MULTITHREADED; from_type++)
|
|
{
|
|
winetest_push_context("%d %d", option, from_type);
|
|
|
|
hr = RoGetAgileReference(option, &IID_IUnknown, &unk_obj.IUnknown_iface, &agile_reference);
|
|
ok(hr == CO_E_NOTINITIALIZED, "Got unexpected hr %#lx.\n", hr);
|
|
|
|
RoInitialize(from_type);
|
|
|
|
agile_reference = NULL;
|
|
EXPECT_REF(&unk_obj, 1);
|
|
|
|
/* Invalid option */
|
|
hr = RoGetAgileReference(AGILEREFERENCE_DELAYEDMARSHAL + 1, &IID_IUnknown, &unk_obj.IUnknown_iface, &agile_reference);
|
|
ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
|
|
|
|
/* Non-existent interface for the object */
|
|
hr = RoGetAgileReference(option, &IID_IActivationFactory, &unk_obj.IUnknown_iface, &agile_reference);
|
|
ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx.\n", hr);
|
|
|
|
/* Objects that implements INoMarshal */
|
|
hr = RoGetAgileReference(option, &IID_IUnknown, &unk_no_marshal_obj.IUnknown_iface, &agile_reference);
|
|
ok(hr == CO_E_NOT_SUPPORTED, "Got unexpected hr %#lx.\n", hr);
|
|
|
|
/* Create agile reference object */
|
|
hr = RoGetAgileReference(option, &IID_IUnknown, &unk_obj.IUnknown_iface, &agile_reference);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
ok(!!agile_reference, "Got unexpected agile_reference.\n");
|
|
todo_wine_if(option == AGILEREFERENCE_DEFAULT)
|
|
EXPECT_REF(&unk_obj, 2);
|
|
|
|
/* Check the created agile reference object has IAgileObject */
|
|
hr = IAgileReference_QueryInterface(agile_reference, &IID_IAgileObject, (void **)&agile_object);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
IAgileObject_Release(agile_object);
|
|
|
|
/* Resolve once */
|
|
unknown = NULL;
|
|
hr = IAgileReference_Resolve(agile_reference, &IID_IUnknown, (void **)&unknown);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
ok(!!unknown, "Expected pointer not NULL.\n");
|
|
ok(unknown == &unk_obj.IUnknown_iface, "Expected the same object.\n");
|
|
todo_wine
|
|
EXPECT_REF(&unk_obj, 3);
|
|
|
|
/* Resolve twice */
|
|
unknown2 = NULL;
|
|
hr = IAgileReference_Resolve(agile_reference, &IID_IUnknown, (void **)&unknown2);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
ok(!!unknown2, "Expected pointer not NULL.\n");
|
|
ok(unknown2 == &unk_obj.IUnknown_iface, "Expected the same object.\n");
|
|
todo_wine
|
|
EXPECT_REF(&unk_obj, 4);
|
|
|
|
/* Resolve in another apartment */
|
|
for (to_type = RO_INIT_SINGLETHREADED; to_type <= RO_INIT_MULTITHREADED; to_type++)
|
|
{
|
|
param.option = option;
|
|
param.from_type = from_type;
|
|
param.to_type = to_type;
|
|
param.agile_reference = agile_reference;
|
|
param.unk_obj = &unk_obj.IUnknown_iface;
|
|
thread = CreateThread(NULL, 0, test_RoGetAgileReference_thread_proc, ¶m, 0, NULL);
|
|
flush_events();
|
|
ret = WaitForSingleObject(thread, 100);
|
|
ok(!ret, "WaitForSingleObject failed, error %ld.\n", GetLastError());
|
|
}
|
|
|
|
IUnknown_Release(unknown2);
|
|
IUnknown_Release(unknown);
|
|
IAgileReference_Release(agile_reference);
|
|
EXPECT_REF(&unk_obj, 1);
|
|
|
|
RoUninitialize();
|
|
winetest_pop_context();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_RoGetErrorReportingFlags(void)
|
|
{
|
|
UINT32 flags;
|
|
HRESULT hr;
|
|
|
|
hr = RoGetErrorReportingFlags(NULL);
|
|
ok(hr == E_POINTER, "Got unexpected hr %#lx.\n", hr);
|
|
|
|
hr = RoGetErrorReportingFlags(&flags);
|
|
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
|
|
ok(flags == RO_ERROR_REPORTING_USESETERRORINFO, "Got unexpected flag %#x.\n", flags);
|
|
}
|
|
|
|
START_TEST(roapi)
|
|
{
|
|
BOOL ret;
|
|
|
|
load_resource(L"wine.combase.test.dll");
|
|
|
|
test_implicit_mta();
|
|
test_ActivationFactories();
|
|
test_RoGetAgileReference();
|
|
test_RoGetErrorReportingFlags();
|
|
|
|
SetLastError(0xdeadbeef);
|
|
ret = DeleteFileW(L"wine.combase.test.dll");
|
|
todo_wine_if(!ret && GetLastError() == ERROR_ACCESS_DENIED)
|
|
ok(ret, "Failed to delete file, error %lu\n", GetLastError());
|
|
}
|