Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/combase/combase.c
4389 views
1
/*
2
* Copyright 2005 Juan Lang
3
* Copyright 2005-2006 Robert Shearman (for CodeWeavers)
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
*/
19
20
#define COBJMACROS
21
#include "ntstatus.h"
22
#define WIN32_NO_STATUS
23
#define USE_COM_CONTEXT_DEF
24
#include "objbase.h"
25
#include "ctxtcall.h"
26
#include "oleauto.h"
27
#include "dde.h"
28
#include "winternl.h"
29
30
#include "combase_private.h"
31
32
#include "wine/debug.h"
33
34
WINE_DEFAULT_DEBUG_CHANNEL(ole);
35
36
HINSTANCE hProxyDll;
37
38
static ULONG_PTR global_options[COMGLB_PROPERTIES_RESERVED3 + 1];
39
40
/* Ole32 exports */
41
extern void WINAPI DestroyRunningObjectTable(void);
42
extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
43
44
/*
45
* Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
46
*/
47
static LONG com_lockcount;
48
49
static LONG com_server_process_refcount;
50
51
struct comclassredirect_data
52
{
53
ULONG size;
54
ULONG flags;
55
DWORD model;
56
GUID clsid;
57
GUID alias;
58
GUID clsid2;
59
GUID tlbid;
60
ULONG name_len;
61
ULONG name_offset;
62
ULONG progid_len;
63
ULONG progid_offset;
64
ULONG clrdata_len;
65
ULONG clrdata_offset;
66
DWORD miscstatus;
67
DWORD miscstatuscontent;
68
DWORD miscstatusthumbnail;
69
DWORD miscstatusicon;
70
DWORD miscstatusdocprint;
71
};
72
73
struct ifacepsredirect_data
74
{
75
ULONG size;
76
DWORD mask;
77
GUID iid;
78
ULONG nummethods;
79
GUID tlbid;
80
GUID base;
81
ULONG name_len;
82
ULONG name_offset;
83
};
84
85
struct progidredirect_data
86
{
87
ULONG size;
88
DWORD reserved;
89
ULONG clsid_offset;
90
};
91
92
struct init_spy
93
{
94
struct list entry;
95
IInitializeSpy *spy;
96
unsigned int id;
97
};
98
99
struct registered_ps
100
{
101
struct list entry;
102
IID iid;
103
CLSID clsid;
104
};
105
106
static struct list registered_proxystubs = LIST_INIT(registered_proxystubs);
107
108
static CRITICAL_SECTION cs_registered_ps;
109
static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
110
{
111
0, 0, &cs_registered_ps,
112
{ &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
113
0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
114
};
115
static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
116
117
struct registered_class
118
{
119
struct list entry;
120
CLSID clsid;
121
OXID apartment_id;
122
IUnknown *object;
123
DWORD clscontext;
124
DWORD flags;
125
unsigned int cookie;
126
unsigned int rpcss_cookie;
127
};
128
129
static struct list registered_classes = LIST_INIT(registered_classes);
130
131
static CRITICAL_SECTION registered_classes_cs;
132
static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
133
{
134
0, 0, &registered_classes_cs,
135
{ &registered_classes_cs_debug.ProcessLocksList, &registered_classes_cs_debug.ProcessLocksList },
136
0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") }
137
};
138
static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
139
140
IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
141
{
142
struct registered_class *cur;
143
IUnknown *object = NULL;
144
145
EnterCriticalSection(&registered_classes_cs);
146
147
LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
148
{
149
if ((apt->oxid == cur->apartment_id) &&
150
(clscontext & cur->clscontext) &&
151
IsEqualGUID(&cur->clsid, rclsid))
152
{
153
object = cur->object;
154
IUnknown_AddRef(cur->object);
155
break;
156
}
157
}
158
159
LeaveCriticalSection(&registered_classes_cs);
160
161
return object;
162
}
163
164
static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
165
{
166
struct init_spy *spy;
167
168
LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry)
169
{
170
if (id == spy->id && spy->spy)
171
return spy;
172
}
173
174
return NULL;
175
}
176
177
static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr)
178
{
179
NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
180
181
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
182
{
183
HANDLE subkey;
184
WCHAR *buffer = attr->ObjectName->Buffer;
185
DWORD pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
186
UNICODE_STRING str;
187
OBJECT_ATTRIBUTES attr2 = *attr;
188
189
while (i < len && buffer[i] != '\\') i++;
190
if (i == len) return status;
191
192
attr2.ObjectName = &str;
193
194
while (i < len)
195
{
196
str.Buffer = buffer + pos;
197
str.Length = (i - pos) * sizeof(WCHAR);
198
status = NtCreateKey(&subkey, access, &attr2, 0, NULL, 0, NULL);
199
if (attr2.RootDirectory != attr->RootDirectory) NtClose(attr2.RootDirectory);
200
if (status) return status;
201
attr2.RootDirectory = subkey;
202
while (i < len && buffer[i] == '\\') i++;
203
pos = i;
204
while (i < len && buffer[i] != '\\') i++;
205
}
206
str.Buffer = buffer + pos;
207
str.Length = (i - pos) * sizeof(WCHAR);
208
status = NtCreateKey((HANDLE *)retkey, access, &attr2, 0, NULL, 0, NULL);
209
if (attr2.RootDirectory != attr->RootDirectory) NtClose(attr2.RootDirectory);
210
}
211
return status;
212
}
213
214
static HKEY classes_root_hkey;
215
216
static HKEY create_classes_root_hkey(DWORD access)
217
{
218
HKEY hkey, ret = 0;
219
OBJECT_ATTRIBUTES attr;
220
UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
221
222
attr.Length = sizeof(attr);
223
attr.RootDirectory = 0;
224
attr.ObjectName = &name;
225
attr.Attributes = 0;
226
attr.SecurityDescriptor = NULL;
227
attr.SecurityQualityOfService = NULL;
228
229
if (create_key( &hkey, access, &attr )) return 0;
230
TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
231
232
if (!(access & KEY_WOW64_64KEY))
233
{
234
if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
235
ret = hkey;
236
else
237
NtClose( hkey ); /* somebody beat us to it */
238
}
239
else
240
ret = hkey;
241
return ret;
242
}
243
244
static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access);
245
246
static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
247
{
248
OBJECT_ATTRIBUTES attr;
249
UNICODE_STRING nameW;
250
251
if (!(hkey = get_classes_root_hkey(hkey, access)))
252
return ERROR_INVALID_HANDLE;
253
254
attr.Length = sizeof(attr);
255
attr.RootDirectory = hkey;
256
attr.ObjectName = &nameW;
257
attr.Attributes = 0;
258
attr.SecurityDescriptor = NULL;
259
attr.SecurityQualityOfService = NULL;
260
RtlInitUnicodeString( &nameW, name );
261
262
return RtlNtStatusToDosError(create_key(retkey, access, &attr));
263
}
264
265
static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access)
266
{
267
HKEY ret = hkey;
268
const BOOL is_win64 = sizeof(void*) > sizeof(int);
269
const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
270
271
if (hkey == HKEY_CLASSES_ROOT &&
272
((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
273
ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
274
if (force_wow32 && ret && ret == classes_root_hkey)
275
{
276
access &= ~KEY_WOW64_32KEY;
277
if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey))
278
return 0;
279
ret = hkey;
280
}
281
282
return ret;
283
}
284
285
static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
286
{
287
OBJECT_ATTRIBUTES attr;
288
UNICODE_STRING nameW;
289
290
if (!(hkey = get_classes_root_hkey(hkey, access)))
291
return ERROR_INVALID_HANDLE;
292
293
attr.Length = sizeof(attr);
294
attr.RootDirectory = hkey;
295
attr.ObjectName = &nameW;
296
attr.Attributes = 0;
297
attr.SecurityDescriptor = NULL;
298
attr.SecurityQualityOfService = NULL;
299
RtlInitUnicodeString( &nameW, name );
300
301
return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
302
}
303
304
HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
305
{
306
static const WCHAR clsidW[] = L"CLSID\\";
307
WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
308
LONG res;
309
HKEY key;
310
311
lstrcpyW(path, clsidW);
312
StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID);
313
res = open_classes_key(HKEY_CLASSES_ROOT, path, access, &key);
314
if (res == ERROR_FILE_NOT_FOUND)
315
return REGDB_E_CLASSNOTREG;
316
else if (res != ERROR_SUCCESS)
317
return REGDB_E_READREGDB;
318
319
if (!keyname)
320
{
321
*subkey = key;
322
return S_OK;
323
}
324
325
res = open_classes_key(key, keyname, access, subkey);
326
RegCloseKey(key);
327
if (res == ERROR_FILE_NOT_FOUND)
328
return REGDB_E_KEYMISSING;
329
else if (res != ERROR_SUCCESS)
330
return REGDB_E_READREGDB;
331
332
return S_OK;
333
}
334
335
/* open HKCR\\AppId\\{string form of appid clsid} key */
336
HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey)
337
{
338
static const WCHAR appidkeyW[] = L"AppId\\";
339
DWORD res;
340
WCHAR buf[CHARS_IN_GUID];
341
WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID];
342
DWORD size;
343
HKEY hkey;
344
DWORD type;
345
HRESULT hr;
346
347
/* read the AppID value under the class's key */
348
hr = open_key_for_clsid(clsid, NULL, access, &hkey);
349
if (FAILED(hr))
350
return hr;
351
352
size = sizeof(buf);
353
res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size);
354
RegCloseKey(hkey);
355
if (res == ERROR_FILE_NOT_FOUND)
356
return REGDB_E_KEYMISSING;
357
else if (res != ERROR_SUCCESS || type!=REG_SZ)
358
return REGDB_E_READREGDB;
359
360
lstrcpyW(keyname, appidkeyW);
361
lstrcatW(keyname, buf);
362
res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
363
if (res == ERROR_FILE_NOT_FOUND)
364
return REGDB_E_KEYMISSING;
365
else if (res != ERROR_SUCCESS)
366
return REGDB_E_READREGDB;
367
368
return S_OK;
369
}
370
371
/***********************************************************************
372
* InternalIsProcessInitialized (combase.@)
373
*/
374
BOOL WINAPI InternalIsProcessInitialized(void)
375
{
376
struct apartment *apt;
377
378
if (!(apt = apartment_get_current_or_mta()))
379
return FALSE;
380
apartment_release(apt);
381
382
return TRUE;
383
}
384
385
/***********************************************************************
386
* InternalTlsAllocData (combase.@)
387
*/
388
HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data)
389
{
390
if (!(*data = calloc(1, sizeof(**data))))
391
return E_OUTOFMEMORY;
392
393
list_init(&(*data)->spies);
394
NtCurrentTeb()->ReservedForOle = *data;
395
396
return S_OK;
397
}
398
399
static void com_cleanup_tlsdata(void)
400
{
401
struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle;
402
struct init_spy *cursor, *cursor2;
403
404
if (!tlsdata)
405
return;
406
407
if (tlsdata->apt)
408
apartment_release(tlsdata->apt);
409
if (tlsdata->implicit_mta_cookie)
410
apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie);
411
412
if (tlsdata->errorinfo)
413
IErrorInfo_Release(tlsdata->errorinfo);
414
if (tlsdata->state)
415
IUnknown_Release(tlsdata->state);
416
417
LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry)
418
{
419
list_remove(&cursor->entry);
420
if (cursor->spy)
421
IInitializeSpy_Release(cursor->spy);
422
free(cursor);
423
}
424
425
if (tlsdata->context_token)
426
IObjContext_Release(tlsdata->context_token);
427
428
free(tlsdata);
429
NtCurrentTeb()->ReservedForOle = NULL;
430
}
431
432
struct global_options
433
{
434
IGlobalOptions IGlobalOptions_iface;
435
LONG refcount;
436
};
437
438
static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface)
439
{
440
return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface);
441
}
442
443
static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
444
{
445
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
446
447
if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
448
{
449
*ppv = iface;
450
}
451
else
452
{
453
*ppv = NULL;
454
return E_NOINTERFACE;
455
}
456
457
IUnknown_AddRef((IUnknown *)*ppv);
458
return S_OK;
459
}
460
461
static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface)
462
{
463
struct global_options *options = impl_from_IGlobalOptions(iface);
464
LONG refcount = InterlockedIncrement(&options->refcount);
465
466
TRACE("%p, refcount %ld.\n", iface, refcount);
467
468
return refcount;
469
}
470
471
static ULONG WINAPI global_options_Release(IGlobalOptions *iface)
472
{
473
struct global_options *options = impl_from_IGlobalOptions(iface);
474
LONG refcount = InterlockedDecrement(&options->refcount);
475
476
TRACE("%p, refcount %ld.\n", iface, refcount);
477
478
if (!refcount)
479
free(options);
480
481
return refcount;
482
}
483
484
static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
485
{
486
FIXME("%p, %u, %Ix.\n", iface, property, value);
487
488
return S_OK;
489
}
490
491
static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
492
{
493
TRACE("%p, %u, %p.\n", iface, property, value);
494
495
if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3)
496
return E_INVALIDARG;
497
498
*value = global_options[property];
499
500
return S_OK;
501
}
502
503
static const IGlobalOptionsVtbl global_options_vtbl =
504
{
505
global_options_QueryInterface,
506
global_options_AddRef,
507
global_options_Release,
508
global_options_Set,
509
global_options_Query
510
};
511
512
static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
513
{
514
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
515
516
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
517
{
518
*ppv = iface;
519
return S_OK;
520
}
521
522
*ppv = NULL;
523
return E_NOINTERFACE;
524
}
525
526
static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
527
{
528
return 2;
529
}
530
531
static ULONG WINAPI class_factory_Release(IClassFactory *iface)
532
{
533
return 1;
534
}
535
536
static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock)
537
{
538
TRACE("%d\n", fLock);
539
540
return S_OK;
541
}
542
543
static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
544
{
545
struct global_options *object;
546
HRESULT hr;
547
548
TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv);
549
550
if (outer)
551
return E_INVALIDARG;
552
553
if (!(object = malloc(sizeof(*object))))
554
return E_OUTOFMEMORY;
555
object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl;
556
object->refcount = 1;
557
558
hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv);
559
IGlobalOptions_Release(&object->IGlobalOptions_iface);
560
return hr;
561
}
562
563
static const IClassFactoryVtbl global_options_factory_vtbl =
564
{
565
class_factory_QueryInterface,
566
class_factory_AddRef,
567
class_factory_Release,
568
global_options_CreateInstance,
569
class_factory_LockServer
570
};
571
572
static IClassFactory global_options_factory = { &global_options_factory_vtbl };
573
574
static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj)
575
{
576
if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
577
return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
578
return E_UNEXPECTED;
579
}
580
581
/***********************************************************************
582
* FreePropVariantArray (combase.@)
583
*/
584
HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
585
{
586
ULONG i;
587
588
TRACE("%lu, %p.\n", count, rgvars);
589
590
if (!rgvars)
591
return E_INVALIDARG;
592
593
for (i = 0; i < count; ++i)
594
PropVariantClear(&rgvars[i]);
595
596
return S_OK;
597
}
598
599
static HRESULT propvar_validatetype(VARTYPE vt)
600
{
601
switch (vt)
602
{
603
case VT_EMPTY:
604
case VT_NULL:
605
case VT_I1:
606
case VT_I2:
607
case VT_I4:
608
case VT_I8:
609
case VT_R4:
610
case VT_R8:
611
case VT_CY:
612
case VT_DATE:
613
case VT_BSTR:
614
case VT_ERROR:
615
case VT_BOOL:
616
case VT_DECIMAL:
617
case VT_UI1:
618
case VT_UI2:
619
case VT_UI4:
620
case VT_UI8:
621
case VT_INT:
622
case VT_UINT:
623
case VT_LPSTR:
624
case VT_LPWSTR:
625
case VT_FILETIME:
626
case VT_BLOB:
627
case VT_DISPATCH:
628
case VT_UNKNOWN:
629
case VT_STREAM:
630
case VT_STORAGE:
631
case VT_STREAMED_OBJECT:
632
case VT_STORED_OBJECT:
633
case VT_BLOB_OBJECT:
634
case VT_CF:
635
case VT_CLSID:
636
case VT_I1|VT_VECTOR:
637
case VT_I2|VT_VECTOR:
638
case VT_I4|VT_VECTOR:
639
case VT_I8|VT_VECTOR:
640
case VT_R4|VT_VECTOR:
641
case VT_R8|VT_VECTOR:
642
case VT_CY|VT_VECTOR:
643
case VT_DATE|VT_VECTOR:
644
case VT_BSTR|VT_VECTOR:
645
case VT_ERROR|VT_VECTOR:
646
case VT_BOOL|VT_VECTOR:
647
case VT_VARIANT|VT_VECTOR:
648
case VT_UI1|VT_VECTOR:
649
case VT_UI2|VT_VECTOR:
650
case VT_UI4|VT_VECTOR:
651
case VT_UI8|VT_VECTOR:
652
case VT_LPSTR|VT_VECTOR:
653
case VT_LPWSTR|VT_VECTOR:
654
case VT_FILETIME|VT_VECTOR:
655
case VT_CF|VT_VECTOR:
656
case VT_CLSID|VT_VECTOR:
657
case VT_ARRAY|VT_I1:
658
case VT_ARRAY|VT_UI1:
659
case VT_ARRAY|VT_I2:
660
case VT_ARRAY|VT_UI2:
661
case VT_ARRAY|VT_I4:
662
case VT_ARRAY|VT_UI4:
663
case VT_ARRAY|VT_INT:
664
case VT_ARRAY|VT_UINT:
665
case VT_ARRAY|VT_R4:
666
case VT_ARRAY|VT_R8:
667
case VT_ARRAY|VT_CY:
668
case VT_ARRAY|VT_DATE:
669
case VT_ARRAY|VT_BSTR:
670
case VT_ARRAY|VT_BOOL:
671
case VT_ARRAY|VT_DECIMAL:
672
case VT_ARRAY|VT_DISPATCH:
673
case VT_ARRAY|VT_UNKNOWN:
674
case VT_ARRAY|VT_ERROR:
675
case VT_ARRAY|VT_VARIANT:
676
return S_OK;
677
}
678
WARN("Bad type %d\n", vt);
679
return STG_E_INVALIDPARAMETER;
680
}
681
682
static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
683
{
684
ULONG i;
685
for (i = 0; i < count; ++i)
686
CoTaskMemFree(data[i].pClipData);
687
}
688
689
/***********************************************************************
690
* PropVariantClear (combase.@)
691
*/
692
HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
693
{
694
HRESULT hr;
695
696
TRACE("%p.\n", pvar);
697
698
if (!pvar)
699
return S_OK;
700
701
hr = propvar_validatetype(pvar->vt);
702
if (FAILED(hr))
703
{
704
memset(pvar, 0, sizeof(*pvar));
705
return hr;
706
}
707
708
switch (pvar->vt)
709
{
710
case VT_EMPTY:
711
case VT_NULL:
712
case VT_I1:
713
case VT_I2:
714
case VT_I4:
715
case VT_I8:
716
case VT_R4:
717
case VT_R8:
718
case VT_CY:
719
case VT_DATE:
720
case VT_ERROR:
721
case VT_BOOL:
722
case VT_DECIMAL:
723
case VT_UI1:
724
case VT_UI2:
725
case VT_UI4:
726
case VT_UI8:
727
case VT_INT:
728
case VT_UINT:
729
case VT_FILETIME:
730
break;
731
case VT_DISPATCH:
732
case VT_UNKNOWN:
733
case VT_STREAM:
734
case VT_STREAMED_OBJECT:
735
case VT_STORAGE:
736
case VT_STORED_OBJECT:
737
if (pvar->pStream)
738
IStream_Release(pvar->pStream);
739
break;
740
case VT_CLSID:
741
case VT_LPSTR:
742
case VT_LPWSTR:
743
/* pick an arbitrary typed pointer - we don't care about the type
744
* as we are just freeing it */
745
CoTaskMemFree(pvar->puuid);
746
break;
747
case VT_BLOB:
748
case VT_BLOB_OBJECT:
749
CoTaskMemFree(pvar->blob.pBlobData);
750
break;
751
case VT_BSTR:
752
SysFreeString(pvar->bstrVal);
753
break;
754
case VT_CF:
755
if (pvar->pclipdata)
756
{
757
propvar_free_cf_array(1, pvar->pclipdata);
758
CoTaskMemFree(pvar->pclipdata);
759
}
760
break;
761
default:
762
if (pvar->vt & VT_VECTOR)
763
{
764
ULONG i;
765
766
switch (pvar->vt & ~VT_VECTOR)
767
{
768
case VT_VARIANT:
769
FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems);
770
break;
771
case VT_CF:
772
propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems);
773
break;
774
case VT_BSTR:
775
for (i = 0; i < pvar->cabstr.cElems; i++)
776
SysFreeString(pvar->cabstr.pElems[i]);
777
break;
778
case VT_LPSTR:
779
for (i = 0; i < pvar->calpstr.cElems; i++)
780
CoTaskMemFree(pvar->calpstr.pElems[i]);
781
break;
782
case VT_LPWSTR:
783
for (i = 0; i < pvar->calpwstr.cElems; i++)
784
CoTaskMemFree(pvar->calpwstr.pElems[i]);
785
break;
786
}
787
if (pvar->vt & ~VT_VECTOR)
788
{
789
/* pick an arbitrary VT_VECTOR structure - they all have the same
790
* memory layout */
791
CoTaskMemFree(pvar->capropvar.pElems);
792
}
793
}
794
else if (pvar->vt & VT_ARRAY)
795
hr = SafeArrayDestroy(pvar->parray);
796
else
797
{
798
WARN("Invalid/unsupported type %d\n", pvar->vt);
799
hr = STG_E_INVALIDPARAMETER;
800
}
801
}
802
803
memset(pvar, 0, sizeof(*pvar));
804
return hr;
805
}
806
807
/***********************************************************************
808
* PropVariantCopy (combase.@)
809
*/
810
HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
811
{
812
ULONG len;
813
HRESULT hr;
814
815
TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
816
817
hr = propvar_validatetype(pvarSrc->vt);
818
if (FAILED(hr))
819
return DISP_E_BADVARTYPE;
820
821
/* this will deal with most cases */
822
*pvarDest = *pvarSrc;
823
824
switch (pvarSrc->vt)
825
{
826
case VT_EMPTY:
827
case VT_NULL:
828
case VT_I1:
829
case VT_UI1:
830
case VT_I2:
831
case VT_UI2:
832
case VT_BOOL:
833
case VT_DECIMAL:
834
case VT_I4:
835
case VT_UI4:
836
case VT_R4:
837
case VT_ERROR:
838
case VT_I8:
839
case VT_UI8:
840
case VT_INT:
841
case VT_UINT:
842
case VT_R8:
843
case VT_CY:
844
case VT_DATE:
845
case VT_FILETIME:
846
break;
847
case VT_DISPATCH:
848
case VT_UNKNOWN:
849
case VT_STREAM:
850
case VT_STREAMED_OBJECT:
851
case VT_STORAGE:
852
case VT_STORED_OBJECT:
853
if (pvarDest->pStream)
854
IStream_AddRef(pvarDest->pStream);
855
break;
856
case VT_CLSID:
857
pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID));
858
*pvarDest->puuid = *pvarSrc->puuid;
859
break;
860
case VT_LPSTR:
861
if (pvarSrc->pszVal)
862
{
863
len = strlen(pvarSrc->pszVal);
864
pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
865
CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR));
866
}
867
break;
868
case VT_LPWSTR:
869
if (pvarSrc->pwszVal)
870
{
871
len = lstrlenW(pvarSrc->pwszVal);
872
pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
873
CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR));
874
}
875
break;
876
case VT_BLOB:
877
case VT_BLOB_OBJECT:
878
if (pvarSrc->blob.pBlobData)
879
{
880
len = pvarSrc->blob.cbSize;
881
pvarDest->blob.pBlobData = CoTaskMemAlloc(len);
882
CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len);
883
}
884
break;
885
case VT_BSTR:
886
pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal);
887
break;
888
case VT_CF:
889
if (pvarSrc->pclipdata)
890
{
891
len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt);
892
pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
893
pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize;
894
pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt;
895
pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len);
896
CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len);
897
}
898
break;
899
default:
900
if (pvarSrc->vt & VT_VECTOR)
901
{
902
int elemSize;
903
ULONG i;
904
905
switch (pvarSrc->vt & ~VT_VECTOR)
906
{
907
case VT_I1: elemSize = sizeof(pvarSrc->cVal); break;
908
case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break;
909
case VT_I2: elemSize = sizeof(pvarSrc->iVal); break;
910
case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break;
911
case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break;
912
case VT_I4: elemSize = sizeof(pvarSrc->lVal); break;
913
case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break;
914
case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break;
915
case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break;
916
case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break;
917
case VT_I8: elemSize = sizeof(pvarSrc->hVal); break;
918
case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break;
919
case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break;
920
case VT_DATE: elemSize = sizeof(pvarSrc->date); break;
921
case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break;
922
case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break;
923
case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break;
924
case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break;
925
case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break;
926
case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break;
927
case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break;
928
929
default:
930
FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
931
return E_INVALIDARG;
932
}
933
len = pvarSrc->capropvar.cElems;
934
pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
935
if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
936
{
937
for (i = 0; i < len; i++)
938
PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]);
939
}
940
else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
941
{
942
FIXME("Copy clipformats\n");
943
}
944
else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
945
{
946
for (i = 0; i < len; i++)
947
pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]);
948
}
949
else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
950
{
951
size_t strLen;
952
for (i = 0; i < len; i++)
953
{
954
strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1;
955
pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
956
memcpy(pvarDest->calpstr.pElems[i],
957
pvarSrc->calpstr.pElems[i], strLen);
958
}
959
}
960
else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
961
{
962
size_t strLen;
963
for (i = 0; i < len; i++)
964
{
965
strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) *
966
sizeof(WCHAR);
967
pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
968
memcpy(pvarDest->calpstr.pElems[i],
969
pvarSrc->calpstr.pElems[i], strLen);
970
}
971
}
972
else
973
CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize);
974
}
975
else if (pvarSrc->vt & VT_ARRAY)
976
{
977
pvarDest->uhVal.QuadPart = 0;
978
return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray);
979
}
980
else
981
WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
982
}
983
984
return S_OK;
985
}
986
987
/***********************************************************************
988
* CoFileTimeNow (combase.@)
989
*/
990
HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
991
{
992
GetSystemTimeAsFileTime(filetime);
993
return S_OK;
994
}
995
996
/******************************************************************************
997
* CoCreateGuid (combase.@)
998
*/
999
HRESULT WINAPI CoCreateGuid(GUID *guid)
1000
{
1001
RPC_STATUS status;
1002
1003
if (!guid) return E_INVALIDARG;
1004
1005
status = UuidCreate(guid);
1006
if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1007
return HRESULT_FROM_WIN32(status);
1008
}
1009
1010
/******************************************************************************
1011
* CoQueryProxyBlanket (combase.@)
1012
*/
1013
HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
1014
DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
1015
DWORD *imp_level, void **auth_info, DWORD *capabilities)
1016
{
1017
IClientSecurity *client_security;
1018
HRESULT hr;
1019
1020
TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
1021
auth_info, capabilities);
1022
1023
hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1024
if (SUCCEEDED(hr))
1025
{
1026
hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
1027
authn_level, imp_level, auth_info, capabilities);
1028
IClientSecurity_Release(client_security);
1029
}
1030
1031
if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1032
return hr;
1033
}
1034
1035
/******************************************************************************
1036
* CoSetProxyBlanket (combase.@)
1037
*/
1038
HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
1039
OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
1040
{
1041
IClientSecurity *client_security;
1042
HRESULT hr;
1043
1044
TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, authz_service, servername,
1045
authn_level, imp_level, auth_info, capabilities);
1046
1047
hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1048
if (SUCCEEDED(hr))
1049
{
1050
hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
1051
imp_level, auth_info, capabilities);
1052
IClientSecurity_Release(client_security);
1053
}
1054
1055
if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1056
return hr;
1057
}
1058
1059
/***********************************************************************
1060
* CoCopyProxy (combase.@)
1061
*/
1062
HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
1063
{
1064
IClientSecurity *client_security;
1065
HRESULT hr;
1066
1067
TRACE("%p, %p.\n", proxy, proxy_copy);
1068
1069
hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1070
if (SUCCEEDED(hr))
1071
{
1072
hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
1073
IClientSecurity_Release(client_security);
1074
}
1075
1076
if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1077
return hr;
1078
}
1079
1080
/***********************************************************************
1081
* CoQueryClientBlanket (combase.@)
1082
*/
1083
HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
1084
DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
1085
{
1086
IServerSecurity *server_security;
1087
HRESULT hr;
1088
1089
TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
1090
privs, capabilities);
1091
1092
hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1093
if (SUCCEEDED(hr))
1094
{
1095
hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
1096
imp_level, privs, capabilities);
1097
IServerSecurity_Release(server_security);
1098
}
1099
1100
return hr;
1101
}
1102
1103
/***********************************************************************
1104
* CoImpersonateClient (combase.@)
1105
*/
1106
HRESULT WINAPI CoImpersonateClient(void)
1107
{
1108
IServerSecurity *server_security;
1109
HRESULT hr;
1110
1111
TRACE("\n");
1112
1113
hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1114
if (SUCCEEDED(hr))
1115
{
1116
hr = IServerSecurity_ImpersonateClient(server_security);
1117
IServerSecurity_Release(server_security);
1118
}
1119
1120
return hr;
1121
}
1122
1123
/***********************************************************************
1124
* CoRevertToSelf (combase.@)
1125
*/
1126
HRESULT WINAPI CoRevertToSelf(void)
1127
{
1128
IServerSecurity *server_security;
1129
HRESULT hr;
1130
1131
TRACE("\n");
1132
1133
hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1134
if (SUCCEEDED(hr))
1135
{
1136
hr = IServerSecurity_RevertToSelf(server_security);
1137
IServerSecurity_Release(server_security);
1138
}
1139
1140
return hr;
1141
}
1142
1143
/***********************************************************************
1144
* CoInitializeSecurity (combase.@)
1145
*/
1146
HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
1147
SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
1148
DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1149
{
1150
FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1151
imp_level, reserved2, capabilities, reserved3);
1152
1153
return S_OK;
1154
}
1155
1156
/***********************************************************************
1157
* CoGetObjectContext (combase.@)
1158
*/
1159
HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1160
{
1161
IObjContext *context;
1162
HRESULT hr;
1163
1164
TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1165
1166
*ppv = NULL;
1167
hr = CoGetContextToken((ULONG_PTR *)&context);
1168
if (FAILED(hr))
1169
return hr;
1170
1171
return IObjContext_QueryInterface(context, riid, ppv);
1172
}
1173
1174
/***********************************************************************
1175
* CoGetDefaultContext (combase.@)
1176
*/
1177
HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1178
{
1179
FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1180
1181
return E_NOINTERFACE;
1182
}
1183
1184
/***********************************************************************
1185
* CoGetCallState (combase.@)
1186
*/
1187
HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1188
{
1189
FIXME("%d, %p.\n", arg1, arg2);
1190
1191
return E_NOTIMPL;
1192
}
1193
1194
/***********************************************************************
1195
* CoGetActivationState (combase.@)
1196
*/
1197
HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1198
{
1199
FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3);
1200
1201
return E_NOTIMPL;
1202
}
1203
1204
/******************************************************************************
1205
* CoGetTreatAsClass (combase.@)
1206
*/
1207
HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1208
{
1209
WCHAR buffW[CHARS_IN_GUID];
1210
LONG len = sizeof(buffW);
1211
HRESULT hr = S_OK;
1212
HKEY hkey = NULL;
1213
1214
TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1215
1216
if (!clsidOld || !clsidNew)
1217
return E_INVALIDARG;
1218
1219
*clsidNew = *clsidOld;
1220
1221
hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1222
if (FAILED(hr))
1223
{
1224
hr = S_FALSE;
1225
goto done;
1226
}
1227
1228
if (RegQueryValueW(hkey, NULL, buffW, &len))
1229
{
1230
hr = S_FALSE;
1231
goto done;
1232
}
1233
1234
hr = CLSIDFromString(buffW, clsidNew);
1235
if (FAILED(hr))
1236
ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), hr);
1237
done:
1238
if (hkey) RegCloseKey(hkey);
1239
return hr;
1240
}
1241
1242
/******************************************************************************
1243
* ProgIDFromCLSID (combase.@)
1244
*/
1245
HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1246
{
1247
ACTCTX_SECTION_KEYED_DATA data;
1248
LONG progidlen = 0;
1249
HKEY hkey;
1250
REGSAM opposite = (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1251
BOOL is_wow64;
1252
HRESULT hr;
1253
1254
if (!progid)
1255
return E_INVALIDARG;
1256
1257
*progid = NULL;
1258
1259
data.cbSize = sizeof(data);
1260
if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
1261
clsid, &data))
1262
{
1263
struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1264
if (comclass->progid_len)
1265
{
1266
WCHAR *ptrW;
1267
1268
*progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
1269
if (!*progid) return E_OUTOFMEMORY;
1270
1271
ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
1272
memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
1273
return S_OK;
1274
}
1275
else
1276
return REGDB_E_CLASSNOTREG;
1277
}
1278
1279
hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
1280
if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1281
{
1282
hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey);
1283
if (FAILED(hr))
1284
return hr;
1285
}
1286
1287
if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1288
hr = REGDB_E_CLASSNOTREG;
1289
1290
if (hr == S_OK)
1291
{
1292
*progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1293
if (*progid)
1294
{
1295
if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1296
{
1297
hr = REGDB_E_CLASSNOTREG;
1298
CoTaskMemFree(*progid);
1299
*progid = NULL;
1300
}
1301
}
1302
else
1303
hr = E_OUTOFMEMORY;
1304
}
1305
1306
RegCloseKey(hkey);
1307
return hr;
1308
}
1309
1310
static inline BOOL is_valid_hex(WCHAR c)
1311
{
1312
if (!(((c >= '0') && (c <= '9')) ||
1313
((c >= 'a') && (c <= 'f')) ||
1314
((c >= 'A') && (c <= 'F'))))
1315
return FALSE;
1316
return TRUE;
1317
}
1318
1319
static const BYTE guid_conv_table[256] =
1320
{
1321
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1322
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1323
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1324
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1325
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1326
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1327
0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1328
};
1329
1330
static BOOL guid_from_string(LPCWSTR s, GUID *id)
1331
{
1332
int i;
1333
1334
if (!s || s[0] != '{')
1335
{
1336
memset(id, 0, sizeof(*id));
1337
if (!s) return TRUE;
1338
return FALSE;
1339
}
1340
1341
TRACE("%s -> %p\n", debugstr_w(s), id);
1342
1343
/* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1344
1345
id->Data1 = 0;
1346
for (i = 1; i < 9; ++i)
1347
{
1348
if (!is_valid_hex(s[i])) return FALSE;
1349
id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1350
}
1351
if (s[9] != '-') return FALSE;
1352
1353
id->Data2 = 0;
1354
for (i = 10; i < 14; ++i)
1355
{
1356
if (!is_valid_hex(s[i])) return FALSE;
1357
id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1358
}
1359
if (s[14] != '-') return FALSE;
1360
1361
id->Data3 = 0;
1362
for (i = 15; i < 19; ++i)
1363
{
1364
if (!is_valid_hex(s[i])) return FALSE;
1365
id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1366
}
1367
if (s[19] != '-') return FALSE;
1368
1369
for (i = 20; i < 37; i += 2)
1370
{
1371
if (i == 24)
1372
{
1373
if (s[i] != '-') return FALSE;
1374
i++;
1375
}
1376
if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1377
id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1378
}
1379
1380
if (s[37] == '}' && s[38] == '\0')
1381
return TRUE;
1382
1383
return FALSE;
1384
}
1385
1386
static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1387
{
1388
WCHAR buf2[CHARS_IN_GUID];
1389
LONG buf2len = sizeof(buf2);
1390
HKEY xhkey;
1391
WCHAR *buf;
1392
1393
memset(clsid, 0, sizeof(*clsid));
1394
buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1395
if (!buf) return E_OUTOFMEMORY;
1396
1397
lstrcpyW(buf, progid);
1398
lstrcatW(buf, L"\\CLSID");
1399
if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1400
{
1401
free(buf);
1402
WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1403
return CO_E_CLASSSTRING;
1404
}
1405
free(buf);
1406
1407
if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1408
{
1409
RegCloseKey(xhkey);
1410
WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1411
return CO_E_CLASSSTRING;
1412
}
1413
RegCloseKey(xhkey);
1414
return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1415
}
1416
1417
/******************************************************************************
1418
* CLSIDFromProgID (combase.@)
1419
*/
1420
HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1421
{
1422
ACTCTX_SECTION_KEYED_DATA data;
1423
1424
if (!progid || !clsid)
1425
return E_INVALIDARG;
1426
1427
data.cbSize = sizeof(data);
1428
if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1429
progid, &data))
1430
{
1431
struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1432
CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1433
*clsid = *alias;
1434
return S_OK;
1435
}
1436
1437
return clsid_from_string_reg(progid, clsid);
1438
}
1439
1440
/******************************************************************************
1441
* CLSIDFromProgIDEx (combase.@)
1442
*/
1443
HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1444
{
1445
FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1446
1447
return CLSIDFromProgID(progid, clsid);
1448
}
1449
1450
/******************************************************************************
1451
* CLSIDFromString (combase.@)
1452
*/
1453
HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1454
{
1455
CLSID tmp_id;
1456
HRESULT hr;
1457
1458
if (!clsid)
1459
return E_INVALIDARG;
1460
1461
if (guid_from_string(str, clsid))
1462
return S_OK;
1463
1464
/* It appears a ProgID is also valid */
1465
hr = clsid_from_string_reg(str, &tmp_id);
1466
if (SUCCEEDED(hr))
1467
*clsid = tmp_id;
1468
1469
return hr;
1470
}
1471
1472
/******************************************************************************
1473
* IIDFromString (combase.@)
1474
*/
1475
HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1476
{
1477
TRACE("%s, %p\n", debugstr_w(str), iid);
1478
1479
if (!str)
1480
{
1481
memset(iid, 0, sizeof(*iid));
1482
return S_OK;
1483
}
1484
1485
/* length mismatch is a special case */
1486
if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1487
return E_INVALIDARG;
1488
1489
if (str[0] != '{')
1490
return CO_E_IIDSTRING;
1491
1492
return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1493
}
1494
1495
/******************************************************************************
1496
* StringFromCLSID (combase.@)
1497
*/
1498
HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1499
{
1500
if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1501
StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1502
return S_OK;
1503
}
1504
1505
/******************************************************************************
1506
* StringFromGUID2 (combase.@)
1507
*/
1508
INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1509
{
1510
if (!guid || cmax < CHARS_IN_GUID) return 0;
1511
swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1512
guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1513
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1514
return CHARS_IN_GUID;
1515
}
1516
1517
static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1518
{
1519
ULONG i;
1520
1521
for (i = 0; i < count; i++)
1522
{
1523
mqi[i].pItf = NULL;
1524
mqi[i].hr = hr;
1525
}
1526
}
1527
1528
static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1529
{
1530
ULONG index = 0, fetched = 0;
1531
1532
if (include_unk)
1533
{
1534
mqi[0].hr = S_OK;
1535
mqi[0].pItf = unk;
1536
index = fetched = 1;
1537
}
1538
1539
for (; index < count; index++)
1540
{
1541
mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1542
if (mqi[index].hr == S_OK)
1543
fetched++;
1544
}
1545
1546
if (!include_unk)
1547
IUnknown_Release(unk);
1548
1549
if (fetched == 0)
1550
return E_NOINTERFACE;
1551
1552
return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1553
}
1554
1555
/***********************************************************************
1556
* CoGetInstanceFromFile (combase.@)
1557
*/
1558
HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1559
IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1560
MULTI_QI *results)
1561
{
1562
IPersistFile *pf = NULL;
1563
IUnknown *obj = NULL;
1564
CLSID clsid;
1565
HRESULT hr;
1566
1567
if (!count || !results)
1568
return E_INVALIDARG;
1569
1570
if (server_info)
1571
FIXME("() non-NULL server_info not supported\n");
1572
1573
init_multi_qi(count, results, E_NOINTERFACE);
1574
1575
if (!rclsid)
1576
{
1577
hr = GetClassFile(filename, &clsid);
1578
if (FAILED(hr))
1579
{
1580
ERR("Failed to get CLSID from a file.\n");
1581
return hr;
1582
}
1583
1584
rclsid = &clsid;
1585
}
1586
1587
hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1588
if (hr != S_OK)
1589
{
1590
init_multi_qi(count, results, hr);
1591
return hr;
1592
}
1593
1594
/* Init from file */
1595
hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1596
if (FAILED(hr))
1597
{
1598
init_multi_qi(count, results, hr);
1599
IUnknown_Release(obj);
1600
return hr;
1601
}
1602
1603
hr = IPersistFile_Load(pf, filename, grfmode);
1604
IPersistFile_Release(pf);
1605
if (SUCCEEDED(hr))
1606
return return_multi_qi(obj, count, results, FALSE);
1607
else
1608
{
1609
init_multi_qi(count, results, hr);
1610
IUnknown_Release(obj);
1611
return hr;
1612
}
1613
}
1614
1615
/***********************************************************************
1616
* CoGetInstanceFromIStorage (combase.@)
1617
*/
1618
HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1619
IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1620
{
1621
IPersistStorage *ps = NULL;
1622
IUnknown *obj = NULL;
1623
STATSTG stat;
1624
HRESULT hr;
1625
1626
if (!count || !results || !storage)
1627
return E_INVALIDARG;
1628
1629
if (server_info)
1630
FIXME("() non-NULL server_info not supported\n");
1631
1632
init_multi_qi(count, results, E_NOINTERFACE);
1633
1634
if (!rclsid)
1635
{
1636
memset(&stat.clsid, 0, sizeof(stat.clsid));
1637
hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1638
if (FAILED(hr))
1639
{
1640
ERR("Failed to get CLSID from a storage.\n");
1641
return hr;
1642
}
1643
1644
rclsid = &stat.clsid;
1645
}
1646
1647
hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1648
if (hr != S_OK)
1649
return hr;
1650
1651
/* Init from IStorage */
1652
hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1653
if (FAILED(hr))
1654
ERR("failed to get IPersistStorage\n");
1655
1656
if (ps)
1657
{
1658
IPersistStorage_Load(ps, storage);
1659
IPersistStorage_Release(ps);
1660
}
1661
1662
return return_multi_qi(obj, count, results, FALSE);
1663
}
1664
1665
/***********************************************************************
1666
* CoCreateInstance (combase.@)
1667
*/
1668
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1669
REFIID riid, void **obj)
1670
{
1671
MULTI_QI multi_qi = { .pIID = riid };
1672
HRESULT hr;
1673
1674
TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1675
1676
if (!obj)
1677
return E_POINTER;
1678
1679
hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1680
*obj = multi_qi.pItf;
1681
return hr;
1682
}
1683
1684
/***********************************************************************
1685
* CoCreateInstanceFromApp (combase.@)
1686
*/
1687
HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1688
void *server_info, ULONG count, MULTI_QI *results)
1689
{
1690
TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1691
count, results);
1692
1693
return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1694
count, results);
1695
}
1696
1697
static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1698
COSERVERINFO *server_info, REFIID riid, void **obj)
1699
{
1700
struct class_reg_data clsreg = { 0 };
1701
HRESULT hr = E_UNEXPECTED;
1702
IUnknown *registered_obj;
1703
struct apartment *apt;
1704
1705
if (!obj)
1706
return E_INVALIDARG;
1707
1708
*obj = NULL;
1709
1710
if (!(apt = apartment_get_current_or_mta()))
1711
{
1712
ERR("apartment not initialised\n");
1713
return CO_E_NOTINITIALIZED;
1714
}
1715
1716
if (server_info)
1717
FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1718
1719
if (clscontext & CLSCTX_INPROC_SERVER)
1720
{
1721
if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1722
IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1723
(!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1724
IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1725
{
1726
apartment_release(apt);
1727
1728
if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
1729
return get_builtin_class_factory(rclsid, riid, obj);
1730
else
1731
return Ole32DllGetClassObject(rclsid, riid, obj);
1732
}
1733
}
1734
1735
if (clscontext & CLSCTX_INPROC)
1736
{
1737
ACTCTX_SECTION_KEYED_DATA data;
1738
1739
data.cbSize = sizeof(data);
1740
/* search activation context first */
1741
if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1742
ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1743
{
1744
struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1745
1746
clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1747
clsreg.u.actctx.hactctx = data.hActCtx;
1748
clsreg.u.actctx.threading_model = comclass->model;
1749
clsreg.origin = CLASS_REG_ACTCTX;
1750
1751
hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1752
ReleaseActCtx(data.hActCtx);
1753
apartment_release(apt);
1754
return hr;
1755
}
1756
}
1757
1758
/*
1759
* First, try and see if we can't match the class ID with one of the
1760
* registered classes.
1761
*/
1762
if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1763
{
1764
hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1765
IUnknown_Release(registered_obj);
1766
apartment_release(apt);
1767
return hr;
1768
}
1769
1770
/* First try in-process server */
1771
if (clscontext & CLSCTX_INPROC_SERVER)
1772
{
1773
HKEY hkey;
1774
1775
hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1776
if (FAILED(hr))
1777
{
1778
if (hr == REGDB_E_CLASSNOTREG)
1779
ERR("class %s not registered\n", debugstr_guid(rclsid));
1780
else if (hr == REGDB_E_KEYMISSING)
1781
{
1782
WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1783
hr = REGDB_E_CLASSNOTREG;
1784
}
1785
}
1786
1787
if (SUCCEEDED(hr))
1788
{
1789
clsreg.u.hkey = hkey;
1790
clsreg.origin = CLASS_REG_REGISTRY;
1791
1792
hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1793
RegCloseKey(hkey);
1794
}
1795
1796
/* return if we got a class, otherwise fall through to one of the
1797
* other types */
1798
if (SUCCEEDED(hr))
1799
{
1800
apartment_release(apt);
1801
return hr;
1802
}
1803
}
1804
1805
/* Next try in-process handler */
1806
if (clscontext & CLSCTX_INPROC_HANDLER)
1807
{
1808
HKEY hkey;
1809
1810
hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1811
if (FAILED(hr))
1812
{
1813
if (hr == REGDB_E_CLASSNOTREG)
1814
ERR("class %s not registered\n", debugstr_guid(rclsid));
1815
else if (hr == REGDB_E_KEYMISSING)
1816
{
1817
WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1818
hr = REGDB_E_CLASSNOTREG;
1819
}
1820
}
1821
1822
if (SUCCEEDED(hr))
1823
{
1824
clsreg.u.hkey = hkey;
1825
clsreg.origin = CLASS_REG_REGISTRY;
1826
1827
hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1828
RegCloseKey(hkey);
1829
}
1830
1831
/* return if we got a class, otherwise fall through to one of the
1832
* other types */
1833
if (SUCCEEDED(hr))
1834
{
1835
apartment_release(apt);
1836
return hr;
1837
}
1838
}
1839
apartment_release(apt);
1840
1841
/* Next try out of process */
1842
if (clscontext & CLSCTX_LOCAL_SERVER)
1843
{
1844
hr = rpc_get_local_class_object(rclsid, riid, obj);
1845
if (SUCCEEDED(hr))
1846
return hr;
1847
}
1848
1849
/* Finally try remote: this requires networked DCOM (a lot of work) */
1850
if (clscontext & CLSCTX_REMOTE_SERVER)
1851
{
1852
FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1853
hr = REGDB_E_CLASSNOTREG;
1854
}
1855
1856
if (FAILED(hr))
1857
ERR("no class object %s could be created for context %#lx\n", debugstr_guid(rclsid), clscontext);
1858
1859
return hr;
1860
}
1861
1862
/***********************************************************************
1863
* CoCreateInstanceEx (combase.@)
1864
*/
1865
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1866
COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1867
{
1868
IClassFactory *factory;
1869
IUnknown *unk = NULL;
1870
CLSID clsid;
1871
HRESULT hr;
1872
1873
TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1874
1875
if (!count || !results)
1876
return E_INVALIDARG;
1877
1878
if (server_info)
1879
FIXME("Server info is not supported.\n");
1880
1881
init_multi_qi(count, results, E_NOINTERFACE);
1882
1883
clsid = *rclsid;
1884
if (!(cls_context & CLSCTX_APPCONTAINER))
1885
CoGetTreatAsClass(rclsid, &clsid);
1886
1887
if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1888
return hr;
1889
1890
hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1891
IClassFactory_Release(factory);
1892
if (FAILED(hr))
1893
{
1894
if (hr == CLASS_E_NOAGGREGATION && outer)
1895
FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1896
else
1897
FIXME("no instance created for interface %s of class %s, hr %#lx.\n",
1898
debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1899
return hr;
1900
}
1901
1902
return return_multi_qi(unk, count, results, TRUE);
1903
}
1904
1905
/***********************************************************************
1906
* CoGetClassObject (combase.@)
1907
*/
1908
HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1909
COSERVERINFO *server_info, REFIID riid, void **obj)
1910
{
1911
TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1912
1913
return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1914
}
1915
1916
/***********************************************************************
1917
* CoFreeUnusedLibraries (combase.@)
1918
*/
1919
void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1920
{
1921
CoFreeUnusedLibrariesEx(INFINITE, 0);
1922
}
1923
1924
/***********************************************************************
1925
* CoGetCallContext (combase.@)
1926
*/
1927
HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1928
{
1929
struct tlsdata *tlsdata;
1930
HRESULT hr;
1931
1932
TRACE("%s, %p\n", debugstr_guid(riid), obj);
1933
1934
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1935
return hr;
1936
1937
if (!tlsdata->call_state)
1938
return RPC_E_CALL_COMPLETE;
1939
1940
return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1941
}
1942
1943
/***********************************************************************
1944
* CoSwitchCallContext (combase.@)
1945
*/
1946
HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1947
{
1948
struct tlsdata *tlsdata;
1949
HRESULT hr;
1950
1951
TRACE("%p, %p\n", context, old_context);
1952
1953
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1954
return hr;
1955
1956
/* Reference counts are not touched. */
1957
*old_context = tlsdata->call_state;
1958
tlsdata->call_state = context;
1959
1960
return S_OK;
1961
}
1962
1963
/******************************************************************************
1964
* CoRegisterInitializeSpy (combase.@)
1965
*/
1966
HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1967
{
1968
struct tlsdata *tlsdata;
1969
struct init_spy *entry;
1970
unsigned int id;
1971
HRESULT hr;
1972
1973
TRACE("%p, %p\n", spy, cookie);
1974
1975
if (!spy || !cookie)
1976
return E_INVALIDARG;
1977
1978
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1979
return hr;
1980
1981
hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1982
if (FAILED(hr))
1983
return hr;
1984
1985
entry = malloc(sizeof(*entry));
1986
if (!entry)
1987
{
1988
IInitializeSpy_Release(spy);
1989
return E_OUTOFMEMORY;
1990
}
1991
1992
entry->spy = spy;
1993
1994
id = 0;
1995
while (get_spy_entry(tlsdata, id) != NULL)
1996
{
1997
id++;
1998
}
1999
2000
entry->id = id;
2001
list_add_head(&tlsdata->spies, &entry->entry);
2002
2003
cookie->u.HighPart = GetCurrentThreadId();
2004
cookie->u.LowPart = entry->id;
2005
2006
return S_OK;
2007
}
2008
2009
/******************************************************************************
2010
* CoRevokeInitializeSpy (combase.@)
2011
*/
2012
HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
2013
{
2014
struct tlsdata *tlsdata;
2015
struct init_spy *spy;
2016
HRESULT hr;
2017
2018
TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
2019
2020
if (cookie.u.HighPart != GetCurrentThreadId())
2021
return E_INVALIDARG;
2022
2023
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2024
return hr;
2025
2026
if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
2027
2028
IInitializeSpy_Release(spy->spy);
2029
spy->spy = NULL;
2030
if (!tlsdata->spies_lock)
2031
{
2032
list_remove(&spy->entry);
2033
free(spy);
2034
}
2035
return S_OK;
2036
}
2037
2038
static BOOL com_peek_message(struct apartment *apt, MSG *msg)
2039
{
2040
/* First try to retrieve messages for incoming COM calls to the apartment window */
2041
return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
2042
/* Next retrieve other messages necessary for the app to remain responsive */
2043
PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
2044
PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
2045
}
2046
2047
/***********************************************************************
2048
* CoWaitForMultipleHandles (combase.@)
2049
*/
2050
HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
2051
DWORD *index)
2052
{
2053
BOOL check_apc = !!(flags & COWAIT_ALERTABLE), message_loop;
2054
struct { BOOL post; UINT code; } quit = { .post = FALSE };
2055
DWORD start_time, wait_flags = 0;
2056
struct tlsdata *tlsdata;
2057
struct apartment *apt;
2058
HRESULT hr;
2059
2060
TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index);
2061
2062
if (!index)
2063
return E_INVALIDARG;
2064
2065
*index = 0;
2066
2067
if (!handles)
2068
return E_INVALIDARG;
2069
2070
if (!handle_count)
2071
return RPC_E_NO_SYNC;
2072
2073
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2074
return hr;
2075
2076
apt = com_get_current_apt();
2077
message_loop = apt && !apt->multi_threaded;
2078
2079
if (flags & COWAIT_WAITALL)
2080
wait_flags |= MWMO_WAITALL;
2081
if (flags & COWAIT_ALERTABLE)
2082
wait_flags |= MWMO_ALERTABLE;
2083
2084
start_time = GetTickCount();
2085
2086
while (TRUE)
2087
{
2088
DWORD now = GetTickCount(), res;
2089
2090
if (now - start_time > timeout)
2091
{
2092
hr = RPC_S_CALLPENDING;
2093
break;
2094
}
2095
2096
if (message_loop)
2097
{
2098
TRACE("waiting for rpc completion or window message\n");
2099
2100
res = WAIT_TIMEOUT;
2101
2102
if (check_apc)
2103
{
2104
res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
2105
check_apc = FALSE;
2106
}
2107
2108
if (res == WAIT_TIMEOUT)
2109
res = MsgWaitForMultipleObjectsEx(handle_count, handles,
2110
timeout == INFINITE ? INFINITE : start_time + timeout - now,
2111
QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
2112
2113
if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
2114
{
2115
int msg_count = 0;
2116
MSG msg;
2117
2118
/* call message filter */
2119
2120
if (apt->filter)
2121
{
2122
PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
2123
DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
2124
2125
TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled);
2126
2127
switch (be_handled)
2128
{
2129
case PENDINGMSG_CANCELCALL:
2130
WARN("call canceled\n");
2131
hr = RPC_E_CALL_CANCELED;
2132
break;
2133
case PENDINGMSG_WAITNOPROCESS:
2134
case PENDINGMSG_WAITDEFPROCESS:
2135
default:
2136
/* FIXME: MSDN is very vague about the difference
2137
* between WAITNOPROCESS and WAITDEFPROCESS - there
2138
* appears to be none, so it is possibly a left-over
2139
* from the 16-bit world. */
2140
break;
2141
}
2142
}
2143
2144
if (!apt->win)
2145
{
2146
/* If window is NULL on apartment, peek at messages so that it will not trigger
2147
* MsgWaitForMultipleObjects next time. */
2148
PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
2149
}
2150
2151
/* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
2152
* so after processing 100 messages we go back to checking the wait handles */
2153
while (msg_count++ < 100 && com_peek_message(apt, &msg))
2154
{
2155
if (msg.message == WM_QUIT)
2156
{
2157
TRACE("Received WM_QUIT message\n");
2158
quit.post = TRUE;
2159
quit.code = msg.wParam;
2160
}
2161
else
2162
{
2163
TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2164
TranslateMessage(&msg);
2165
DispatchMessageW(&msg);
2166
}
2167
}
2168
continue;
2169
}
2170
}
2171
else
2172
{
2173
TRACE("Waiting for rpc completion\n");
2174
2175
res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2176
(timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2177
}
2178
2179
switch (res)
2180
{
2181
case WAIT_TIMEOUT:
2182
hr = RPC_S_CALLPENDING;
2183
break;
2184
case WAIT_FAILED:
2185
hr = HRESULT_FROM_WIN32(GetLastError());
2186
break;
2187
default:
2188
*index = res;
2189
break;
2190
}
2191
break;
2192
}
2193
if (quit.post) PostQuitMessage(quit.code);
2194
2195
TRACE("-- %#lx\n", hr);
2196
2197
return hr;
2198
}
2199
2200
/******************************************************************************
2201
* CoRegisterMessageFilter (combase.@)
2202
*/
2203
HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2204
{
2205
IMessageFilter *old_filter;
2206
struct apartment *apt;
2207
2208
TRACE("%p, %p\n", filter, ret_filter);
2209
2210
apt = com_get_current_apt();
2211
2212
/* Can't set a message filter in a multi-threaded apartment */
2213
if (!apt || apt->multi_threaded)
2214
{
2215
WARN("Can't set message filter in MTA or uninitialized apt\n");
2216
return CO_E_NOT_SUPPORTED;
2217
}
2218
2219
if (filter)
2220
IMessageFilter_AddRef(filter);
2221
2222
EnterCriticalSection(&apt->cs);
2223
2224
old_filter = apt->filter;
2225
apt->filter = filter;
2226
2227
LeaveCriticalSection(&apt->cs);
2228
2229
if (ret_filter)
2230
*ret_filter = old_filter;
2231
else if (old_filter)
2232
IMessageFilter_Release(old_filter);
2233
2234
return S_OK;
2235
}
2236
2237
static void com_revoke_all_ps_clsids(void)
2238
{
2239
struct registered_ps *cur, *cur2;
2240
2241
EnterCriticalSection(&cs_registered_ps);
2242
2243
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2244
{
2245
list_remove(&cur->entry);
2246
free(cur);
2247
}
2248
2249
LeaveCriticalSection(&cs_registered_ps);
2250
}
2251
2252
static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2253
{
2254
WCHAR value[CHARS_IN_GUID];
2255
HKEY hkey;
2256
DWORD len;
2257
2258
access |= KEY_READ;
2259
2260
if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2261
return REGDB_E_IIDNOTREG;
2262
2263
len = sizeof(value);
2264
if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2265
return REGDB_E_IIDNOTREG;
2266
RegCloseKey(hkey);
2267
2268
if (CLSIDFromString(value, pclsid) != NOERROR)
2269
return REGDB_E_IIDNOTREG;
2270
2271
return S_OK;
2272
}
2273
2274
/*****************************************************************************
2275
* CoGetPSClsid (combase.@)
2276
*/
2277
HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2278
{
2279
static const WCHAR interfaceW[] = L"Interface\\";
2280
static const WCHAR psW[] = L"\\ProxyStubClsid32";
2281
WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2282
ACTCTX_SECTION_KEYED_DATA data;
2283
struct registered_ps *cur;
2284
REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2285
BOOL is_wow64;
2286
HRESULT hr;
2287
2288
TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2289
2290
if (!InternalIsProcessInitialized())
2291
{
2292
ERR("apartment not initialised\n");
2293
return CO_E_NOTINITIALIZED;
2294
}
2295
2296
if (!pclsid)
2297
return E_INVALIDARG;
2298
2299
EnterCriticalSection(&cs_registered_ps);
2300
2301
LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2302
{
2303
if (IsEqualIID(&cur->iid, riid))
2304
{
2305
*pclsid = cur->clsid;
2306
LeaveCriticalSection(&cs_registered_ps);
2307
return S_OK;
2308
}
2309
}
2310
2311
LeaveCriticalSection(&cs_registered_ps);
2312
2313
data.cbSize = sizeof(data);
2314
if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2315
riid, &data))
2316
{
2317
struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2318
*pclsid = ifaceps->iid;
2319
return S_OK;
2320
}
2321
2322
/* Interface\\{string form of riid}\\ProxyStubClsid32 */
2323
lstrcpyW(path, interfaceW);
2324
StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2325
lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2326
2327
hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid);
2328
if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2329
hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid);
2330
2331
if (hr == S_OK)
2332
TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2333
else
2334
WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2335
2336
return hr;
2337
}
2338
2339
/*****************************************************************************
2340
* CoRegisterPSClsid (combase.@)
2341
*/
2342
HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2343
{
2344
struct registered_ps *cur;
2345
2346
TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2347
2348
if (!InternalIsProcessInitialized())
2349
{
2350
ERR("apartment not initialised\n");
2351
return CO_E_NOTINITIALIZED;
2352
}
2353
2354
EnterCriticalSection(&cs_registered_ps);
2355
2356
LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2357
{
2358
if (IsEqualIID(&cur->iid, riid))
2359
{
2360
cur->clsid = *rclsid;
2361
LeaveCriticalSection(&cs_registered_ps);
2362
return S_OK;
2363
}
2364
}
2365
2366
cur = malloc(sizeof(*cur));
2367
if (!cur)
2368
{
2369
LeaveCriticalSection(&cs_registered_ps);
2370
return E_OUTOFMEMORY;
2371
}
2372
2373
cur->iid = *riid;
2374
cur->clsid = *rclsid;
2375
list_add_head(&registered_proxystubs, &cur->entry);
2376
2377
LeaveCriticalSection(&cs_registered_ps);
2378
2379
return S_OK;
2380
}
2381
2382
struct thread_context
2383
{
2384
IComThreadingInfo IComThreadingInfo_iface;
2385
IContextCallback IContextCallback_iface;
2386
IObjContext IObjContext_iface;
2387
LONG refcount;
2388
};
2389
2390
static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2391
{
2392
return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2393
}
2394
2395
static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2396
{
2397
return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2398
}
2399
2400
static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2401
{
2402
return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2403
}
2404
2405
static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2406
{
2407
struct thread_context *context = impl_from_IComThreadingInfo(iface);
2408
2409
*obj = NULL;
2410
2411
if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2412
IsEqualIID(riid, &IID_IUnknown))
2413
{
2414
*obj = &context->IComThreadingInfo_iface;
2415
}
2416
else if (IsEqualIID(riid, &IID_IContextCallback))
2417
{
2418
*obj = &context->IContextCallback_iface;
2419
}
2420
else if (IsEqualIID(riid, &IID_IObjContext))
2421
{
2422
*obj = &context->IObjContext_iface;
2423
}
2424
2425
if (*obj)
2426
{
2427
IUnknown_AddRef((IUnknown *)*obj);
2428
return S_OK;
2429
}
2430
2431
FIXME("interface not implemented %s\n", debugstr_guid(riid));
2432
return E_NOINTERFACE;
2433
}
2434
2435
static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2436
{
2437
struct thread_context *context = impl_from_IComThreadingInfo(iface);
2438
return InterlockedIncrement(&context->refcount);
2439
}
2440
2441
static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2442
{
2443
struct thread_context *context = impl_from_IComThreadingInfo(iface);
2444
2445
/* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2446
releasing context while refcount is at 0 destroys it. */
2447
if (!context->refcount)
2448
{
2449
free(context);
2450
return 0;
2451
}
2452
2453
return InterlockedDecrement(&context->refcount);
2454
}
2455
2456
static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2457
{
2458
APTTYPEQUALIFIER qualifier;
2459
2460
TRACE("%p\n", apttype);
2461
2462
return CoGetApartmentType(apttype, &qualifier);
2463
}
2464
2465
static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2466
{
2467
APTTYPEQUALIFIER qualifier;
2468
APTTYPE apttype;
2469
HRESULT hr;
2470
2471
hr = CoGetApartmentType(&apttype, &qualifier);
2472
if (FAILED(hr))
2473
return hr;
2474
2475
TRACE("%p\n", thdtype);
2476
2477
switch (apttype)
2478
{
2479
case APTTYPE_STA:
2480
case APTTYPE_MAINSTA:
2481
*thdtype = THDTYPE_PROCESSMESSAGES;
2482
break;
2483
default:
2484
*thdtype = THDTYPE_BLOCKMESSAGES;
2485
break;
2486
}
2487
return S_OK;
2488
}
2489
2490
static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2491
{
2492
TRACE("%p\n", logical_thread_id);
2493
2494
return CoGetCurrentLogicalThreadId(logical_thread_id);
2495
}
2496
2497
static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2498
{
2499
FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2500
2501
return E_NOTIMPL;
2502
}
2503
2504
static const IComThreadingInfoVtbl thread_context_info_vtbl =
2505
{
2506
thread_context_info_QueryInterface,
2507
thread_context_info_AddRef,
2508
thread_context_info_Release,
2509
thread_context_info_GetCurrentApartmentType,
2510
thread_context_info_GetCurrentThreadType,
2511
thread_context_info_GetCurrentLogicalThreadId,
2512
thread_context_info_SetCurrentLogicalThreadId
2513
};
2514
2515
static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2516
{
2517
struct thread_context *context = impl_from_IContextCallback(iface);
2518
return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2519
}
2520
2521
static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2522
{
2523
struct thread_context *context = impl_from_IContextCallback(iface);
2524
return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2525
}
2526
2527
static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2528
{
2529
struct thread_context *context = impl_from_IContextCallback(iface);
2530
return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2531
}
2532
2533
static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2534
PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2535
{
2536
FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2537
2538
return E_NOTIMPL;
2539
}
2540
2541
static const IContextCallbackVtbl thread_context_callback_vtbl =
2542
{
2543
thread_context_callback_QueryInterface,
2544
thread_context_callback_AddRef,
2545
thread_context_callback_Release,
2546
thread_context_callback_ContextCallback
2547
};
2548
2549
static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2550
{
2551
struct thread_context *context = impl_from_IObjContext(iface);
2552
return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2553
}
2554
2555
static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2556
{
2557
struct thread_context *context = impl_from_IObjContext(iface);
2558
return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2559
}
2560
2561
static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2562
{
2563
struct thread_context *context = impl_from_IObjContext(iface);
2564
return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2565
}
2566
2567
static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2568
{
2569
FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk);
2570
2571
return E_NOTIMPL;
2572
}
2573
2574
static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2575
{
2576
FIXME("%p, %s\n", iface, debugstr_guid(propid));
2577
2578
return E_NOTIMPL;
2579
}
2580
2581
static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2582
{
2583
FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2584
2585
return E_NOTIMPL;
2586
}
2587
2588
static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2589
{
2590
FIXME("%p, %p\n", iface, props);
2591
2592
return E_NOTIMPL;
2593
}
2594
2595
static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2596
{
2597
FIXME("%p\n", iface);
2598
}
2599
2600
static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2601
{
2602
FIXME("%p\n", iface);
2603
}
2604
2605
static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2606
{
2607
FIXME("%p\n", iface);
2608
}
2609
2610
static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2611
{
2612
FIXME("%p\n", iface);
2613
}
2614
2615
static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2616
{
2617
FIXME("%p\n", iface);
2618
}
2619
2620
static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2621
{
2622
FIXME("%p\n", iface);
2623
}
2624
2625
static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2626
{
2627
FIXME("%p\n", iface);
2628
}
2629
2630
static const IObjContextVtbl thread_object_context_vtbl =
2631
{
2632
thread_object_context_QueryInterface,
2633
thread_object_context_AddRef,
2634
thread_object_context_Release,
2635
thread_object_context_SetProperty,
2636
thread_object_context_RemoveProperty,
2637
thread_object_context_GetProperty,
2638
thread_object_context_EnumContextProps,
2639
thread_object_context_Reserved1,
2640
thread_object_context_Reserved2,
2641
thread_object_context_Reserved3,
2642
thread_object_context_Reserved4,
2643
thread_object_context_Reserved5,
2644
thread_object_context_Reserved6,
2645
thread_object_context_Reserved7
2646
};
2647
2648
/***********************************************************************
2649
* CoGetContextToken (combase.@)
2650
*/
2651
HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2652
{
2653
struct tlsdata *tlsdata;
2654
HRESULT hr;
2655
2656
TRACE("%p\n", token);
2657
2658
if (!InternalIsProcessInitialized())
2659
{
2660
ERR("apartment not initialised\n");
2661
return CO_E_NOTINITIALIZED;
2662
}
2663
2664
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2665
return hr;
2666
2667
if (!token)
2668
return E_POINTER;
2669
2670
if (!tlsdata->context_token)
2671
{
2672
struct thread_context *context;
2673
2674
context = calloc(1, sizeof(*context));
2675
if (!context)
2676
return E_OUTOFMEMORY;
2677
2678
context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2679
context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2680
context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2681
/* Context token does not take a reference, it's always zero until the
2682
interface is explicitly requested with CoGetObjectContext(). */
2683
context->refcount = 0;
2684
2685
tlsdata->context_token = &context->IObjContext_iface;
2686
}
2687
2688
*token = (ULONG_PTR)tlsdata->context_token;
2689
TRACE("context_token %p\n", tlsdata->context_token);
2690
2691
return S_OK;
2692
}
2693
2694
/***********************************************************************
2695
* CoGetCurrentLogicalThreadId (combase.@)
2696
*/
2697
HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2698
{
2699
struct tlsdata *tlsdata;
2700
HRESULT hr;
2701
2702
if (!id)
2703
return E_INVALIDARG;
2704
2705
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2706
return hr;
2707
2708
if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2709
{
2710
CoCreateGuid(&tlsdata->causality_id);
2711
tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2712
}
2713
2714
*id = tlsdata->causality_id;
2715
2716
return S_OK;
2717
}
2718
2719
/******************************************************************************
2720
* CoGetCurrentProcess (combase.@)
2721
*/
2722
DWORD WINAPI CoGetCurrentProcess(void)
2723
{
2724
struct tlsdata *tlsdata;
2725
2726
if (FAILED(com_get_tlsdata(&tlsdata)))
2727
return 0;
2728
2729
if (!tlsdata->thread_seqid)
2730
rpcss_get_next_seqid(&tlsdata->thread_seqid);
2731
2732
return tlsdata->thread_seqid;
2733
}
2734
2735
/***********************************************************************
2736
* CoFreeUnusedLibrariesEx (combase.@)
2737
*/
2738
void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2739
{
2740
struct apartment *apt = com_get_current_apt();
2741
if (!apt)
2742
{
2743
ERR("apartment not initialised\n");
2744
return;
2745
}
2746
2747
apartment_freeunusedlibraries(apt, unload_delay);
2748
}
2749
2750
/*
2751
* When locked, don't modify list (unless we add a new head), so that it's
2752
* safe to iterate it. Freeing of list entries is delayed and done on unlock.
2753
*/
2754
static inline void lock_init_spies(struct tlsdata *tlsdata)
2755
{
2756
tlsdata->spies_lock++;
2757
}
2758
2759
static void unlock_init_spies(struct tlsdata *tlsdata)
2760
{
2761
struct init_spy *spy, *next;
2762
2763
if (--tlsdata->spies_lock) return;
2764
2765
LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2766
{
2767
if (spy->spy) continue;
2768
list_remove(&spy->entry);
2769
free(spy);
2770
}
2771
}
2772
2773
/******************************************************************************
2774
* CoInitializeWOW (combase.@)
2775
*/
2776
HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2777
{
2778
FIXME("%#lx, %#lx\n", arg1, arg2);
2779
2780
return S_OK;
2781
}
2782
2783
/******************************************************************************
2784
* CoInitializeEx (combase.@)
2785
*/
2786
HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2787
{
2788
struct tlsdata *tlsdata;
2789
struct init_spy *cursor;
2790
HRESULT hr;
2791
2792
TRACE("%p, %#lx\n", reserved, model);
2793
2794
if (reserved)
2795
WARN("Unexpected reserved argument %p\n", reserved);
2796
2797
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2798
return hr;
2799
2800
if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2801
TRACE("Initializing the COM libraries\n");
2802
2803
lock_init_spies(tlsdata);
2804
LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2805
{
2806
if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2807
}
2808
unlock_init_spies(tlsdata);
2809
2810
hr = enter_apartment(tlsdata, model);
2811
2812
lock_init_spies(tlsdata);
2813
LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2814
{
2815
if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2816
}
2817
unlock_init_spies(tlsdata);
2818
2819
return hr;
2820
}
2821
2822
/***********************************************************************
2823
* CoUninitialize (combase.@)
2824
*/
2825
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2826
{
2827
struct tlsdata *tlsdata;
2828
struct init_spy *cursor, *next;
2829
LONG lockcount;
2830
2831
TRACE("\n");
2832
2833
if (FAILED(com_get_tlsdata(&tlsdata)))
2834
return;
2835
2836
lock_init_spies(tlsdata);
2837
LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2838
{
2839
if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2840
}
2841
unlock_init_spies(tlsdata);
2842
2843
/* sanity check */
2844
if (!tlsdata->inits)
2845
{
2846
ERR("Mismatched CoUninitialize\n");
2847
2848
lock_init_spies(tlsdata);
2849
LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2850
{
2851
if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2852
}
2853
unlock_init_spies(tlsdata);
2854
2855
return;
2856
}
2857
2858
leave_apartment(tlsdata);
2859
2860
/*
2861
* Decrease the reference count.
2862
* If we are back to 0 locks on the COM library, make sure we free
2863
* all the associated data structures.
2864
*/
2865
lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2866
if (lockcount == 1)
2867
{
2868
TRACE("Releasing the COM libraries\n");
2869
2870
com_revoke_all_ps_clsids();
2871
DestroyRunningObjectTable();
2872
}
2873
else if (lockcount < 1)
2874
{
2875
ERR("Unbalanced lock count %ld\n", lockcount);
2876
InterlockedExchangeAdd(&com_lockcount, 1);
2877
}
2878
2879
lock_init_spies(tlsdata);
2880
LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2881
{
2882
if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2883
}
2884
unlock_init_spies(tlsdata);
2885
}
2886
2887
/***********************************************************************
2888
* CoIncrementMTAUsage (combase.@)
2889
*/
2890
HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2891
{
2892
TRACE("%p\n", cookie);
2893
2894
return apartment_increment_mta_usage(cookie);
2895
}
2896
2897
/***********************************************************************
2898
* CoDecrementMTAUsage (combase.@)
2899
*/
2900
HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2901
{
2902
TRACE("%p\n", cookie);
2903
2904
apartment_decrement_mta_usage(cookie);
2905
return S_OK;
2906
}
2907
2908
/***********************************************************************
2909
* CoGetApartmentType (combase.@)
2910
*/
2911
HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2912
{
2913
struct tlsdata *tlsdata;
2914
struct apartment *apt;
2915
HRESULT hr;
2916
2917
TRACE("%p, %p\n", type, qualifier);
2918
2919
if (!type || !qualifier)
2920
return E_INVALIDARG;
2921
2922
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2923
return hr;
2924
2925
if (!tlsdata->apt)
2926
*type = APTTYPE_CURRENT;
2927
else if (tlsdata->apt->multi_threaded)
2928
*type = APTTYPE_MTA;
2929
else if (tlsdata->apt->main)
2930
*type = APTTYPE_MAINSTA;
2931
else
2932
*type = APTTYPE_STA;
2933
2934
*qualifier = APTTYPEQUALIFIER_NONE;
2935
2936
if (!tlsdata->apt && (apt = apartment_get_mta()))
2937
{
2938
apartment_release(apt);
2939
*type = APTTYPE_MTA;
2940
*qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2941
return S_OK;
2942
}
2943
2944
return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2945
}
2946
2947
/******************************************************************************
2948
* CoRegisterClassObject (combase.@)
2949
* BUGS
2950
* MSDN claims that multiple interface registrations are legal, but we
2951
* can't do that with our current implementation.
2952
*/
2953
HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2954
DWORD flags, DWORD *cookie)
2955
{
2956
static LONG next_cookie;
2957
2958
struct registered_class *newclass;
2959
IUnknown *found_object;
2960
struct apartment *apt;
2961
HRESULT hr = S_OK;
2962
2963
TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2964
2965
if (!cookie || !object)
2966
return E_INVALIDARG;
2967
2968
if (!(apt = apartment_get_current_or_mta()))
2969
{
2970
ERR("COM was not initialized\n");
2971
return CO_E_NOTINITIALIZED;
2972
}
2973
2974
*cookie = 0;
2975
2976
/* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2977
* differentiates the flag from REGCLS_MULTI_SEPARATE. */
2978
if (flags & REGCLS_MULTIPLEUSE)
2979
clscontext |= CLSCTX_INPROC_SERVER;
2980
2981
/*
2982
* First, check if the class is already registered.
2983
* If it is, this should cause an error.
2984
*/
2985
if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2986
{
2987
if (flags & REGCLS_MULTIPLEUSE)
2988
{
2989
if (clscontext & CLSCTX_LOCAL_SERVER)
2990
hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2991
IUnknown_Release(found_object);
2992
apartment_release(apt);
2993
return hr;
2994
}
2995
2996
IUnknown_Release(found_object);
2997
ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2998
apartment_release(apt);
2999
return CO_E_OBJISREG;
3000
}
3001
3002
newclass = calloc(1, sizeof(*newclass));
3003
if (!newclass)
3004
{
3005
apartment_release(apt);
3006
return E_OUTOFMEMORY;
3007
}
3008
3009
newclass->clsid = *rclsid;
3010
newclass->apartment_id = apt->oxid;
3011
newclass->clscontext = clscontext;
3012
newclass->flags = flags;
3013
3014
if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
3015
newclass->cookie = InterlockedIncrement(&next_cookie);
3016
3017
newclass->object = object;
3018
IUnknown_AddRef(newclass->object);
3019
3020
EnterCriticalSection(&registered_classes_cs);
3021
list_add_tail(&registered_classes, &newclass->entry);
3022
LeaveCriticalSection(&registered_classes_cs);
3023
3024
*cookie = newclass->cookie;
3025
3026
if (clscontext & CLSCTX_LOCAL_SERVER)
3027
{
3028
IStream *marshal_stream;
3029
3030
hr = apartment_get_local_server_stream(apt, &marshal_stream);
3031
if(FAILED(hr))
3032
{
3033
apartment_release(apt);
3034
return hr;
3035
}
3036
3037
hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
3038
IStream_Release(marshal_stream);
3039
}
3040
3041
apartment_release(apt);
3042
return S_OK;
3043
}
3044
3045
static void com_revoke_class_object(struct registered_class *entry)
3046
{
3047
list_remove(&entry->entry);
3048
3049
if (entry->clscontext & CLSCTX_LOCAL_SERVER)
3050
rpc_revoke_local_server(entry->rpcss_cookie);
3051
3052
IUnknown_Release(entry->object);
3053
free(entry);
3054
}
3055
3056
/* Cleans up rpcss registry */
3057
static void com_revoke_local_servers(void)
3058
{
3059
struct registered_class *cur, *cur2;
3060
3061
EnterCriticalSection(&registered_classes_cs);
3062
3063
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3064
{
3065
if (cur->clscontext & CLSCTX_LOCAL_SERVER)
3066
com_revoke_class_object(cur);
3067
}
3068
3069
LeaveCriticalSection(&registered_classes_cs);
3070
}
3071
3072
void apartment_revoke_all_classes(const struct apartment *apt)
3073
{
3074
struct registered_class *cur, *cur2;
3075
3076
EnterCriticalSection(&registered_classes_cs);
3077
3078
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3079
{
3080
if (cur->apartment_id == apt->oxid)
3081
com_revoke_class_object(cur);
3082
}
3083
3084
LeaveCriticalSection(&registered_classes_cs);
3085
}
3086
3087
/***********************************************************************
3088
* CoRevokeClassObject (combase.@)
3089
*/
3090
HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
3091
{
3092
HRESULT hr = E_INVALIDARG;
3093
struct registered_class *cur;
3094
struct apartment *apt;
3095
3096
TRACE("%#lx\n", cookie);
3097
3098
if (!(apt = apartment_get_current_or_mta()))
3099
{
3100
ERR("COM was not initialized\n");
3101
return CO_E_NOTINITIALIZED;
3102
}
3103
3104
EnterCriticalSection(&registered_classes_cs);
3105
3106
LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
3107
{
3108
if (cur->cookie != cookie)
3109
continue;
3110
3111
if (cur->apartment_id == apt->oxid)
3112
{
3113
com_revoke_class_object(cur);
3114
hr = S_OK;
3115
}
3116
else
3117
{
3118
ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
3119
hr = RPC_E_WRONG_THREAD;
3120
}
3121
3122
break;
3123
}
3124
3125
LeaveCriticalSection(&registered_classes_cs);
3126
apartment_release(apt);
3127
3128
return hr;
3129
}
3130
3131
/***********************************************************************
3132
* CoAddRefServerProcess (combase.@)
3133
*/
3134
ULONG WINAPI CoAddRefServerProcess(void)
3135
{
3136
ULONG refs;
3137
3138
TRACE("\n");
3139
3140
EnterCriticalSection(&registered_classes_cs);
3141
refs = ++com_server_process_refcount;
3142
LeaveCriticalSection(&registered_classes_cs);
3143
3144
TRACE("refs before: %ld\n", refs - 1);
3145
3146
return refs;
3147
}
3148
3149
/***********************************************************************
3150
* CoReleaseServerProcess [OLE32.@]
3151
*/
3152
ULONG WINAPI CoReleaseServerProcess(void)
3153
{
3154
ULONG refs;
3155
3156
TRACE("\n");
3157
3158
EnterCriticalSection(&registered_classes_cs);
3159
3160
refs = --com_server_process_refcount;
3161
/* FIXME: suspend objects */
3162
3163
LeaveCriticalSection(&registered_classes_cs);
3164
3165
TRACE("refs after: %ld\n", refs);
3166
3167
return refs;
3168
}
3169
3170
/******************************************************************************
3171
* CoDisconnectObject (combase.@)
3172
*/
3173
HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3174
{
3175
struct stub_manager *manager;
3176
struct apartment *apt;
3177
IMarshal *marshal;
3178
HRESULT hr;
3179
3180
TRACE("%p, %#lx\n", object, reserved);
3181
3182
if (!object)
3183
return E_INVALIDARG;
3184
3185
hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3186
if (hr == S_OK)
3187
{
3188
hr = IMarshal_DisconnectObject(marshal, reserved);
3189
IMarshal_Release(marshal);
3190
return hr;
3191
}
3192
3193
if (!(apt = apartment_get_current_or_mta()))
3194
{
3195
ERR("apartment not initialised\n");
3196
return CO_E_NOTINITIALIZED;
3197
}
3198
3199
manager = get_stub_manager_from_object(apt, object, FALSE);
3200
if (manager)
3201
{
3202
stub_manager_disconnect(manager);
3203
/* Release stub manager twice, to remove the apartment reference. */
3204
stub_manager_int_release(manager);
3205
stub_manager_int_release(manager);
3206
}
3207
3208
/* Note: native is pretty broken here because it just silently
3209
* fails, without returning an appropriate error code if the object was
3210
* not found, making apps think that the object was disconnected, when
3211
* it actually wasn't */
3212
3213
apartment_release(apt);
3214
return S_OK;
3215
}
3216
3217
/******************************************************************************
3218
* CoLockObjectExternal (combase.@)
3219
*/
3220
HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3221
{
3222
struct stub_manager *stubmgr;
3223
struct apartment *apt;
3224
3225
TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3226
3227
if (!(apt = apartment_get_current_or_mta()))
3228
{
3229
ERR("apartment not initialised\n");
3230
return CO_E_NOTINITIALIZED;
3231
}
3232
3233
stubmgr = get_stub_manager_from_object(apt, object, lock);
3234
if (!stubmgr)
3235
{
3236
WARN("stub object not found %p\n", object);
3237
/* Note: native is pretty broken here because it just silently
3238
* fails, without returning an appropriate error code, making apps
3239
* think that the object was disconnected, when it actually wasn't */
3240
apartment_release(apt);
3241
return S_OK;
3242
}
3243
3244
if (lock)
3245
stub_manager_ext_addref(stubmgr, 1, FALSE);
3246
else
3247
stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3248
3249
stub_manager_int_release(stubmgr);
3250
apartment_release(apt);
3251
return S_OK;
3252
}
3253
3254
/***********************************************************************
3255
* CoRegisterChannelHook (combase.@)
3256
*/
3257
HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3258
{
3259
TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3260
3261
return rpc_register_channel_hook(guidExtension, channel_hook);
3262
}
3263
3264
/***********************************************************************
3265
* CoDisableCallCancellation (combase.@)
3266
*/
3267
HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3268
{
3269
struct tlsdata *tlsdata;
3270
HRESULT hr;
3271
3272
TRACE("%p\n", reserved);
3273
3274
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3275
return hr;
3276
3277
if (!tlsdata->cancelcount)
3278
return CO_E_CANCEL_DISABLED;
3279
3280
tlsdata->cancelcount--;
3281
3282
return S_OK;
3283
}
3284
3285
/***********************************************************************
3286
* CoEnableCallCancellation (combase.@)
3287
*/
3288
HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3289
{
3290
struct tlsdata *tlsdata;
3291
HRESULT hr;
3292
3293
TRACE("%p\n", reserved);
3294
3295
if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3296
return hr;
3297
3298
tlsdata->cancelcount++;
3299
3300
return S_OK;
3301
}
3302
3303
/***********************************************************************
3304
* CoGetCallerTID (combase.@)
3305
*/
3306
HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3307
{
3308
FIXME("stub!\n");
3309
return E_NOTIMPL;
3310
}
3311
3312
/***********************************************************************
3313
* CoIsHandlerConnected (combase.@)
3314
*/
3315
BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3316
{
3317
FIXME("%p\n", object);
3318
3319
return TRUE;
3320
}
3321
3322
/***********************************************************************
3323
* CoSuspendClassObjects (combase.@)
3324
*/
3325
HRESULT WINAPI CoSuspendClassObjects(void)
3326
{
3327
FIXME("\n");
3328
3329
return S_OK;
3330
}
3331
3332
/***********************************************************************
3333
* CoResumeClassObjects (combase.@)
3334
*/
3335
HRESULT WINAPI CoResumeClassObjects(void)
3336
{
3337
FIXME("stub\n");
3338
3339
return S_OK;
3340
}
3341
3342
/***********************************************************************
3343
* CoRegisterSurrogate (combase.@)
3344
*/
3345
HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3346
{
3347
FIXME("%p stub\n", surrogate);
3348
3349
return E_NOTIMPL;
3350
}
3351
3352
/***********************************************************************
3353
* CoRegisterSurrogateEx (combase.@)
3354
*/
3355
HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3356
{
3357
FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3358
3359
return E_NOTIMPL;
3360
}
3361
3362
/***********************************************************************
3363
* DllMain (combase.@)
3364
*/
3365
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3366
{
3367
TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved);
3368
3369
switch (reason)
3370
{
3371
case DLL_PROCESS_ATTACH:
3372
hProxyDll = hinstDLL;
3373
break;
3374
case DLL_PROCESS_DETACH:
3375
com_revoke_local_servers();
3376
if (reserved) break;
3377
apartment_global_cleanup();
3378
DeleteCriticalSection(&registered_classes_cs);
3379
rpc_unregister_channel_hooks();
3380
break;
3381
case DLL_THREAD_DETACH:
3382
com_cleanup_tlsdata();
3383
break;
3384
}
3385
3386
return TRUE;
3387
}
3388
3389
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj)
3390
{
3391
TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj);
3392
3393
*obj = NULL;
3394
3395
if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3396
return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
3397
3398
return CLASS_E_CLASSNOTAVAILABLE;
3399
}
3400
3401