1 /*
2  * OLE client/server test suite
3  *
4  * Copyright 2013 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define COBJMACROS
22 #define CONST_VTABLE
23 
24 #include <windows.h>
25 #include <exdisp.h>
26 #include <tlhelp32.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include "wine/test.h"
30 
31 #include <initguid.h>
32 DEFINE_GUID(CLSID_WineTestObject, 0xdeadbeef,0xdead,0xbeef,0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef);
33 #ifndef CLSID_IdentityUnmarshal
34 DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
35 #endif
36 DEFINE_GUID(CLSID_UnknownUnmarshal,0x4c1e39e1,0xe3e3,0x4296,0xaa,0x86,0xec,0x93,0x8d,0x89,0x6e,0x92);
37 
38 struct winetest_info
39 {
40     LONG child_failures;
41 };
42 
43 static const struct
44 {
45     const GUID *guid;
46     const char *name;
47 } guid_name[] =
48 {
49 #define GUID_NAME(guid) \
50     { &IID_##guid, #guid }
51     GUID_NAME(IUnknown),
52     GUID_NAME(IClassFactory),
53     GUID_NAME(IOleObject),
54     GUID_NAME(IMarshal),
55     GUID_NAME(IStdMarshalInfo),
56     GUID_NAME(IExternalConnection),
57     GUID_NAME(IRunnableObject),
58     GUID_NAME(ICallFactory),
59     { &CLSID_IdentityUnmarshal, "CLSID_IdentityUnmarshal" },
60     { &CLSID_UnknownUnmarshal, "CLSID_UnknownUnmarshal" },
61 #undef GUID_NAME
62 };
63 
64 static LONG obj_ref, class_ref, server_locks;
65 
66 static const char *debugstr_guid(const GUID *guid)
67 {
68     int i;
69 
70     if (!guid) return "(null)";
71 
72     for (i = 0; i < sizeof(guid_name)/sizeof(guid_name[0]); i++)
73     {
74         if (IsEqualIID(guid, guid_name[i].guid))
75             return guid_name[i].name;
76     }
77 
78     return wine_dbgstr_guid(guid);
79 }
80 
81 /******************************* OLE server *******************************/
82 typedef struct
83 {
84     IUnknown IUnknown_iface;
85     LONG ref;
86 } UnknownImpl;
87 
88 static inline UnknownImpl *impl_from_IUnknown(IUnknown *iface)
89 {
90     return CONTAINING_RECORD(iface, UnknownImpl, IUnknown_iface);
91 }
92 
93 static HRESULT WINAPI UnknownImpl_QueryInterface(IUnknown *iface,
94     REFIID iid, void **ppv)
95 {
96     UnknownImpl *This = impl_from_IUnknown(iface);
97 
98     trace("server: unknown_QueryInterface: %p,%s,%p\n", iface, debugstr_guid(iid), ppv);
99 
100     if (!ppv) return E_INVALIDARG;
101 
102     if (IsEqualIID(&IID_IUnknown, iid))
103     {
104         *ppv = &This->IUnknown_iface;
105         IUnknown_AddRef(&This->IUnknown_iface);
106         return S_OK;
107     }
108 
109     *ppv = NULL;
110     return E_NOINTERFACE;
111 }
112 
113 static ULONG WINAPI UnknownImpl_AddRef(IUnknown *iface)
114 {
115     UnknownImpl *This = impl_from_IUnknown(iface);
116     ULONG ref = InterlockedIncrement(&This->ref);
117 
118     InterlockedIncrement(&obj_ref);
119 
120     trace("server: unknown_AddRef: %p, ref %u\n", iface, ref);
121     return ref;
122 }
123 
124 static ULONG WINAPI UnknownImpl_Release(IUnknown *iface)
125 {
126     UnknownImpl *This = impl_from_IUnknown(iface);
127     ULONG ref = InterlockedDecrement(&This->ref);
128 
129     InterlockedDecrement(&obj_ref);
130 
131     trace("server: unknown_Release: %p, ref %u\n", iface, ref);
132     if (ref == 0) HeapFree(GetProcessHeap(), 0, This);
133     return ref;
134 }
135 
136 static const IUnknownVtbl UnknownImpl_Vtbl =
137 {
138     UnknownImpl_QueryInterface,
139     UnknownImpl_AddRef,
140     UnknownImpl_Release,
141 };
142 
143 typedef struct
144 {
145     IClassFactory IClassFactory_iface;
146     LONG ref;
147 } ClassFactoryImpl;
148 
149 static inline ClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
150 {
151     return CONTAINING_RECORD(iface, ClassFactoryImpl, IClassFactory_iface);
152 }
153 
154 static HRESULT WINAPI ClassFactoryImpl_QueryInterface(IClassFactory *iface,
155     REFIID iid, void **ppv)
156 {
157     ClassFactoryImpl *This = impl_from_IClassFactory(iface);
158 
159     trace("server: factory_QueryInterface: %p,%s,%p\n", iface, debugstr_guid(iid), ppv);
160 
161     if (!ppv) return E_INVALIDARG;
162 
163     if (IsEqualIID(&IID_IUnknown, iid) ||
164         IsEqualIID(&IID_IClassFactory, iid))
165     {
166         IClassFactory_AddRef(&This->IClassFactory_iface);
167         *ppv = &This->IClassFactory_iface;
168         return S_OK;
169     }
170 
171     *ppv = NULL;
172     return E_NOINTERFACE;
173 }
174 
175 static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface)
176 {
177     ClassFactoryImpl *This = impl_from_IClassFactory(iface);
178     ULONG ref = InterlockedIncrement(&This->ref);
179 
180     InterlockedIncrement(&class_ref);
181 
182     trace("server: factory_AddRef: %p, ref %u\n", iface, ref);
183     return ref;
184 }
185 
186 static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface)
187 {
188     ClassFactoryImpl *This = impl_from_IClassFactory(iface);
189     ULONG ref = InterlockedDecrement(&This->ref);
190 
191     InterlockedDecrement(&class_ref);
192 
193     trace("server: factory_Release: %p, ref %u\n", iface, ref);
194     return ref;
195 }
196 
197 static HRESULT WINAPI ClassFactoryImpl_CreateInstance(IClassFactory *iface,
198     IUnknown *punkouter, REFIID iid, void **ppv)
199 {
200     UnknownImpl *unknown;
201     HRESULT hr;
202 
203     trace("server: factory_CreateInstance: %p,%s,%p\n", iface, debugstr_guid(iid), ppv);
204 
205     if (punkouter) return CLASS_E_NOAGGREGATION;
206 
207     unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
208     if (!unknown) return E_OUTOFMEMORY;
209 
210     unknown->IUnknown_iface.lpVtbl = &UnknownImpl_Vtbl;
211     unknown->ref = 0;
212     IUnknown_AddRef(&unknown->IUnknown_iface);
213 
214     hr = IUnknown_QueryInterface(&unknown->IUnknown_iface, iid, ppv);
215     IUnknown_Release(&unknown->IUnknown_iface);
216 
217     return hr;
218 }
219 
220 static HRESULT WINAPI ClassFactoryImpl_LockServer(IClassFactory *iface, BOOL lock)
221 {
222     ULONG ref = lock ? InterlockedIncrement(&server_locks) : InterlockedDecrement(&server_locks);
223 
224     trace("server: factory_LockServer: %p,%d, ref %u\n", iface, lock, ref);
225     return S_OK;
226 }
227 
228 static const IClassFactoryVtbl ClassFactoryImpl_Vtbl =
229 {
230     ClassFactoryImpl_QueryInterface,
231     ClassFactoryImpl_AddRef,
232     ClassFactoryImpl_Release,
233     ClassFactoryImpl_CreateInstance,
234     ClassFactoryImpl_LockServer
235 };
236 
237 static ClassFactoryImpl factory = { { &ClassFactoryImpl_Vtbl }, 0 };
238 
239 static void ole_server(void)
240 {
241     HRESULT hr;
242     DWORD key;
243 
244     trace("server: starting %u\n", GetCurrentProcessId());
245 
246     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
247     if (hr == S_OK)
248     {
249         trace("server: registering class object\n");
250         hr = CoRegisterClassObject(&CLSID_WineTestObject, (IUnknown *)&factory,
251                                    CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &key);
252         if (hr == S_OK)
253         {
254             HANDLE done_event, init_done_event;
255 
256             done_event = OpenEventA(SYNCHRONIZE, FALSE, "ole_server_done_event");
257             ok(done_event != 0, "server: OpenEvent error %d\n", GetLastError());
258             init_done_event = OpenEventA(EVENT_MODIFY_STATE, FALSE, "ole_server_init_done_event");
259             ok(init_done_event != 0, "server: OpenEvent error %d\n", GetLastError());
260 
261             SetEvent(init_done_event);
262 
263             trace("server: waiting for requests\n");
264             WaitForSingleObject(done_event, INFINITE);
265 
266             /* 1 remainining class ref is supposed to be cleared by CoRevokeClassObject */
267             ok(class_ref == 1, "expected 1 class refs, got %d\n", class_ref);
268             ok(!obj_ref, "expected 0 object refs, got %d\n", obj_ref);
269             ok(!server_locks, "expected 0 server locks, got %d\n", server_locks);
270 
271             CloseHandle(done_event);
272             CloseHandle(init_done_event);
273             if (0)
274             {
275                 /* calling CoRevokeClassObject terminates process under Win7 */
276                 trace("call CoRevokeClassObject\n");
277                 CoRevokeClassObject(key);
278                 trace("ret CoRevokeClassObject\n");
279             }
280         }
281         trace("server: call CoUninitialize\n");
282         CoUninitialize();
283         trace("server: ret CoUninitialize\n");
284     }
285 
286     trace("server: exiting %u\n", GetCurrentProcessId());
287 }
288 
289 /******************************* OLE client *******************************/
290 static BOOL register_server(const char *server, BOOL inproc_handler)
291 {
292     static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
293     DWORD ret;
294     HKEY root;
295     WCHAR buf[39 + 6];
296     char server_path[MAX_PATH];
297 
298     lstrcpyA(server_path, server);
299     lstrcatA(server_path, " ole_server");
300 
301     lstrcpyW(buf, clsidW);
302     StringFromGUID2(&CLSID_WineTestObject, buf + 6, 39);
303 
304     ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0,
305                           KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL);
306     if (ret == ERROR_SUCCESS)
307     {
308         ret = RegSetValueA(root, "LocalServer32", REG_SZ, server_path, strlen(server_path));
309         ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret);
310 
311         if (inproc_handler)
312         {
313             ret = RegSetValueA(root, "InprocHandler32", REG_SZ, "ole32.dll", 9);
314             ok(ret == ERROR_SUCCESS, "RegSetValue error %u\n", ret);
315         }
316 
317         RegCloseKey(root);
318     }
319 
320     return ret == ERROR_SUCCESS;
321 }
322 
323 static void unregister_server(void)
324 {
325     static const WCHAR clsidW[] = {'C','L','S','I','D','\\',0};
326     DWORD ret;
327     HKEY root;
328     WCHAR buf[39 + 6];
329 
330     lstrcpyW(buf, clsidW);
331     StringFromGUID2(&CLSID_WineTestObject, buf + 6, 39);
332 
333     ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0,
334                           DELETE, NULL, &root, NULL);
335     if (ret == ERROR_SUCCESS)
336     {
337         ret = RegDeleteKeyA(root, "InprocHandler32");
338         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
339         ret = RegDeleteKeyA(root, "LocalServer32");
340         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
341         ret = RegDeleteKeyA(root, "");
342         ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
343         RegCloseKey(root);
344     }
345 }
346 
347 static HANDLE start_server(const char *argv0)
348 {
349     PROCESS_INFORMATION pi;
350     STARTUPINFOA si;
351     SECURITY_ATTRIBUTES sa;
352     char cmdline[MAX_PATH * 2];
353     BOOL ret;
354 
355     memset(&si, 0, sizeof(si));
356     si.cb = sizeof(si);
357     si.dwFlags = STARTF_USESTDHANDLES;
358     si.hStdInput =  GetStdHandle(STD_INPUT_HANDLE);
359     si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
360     si.hStdError = si.hStdOutput;
361 
362     sa.nLength = sizeof(sa);
363     sa.lpSecurityDescriptor = NULL;
364     sa.bInheritHandle = TRUE;
365 
366     sprintf(cmdline, "\"%s\" ole_server -server", argv0);
367     ret = CreateProcessA(argv0, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
368     ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
369     if (!ret) return 0;
370 
371     CloseHandle(pi.hThread);
372     return pi.hProcess;
373 }
374 
375 START_TEST(ole_server)
376 {
377     CLSID clsid = CLSID_WineTestObject;
378     HRESULT hr;
379     IClassFactory *factory;
380     IUnknown *unknown;
381     IOleObject *oleobj;
382     IRunnableObject *runobj;
383     DWORD ret;
384     HANDLE mapping, done_event, init_done_event, process;
385     struct winetest_info *info;
386     int argc;
387     char **argv;
388 
389     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_ole_server");
390     ok(mapping != 0, "CreateFileMapping failed\n");
391     info = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
392 
393     argc = winetest_get_mainargs(&argv);
394 
395     done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_done_event");
396     ok(done_event != 0, "CreateEvent error %d\n", GetLastError());
397     init_done_event = CreateEventA(NULL, TRUE, FALSE, "ole_server_init_done_event");
398     ok(init_done_event != 0, "CreateEvent error %d\n", GetLastError());
399 
400     if (argc > 2)
401     {
402         if (!lstrcmpiA(argv[2], "-Embedding"))
403         {
404             trace("server: Refusing to be run by ole32\n");
405             return;
406         }
407 
408         if (!lstrcmpiA(argv[2], "-server"))
409         {
410             info->child_failures = 0;
411             ole_server();
412             info->child_failures = winetest_get_failures();
413             return;
414         }
415 
416         trace("server: Unknown parameter: %s\n", argv[2]);
417         return;
418     }
419 
420     if (!register_server(argv[0], FALSE))
421     {
422         win_skip("not enough permissions to create a server CLSID key\n");
423         return;
424     }
425 
426     if (!(process = start_server(argv[0])))
427     {
428         unregister_server();
429         return;
430     }
431     WaitForSingleObject(init_done_event, 5000);
432 
433     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
434     ok(hr == S_OK, "OleInitialize error %#x\n", hr);
435 
436     hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&unknown);
437     ok(hr == REGDB_E_CLASSNOTREG, "expected REGDB_E_CLASSNOTREG, got %#x\n", hr);
438 
439     if (!register_server(argv[0], TRUE))
440     {
441         win_skip("not enough permissions to create a server CLSID key\n");
442         unregister_server();
443         return;
444     }
445 
446     trace("call CoCreateInstance(&IID_NULL)\n");
447     hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_NULL, (void **)&unknown);
448     trace("ret CoCreateInstance(&IID_NULL)\n");
449     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
450 
451     /* in-process handler supports IID_IUnknown starting from Vista */
452     trace("call CoCreateInstance(&IID_IUnknown)\n");
453     hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&unknown);
454     trace("ret CoCreateInstance(&IID_IUnknown)\n");
455     ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /* XP,win2000 and earlier */, "CoCreateInstance(IID_IUnknown) error %#x\n", hr);
456     if (hr != S_OK)
457     {
458         win_skip("In-process handler doesn't support IID_IUnknown on this platform\n");
459         goto test_local_server;
460     }
461 
462     trace("call CoCreateInstance(&IID_IOleObject)\n");
463     hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_IOleObject, (void **)&oleobj);
464     trace("ret CoCreateInstance(&IID_IOleObject)\n");
465     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
466 
467     trace("call IUnknown_QueryInterface(&IID_IRunnableObject)\n");
468     hr = IUnknown_QueryInterface(unknown, &IID_IRunnableObject, (void **)&runobj);
469     trace("ret IUnknown_QueryInterface(&IID_IRunnableObject)\n");
470     ok(hr == S_OK, "QueryInterface(&IID_IRunnableObject) error %#x\n", hr);
471 
472     ret = IRunnableObject_IsRunning(runobj);
473     ok(!ret, "expected 0, got %d\n", ret);
474 
475     trace("call OleRun\n");
476     hr = OleRun(unknown);
477     trace("ret OleRun\n");
478 todo_wine
479     ok(hr == S_OK, "OleRun error %#x\n", hr);
480 
481     ret = IRunnableObject_IsRunning(runobj);
482 todo_wine
483     ok(ret == 1, "expected 1, got %d\n", ret);
484 
485     trace("call IRunnableObject_Release\n");
486     ret = IRunnableObject_Release(runobj);
487     trace("ret IRunnableObject_Release\n");
488     ok(ret == 1, "expected ref 1, got %u\n", ret);
489 
490     trace("call IUnknown_QueryInterface(&IID_IOleObject)\n");
491     hr = IUnknown_QueryInterface(unknown, &IID_IOleObject, (void **)&oleobj);
492     trace("ret IUnknown_QueryInterface(&IID_IOleObject)\n");
493     ok(hr == S_OK, "QueryInterface(&IID_IOleObject) error %#x\n", hr);
494 
495     trace("call IOleObject_Release\n");
496     ret = IOleObject_Release(oleobj);
497     trace("ret IOleObject_Release\n");
498     ok(ret == 1, "expected ref 1, got %u\n", ret);
499 
500     trace("call IUnknown_Release\n");
501     ret = IUnknown_Release(unknown);
502     trace("ret IUnknown_Release\n");
503     ok(!ret, "expected ref 0, got %u\n", ret);
504 
505 test_local_server:
506     /* local server supports IID_IUnknown */
507     trace("call CoCreateInstance(&IID_IUnknown)\n");
508     hr = CoCreateInstance(&clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_IUnknown, (void **)&unknown);
509     trace("ret CoCreateInstance(&IID_IUnknown)\n");
510     ok(hr == S_OK, "CoCreateInstance(IID_IUnknown) error %#x\n", hr);
511 
512     trace("call IUnknown_QueryInterface(&IID_IRunnableObject)\n");
513     hr = IUnknown_QueryInterface(unknown, &IID_IRunnableObject, (void **)&runobj);
514     trace("ret IUnknown_QueryInterface(&IID_IRunnableObject)\n");
515     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
516 
517     trace("call OleRun\n");
518     hr = OleRun(unknown);
519     trace("ret OleRun\n");
520     ok(hr == S_OK, "OleRun error %#x\n", hr);
521 
522     trace("call IUnknown_QueryInterface(&IID_IOleObject)\n");
523     hr = IUnknown_QueryInterface(unknown, &IID_IOleObject, (void **)&oleobj);
524     trace("ret IUnknown_QueryInterface(&IID_IOleObject)\n");
525     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
526 
527     trace("call IUnknown_Release\n");
528     ret = IUnknown_Release(unknown);
529     trace("ret IUnknown_Release\n");
530     ok(!ret, "expected ref 0, got %u\n", ret);
531 
532     trace("call CoGetClassObject(&IID_IClassFactory)\n");
533     hr = CoGetClassObject(&clsid, CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void **)&factory);
534     trace("ret CoGetClassObject(&IID_IClassFactory)\n");
535     ok(hr == S_OK, "CoGetClassObject error %#x\n", hr);
536 
537     trace("call IClassFactory_CreateInstance(&IID_NULL)\n");
538     hr = IClassFactory_CreateInstance(factory, NULL, &IID_NULL, (void **)&oleobj);
539     trace("ret IClassFactory_CreateInstance(&IID_NULL)\n");
540     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
541 
542     trace("call IClassFactory_CreateInstance(&IID_IOleObject)\n");
543     hr = IClassFactory_CreateInstance(factory, NULL, &IID_IOleObject, (void **)&oleobj);
544     trace("ret IClassFactory_CreateInstance(&IID_IOleObject)\n");
545     ok(hr == E_NOINTERFACE, "expected E_NOINTERFACE, got %#x\n", hr);
546 
547     trace("call IClassFactory_Release\n");
548     ret = IClassFactory_Release(factory);
549     trace("ret IClassFactory_Release\n");
550     ok(!ret, "expected ref 0, got %u\n", ret);
551 
552     trace("signalling termination\n");
553     SetEvent(done_event);
554     ret = WaitForSingleObject(process, 10000);
555     ok(ret == WAIT_OBJECT_0, "server failed to terminate\n");
556 
557     OleUninitialize();
558 
559     unregister_server();
560 
561     if (info->child_failures)
562     {
563         trace("%d failures in child process\n", info->child_failures);
564         winetest_add_failures(info->child_failures);
565     }
566 }
567