include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / combase / combase.c
blobe072c1699532b01f5c2b0d4be546374b14728c96
1 /*
2 * Copyright 2005 Juan Lang
3 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
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.
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.
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
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"
30 #include "combase_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36 HINSTANCE hProxyDll;
38 static ULONG_PTR global_options[COMGLB_PROPERTIES_RESERVED3 + 1];
40 /* Ole32 exports */
41 extern void WINAPI DestroyRunningObjectTable(void);
42 extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
45 * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
47 static LONG com_lockcount;
49 static LONG com_server_process_refcount;
51 struct comclassredirect_data
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;
73 struct ifacepsredirect_data
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;
85 struct progidredirect_data
87 ULONG size;
88 DWORD reserved;
89 ULONG clsid_offset;
92 struct init_spy
94 struct list entry;
95 IInitializeSpy *spy;
96 unsigned int id;
99 struct registered_ps
101 struct list entry;
102 IID iid;
103 CLSID clsid;
106 static struct list registered_proxystubs = LIST_INIT(registered_proxystubs);
108 static CRITICAL_SECTION cs_registered_ps;
109 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
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") }
115 static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
117 struct registered_class
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;
129 static struct list registered_classes = LIST_INIT(registered_classes);
131 static CRITICAL_SECTION registered_classes_cs;
132 static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
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") }
138 static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
140 IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
142 struct registered_class *cur;
143 IUnknown *object = NULL;
145 EnterCriticalSection(&registered_classes_cs);
147 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
149 if ((apt->oxid == cur->apartment_id) &&
150 (clscontext & cur->clscontext) &&
151 IsEqualGUID(&cur->clsid, rclsid))
153 object = cur->object;
154 IUnknown_AddRef(cur->object);
155 break;
159 LeaveCriticalSection(&registered_classes_cs);
161 return object;
164 static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
166 struct init_spy *spy;
168 LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry)
170 if (id == spy->id && spy->spy)
171 return spy;
174 return NULL;
177 static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
179 NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
181 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
183 HANDLE subkey, root = attr->RootDirectory;
184 WCHAR *buffer = attr->ObjectName->Buffer;
185 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
186 UNICODE_STRING str;
188 while (i < len && buffer[i] != '\\') i++;
189 if (i == len) return status;
191 attrs = attr->Attributes;
192 attr->ObjectName = &str;
194 while (i < len)
196 str.Buffer = buffer + pos;
197 str.Length = (i - pos) * sizeof(WCHAR);
198 status = NtCreateKey(&subkey, access, attr, 0, NULL, 0, NULL);
199 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
200 if (status) return status;
201 attr->RootDirectory = subkey;
202 while (i < len && buffer[i] == '\\') i++;
203 pos = i;
204 while (i < len && buffer[i] != '\\') i++;
206 str.Buffer = buffer + pos;
207 str.Length = (i - pos) * sizeof(WCHAR);
208 attr->Attributes = attrs;
209 status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
210 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
212 return status;
215 static HKEY classes_root_hkey;
217 static HKEY create_classes_root_hkey(DWORD access)
219 HKEY hkey, ret = 0;
220 OBJECT_ATTRIBUTES attr;
221 UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
223 attr.Length = sizeof(attr);
224 attr.RootDirectory = 0;
225 attr.ObjectName = &name;
226 attr.Attributes = 0;
227 attr.SecurityDescriptor = NULL;
228 attr.SecurityQualityOfService = NULL;
230 if (create_key( &hkey, access, &attr )) return 0;
231 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
233 if (!(access & KEY_WOW64_64KEY))
235 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
236 ret = hkey;
237 else
238 NtClose( hkey ); /* somebody beat us to it */
240 else
241 ret = hkey;
242 return ret;
245 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access);
247 static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
249 OBJECT_ATTRIBUTES attr;
250 UNICODE_STRING nameW;
252 if (!(hkey = get_classes_root_hkey(hkey, access)))
253 return ERROR_INVALID_HANDLE;
255 attr.Length = sizeof(attr);
256 attr.RootDirectory = hkey;
257 attr.ObjectName = &nameW;
258 attr.Attributes = 0;
259 attr.SecurityDescriptor = NULL;
260 attr.SecurityQualityOfService = NULL;
261 RtlInitUnicodeString( &nameW, name );
263 return RtlNtStatusToDosError(create_key(retkey, access, &attr));
266 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access)
268 HKEY ret = hkey;
269 const BOOL is_win64 = sizeof(void*) > sizeof(int);
270 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
272 if (hkey == HKEY_CLASSES_ROOT &&
273 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
274 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
275 if (force_wow32 && ret && ret == classes_root_hkey)
277 access &= ~KEY_WOW64_32KEY;
278 if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey))
279 return 0;
280 ret = hkey;
283 return ret;
286 static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
288 OBJECT_ATTRIBUTES attr;
289 UNICODE_STRING nameW;
291 if (!(hkey = get_classes_root_hkey(hkey, access)))
292 return ERROR_INVALID_HANDLE;
294 attr.Length = sizeof(attr);
295 attr.RootDirectory = hkey;
296 attr.ObjectName = &nameW;
297 attr.Attributes = 0;
298 attr.SecurityDescriptor = NULL;
299 attr.SecurityQualityOfService = NULL;
300 RtlInitUnicodeString( &nameW, name );
302 return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
305 HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
307 static const WCHAR clsidW[] = L"CLSID\\";
308 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
309 LONG res;
310 HKEY key;
312 lstrcpyW(path, clsidW);
313 StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID);
314 res = open_classes_key(HKEY_CLASSES_ROOT, path, access, &key);
315 if (res == ERROR_FILE_NOT_FOUND)
316 return REGDB_E_CLASSNOTREG;
317 else if (res != ERROR_SUCCESS)
318 return REGDB_E_READREGDB;
320 if (!keyname)
322 *subkey = key;
323 return S_OK;
326 res = open_classes_key(key, keyname, access, subkey);
327 RegCloseKey(key);
328 if (res == ERROR_FILE_NOT_FOUND)
329 return REGDB_E_KEYMISSING;
330 else if (res != ERROR_SUCCESS)
331 return REGDB_E_READREGDB;
333 return S_OK;
336 /* open HKCR\\AppId\\{string form of appid clsid} key */
337 HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey)
339 static const WCHAR appidkeyW[] = L"AppId\\";
340 DWORD res;
341 WCHAR buf[CHARS_IN_GUID];
342 WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID];
343 DWORD size;
344 HKEY hkey;
345 DWORD type;
346 HRESULT hr;
348 /* read the AppID value under the class's key */
349 hr = open_key_for_clsid(clsid, NULL, access, &hkey);
350 if (FAILED(hr))
351 return hr;
353 size = sizeof(buf);
354 res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size);
355 RegCloseKey(hkey);
356 if (res == ERROR_FILE_NOT_FOUND)
357 return REGDB_E_KEYMISSING;
358 else if (res != ERROR_SUCCESS || type!=REG_SZ)
359 return REGDB_E_READREGDB;
361 lstrcpyW(keyname, appidkeyW);
362 lstrcatW(keyname, buf);
363 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
364 if (res == ERROR_FILE_NOT_FOUND)
365 return REGDB_E_KEYMISSING;
366 else if (res != ERROR_SUCCESS)
367 return REGDB_E_READREGDB;
369 return S_OK;
372 /***********************************************************************
373 * InternalIsProcessInitialized (combase.@)
375 BOOL WINAPI InternalIsProcessInitialized(void)
377 struct apartment *apt;
379 if (!(apt = apartment_get_current_or_mta()))
380 return FALSE;
381 apartment_release(apt);
383 return TRUE;
386 /***********************************************************************
387 * InternalTlsAllocData (combase.@)
389 HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data)
391 if (!(*data = calloc(1, sizeof(**data))))
392 return E_OUTOFMEMORY;
394 list_init(&(*data)->spies);
395 NtCurrentTeb()->ReservedForOle = *data;
397 return S_OK;
400 static void com_cleanup_tlsdata(void)
402 struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle;
403 struct init_spy *cursor, *cursor2;
405 if (!tlsdata)
406 return;
408 if (tlsdata->apt)
409 apartment_release(tlsdata->apt);
410 if (tlsdata->implicit_mta_cookie)
411 apartment_decrement_mta_usage(tlsdata->implicit_mta_cookie);
413 if (tlsdata->errorinfo)
414 IErrorInfo_Release(tlsdata->errorinfo);
415 if (tlsdata->state)
416 IUnknown_Release(tlsdata->state);
418 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry)
420 list_remove(&cursor->entry);
421 if (cursor->spy)
422 IInitializeSpy_Release(cursor->spy);
423 free(cursor);
426 if (tlsdata->context_token)
427 IObjContext_Release(tlsdata->context_token);
429 free(tlsdata);
430 NtCurrentTeb()->ReservedForOle = NULL;
433 struct global_options
435 IGlobalOptions IGlobalOptions_iface;
436 LONG refcount;
439 static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface)
441 return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface);
444 static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
446 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
448 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
450 *ppv = iface;
452 else
454 *ppv = NULL;
455 return E_NOINTERFACE;
458 IUnknown_AddRef((IUnknown *)*ppv);
459 return S_OK;
462 static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface)
464 struct global_options *options = impl_from_IGlobalOptions(iface);
465 LONG refcount = InterlockedIncrement(&options->refcount);
467 TRACE("%p, refcount %ld.\n", iface, refcount);
469 return refcount;
472 static ULONG WINAPI global_options_Release(IGlobalOptions *iface)
474 struct global_options *options = impl_from_IGlobalOptions(iface);
475 LONG refcount = InterlockedDecrement(&options->refcount);
477 TRACE("%p, refcount %ld.\n", iface, refcount);
479 if (!refcount)
480 free(options);
482 return refcount;
485 static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
487 FIXME("%p, %u, %Ix.\n", iface, property, value);
489 return S_OK;
492 static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
494 TRACE("%p, %u, %p.\n", iface, property, value);
496 if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3)
497 return E_INVALIDARG;
499 *value = global_options[property];
501 return S_OK;
504 static const IGlobalOptionsVtbl global_options_vtbl =
506 global_options_QueryInterface,
507 global_options_AddRef,
508 global_options_Release,
509 global_options_Set,
510 global_options_Query
513 static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
515 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
517 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
519 *ppv = iface;
520 return S_OK;
523 *ppv = NULL;
524 return E_NOINTERFACE;
527 static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
529 return 2;
532 static ULONG WINAPI class_factory_Release(IClassFactory *iface)
534 return 1;
537 static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock)
539 TRACE("%d\n", fLock);
541 return S_OK;
544 static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
546 struct global_options *object;
547 HRESULT hr;
549 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv);
551 if (outer)
552 return E_INVALIDARG;
554 if (!(object = malloc(sizeof(*object))))
555 return E_OUTOFMEMORY;
556 object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl;
557 object->refcount = 1;
559 hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv);
560 IGlobalOptions_Release(&object->IGlobalOptions_iface);
561 return hr;
564 static const IClassFactoryVtbl global_options_factory_vtbl =
566 class_factory_QueryInterface,
567 class_factory_AddRef,
568 class_factory_Release,
569 global_options_CreateInstance,
570 class_factory_LockServer
573 static IClassFactory global_options_factory = { &global_options_factory_vtbl };
575 static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj)
577 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
578 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
579 return E_UNEXPECTED;
582 /***********************************************************************
583 * FreePropVariantArray (combase.@)
585 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
587 ULONG i;
589 TRACE("%lu, %p.\n", count, rgvars);
591 if (!rgvars)
592 return E_INVALIDARG;
594 for (i = 0; i < count; ++i)
595 PropVariantClear(&rgvars[i]);
597 return S_OK;
600 static HRESULT propvar_validatetype(VARTYPE vt)
602 switch (vt)
604 case VT_EMPTY:
605 case VT_NULL:
606 case VT_I1:
607 case VT_I2:
608 case VT_I4:
609 case VT_I8:
610 case VT_R4:
611 case VT_R8:
612 case VT_CY:
613 case VT_DATE:
614 case VT_BSTR:
615 case VT_ERROR:
616 case VT_BOOL:
617 case VT_DECIMAL:
618 case VT_UI1:
619 case VT_UI2:
620 case VT_UI4:
621 case VT_UI8:
622 case VT_INT:
623 case VT_UINT:
624 case VT_LPSTR:
625 case VT_LPWSTR:
626 case VT_FILETIME:
627 case VT_BLOB:
628 case VT_DISPATCH:
629 case VT_UNKNOWN:
630 case VT_STREAM:
631 case VT_STORAGE:
632 case VT_STREAMED_OBJECT:
633 case VT_STORED_OBJECT:
634 case VT_BLOB_OBJECT:
635 case VT_CF:
636 case VT_CLSID:
637 case VT_I1|VT_VECTOR:
638 case VT_I2|VT_VECTOR:
639 case VT_I4|VT_VECTOR:
640 case VT_I8|VT_VECTOR:
641 case VT_R4|VT_VECTOR:
642 case VT_R8|VT_VECTOR:
643 case VT_CY|VT_VECTOR:
644 case VT_DATE|VT_VECTOR:
645 case VT_BSTR|VT_VECTOR:
646 case VT_ERROR|VT_VECTOR:
647 case VT_BOOL|VT_VECTOR:
648 case VT_VARIANT|VT_VECTOR:
649 case VT_UI1|VT_VECTOR:
650 case VT_UI2|VT_VECTOR:
651 case VT_UI4|VT_VECTOR:
652 case VT_UI8|VT_VECTOR:
653 case VT_LPSTR|VT_VECTOR:
654 case VT_LPWSTR|VT_VECTOR:
655 case VT_FILETIME|VT_VECTOR:
656 case VT_CF|VT_VECTOR:
657 case VT_CLSID|VT_VECTOR:
658 case VT_ARRAY|VT_I1:
659 case VT_ARRAY|VT_UI1:
660 case VT_ARRAY|VT_I2:
661 case VT_ARRAY|VT_UI2:
662 case VT_ARRAY|VT_I4:
663 case VT_ARRAY|VT_UI4:
664 case VT_ARRAY|VT_INT:
665 case VT_ARRAY|VT_UINT:
666 case VT_ARRAY|VT_R4:
667 case VT_ARRAY|VT_R8:
668 case VT_ARRAY|VT_CY:
669 case VT_ARRAY|VT_DATE:
670 case VT_ARRAY|VT_BSTR:
671 case VT_ARRAY|VT_BOOL:
672 case VT_ARRAY|VT_DECIMAL:
673 case VT_ARRAY|VT_DISPATCH:
674 case VT_ARRAY|VT_UNKNOWN:
675 case VT_ARRAY|VT_ERROR:
676 case VT_ARRAY|VT_VARIANT:
677 return S_OK;
679 WARN("Bad type %d\n", vt);
680 return STG_E_INVALIDPARAMETER;
683 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
685 ULONG i;
686 for (i = 0; i < count; ++i)
687 CoTaskMemFree(data[i].pClipData);
690 /***********************************************************************
691 * PropVariantClear (combase.@)
693 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
695 HRESULT hr;
697 TRACE("%p.\n", pvar);
699 if (!pvar)
700 return S_OK;
702 hr = propvar_validatetype(pvar->vt);
703 if (FAILED(hr))
705 memset(pvar, 0, sizeof(*pvar));
706 return hr;
709 switch (pvar->vt)
711 case VT_EMPTY:
712 case VT_NULL:
713 case VT_I1:
714 case VT_I2:
715 case VT_I4:
716 case VT_I8:
717 case VT_R4:
718 case VT_R8:
719 case VT_CY:
720 case VT_DATE:
721 case VT_ERROR:
722 case VT_BOOL:
723 case VT_DECIMAL:
724 case VT_UI1:
725 case VT_UI2:
726 case VT_UI4:
727 case VT_UI8:
728 case VT_INT:
729 case VT_UINT:
730 case VT_FILETIME:
731 break;
732 case VT_DISPATCH:
733 case VT_UNKNOWN:
734 case VT_STREAM:
735 case VT_STREAMED_OBJECT:
736 case VT_STORAGE:
737 case VT_STORED_OBJECT:
738 if (pvar->pStream)
739 IStream_Release(pvar->pStream);
740 break;
741 case VT_CLSID:
742 case VT_LPSTR:
743 case VT_LPWSTR:
744 /* pick an arbitrary typed pointer - we don't care about the type
745 * as we are just freeing it */
746 CoTaskMemFree(pvar->puuid);
747 break;
748 case VT_BLOB:
749 case VT_BLOB_OBJECT:
750 CoTaskMemFree(pvar->blob.pBlobData);
751 break;
752 case VT_BSTR:
753 SysFreeString(pvar->bstrVal);
754 break;
755 case VT_CF:
756 if (pvar->pclipdata)
758 propvar_free_cf_array(1, pvar->pclipdata);
759 CoTaskMemFree(pvar->pclipdata);
761 break;
762 default:
763 if (pvar->vt & VT_VECTOR)
765 ULONG i;
767 switch (pvar->vt & ~VT_VECTOR)
769 case VT_VARIANT:
770 FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems);
771 break;
772 case VT_CF:
773 propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems);
774 break;
775 case VT_BSTR:
776 for (i = 0; i < pvar->cabstr.cElems; i++)
777 SysFreeString(pvar->cabstr.pElems[i]);
778 break;
779 case VT_LPSTR:
780 for (i = 0; i < pvar->calpstr.cElems; i++)
781 CoTaskMemFree(pvar->calpstr.pElems[i]);
782 break;
783 case VT_LPWSTR:
784 for (i = 0; i < pvar->calpwstr.cElems; i++)
785 CoTaskMemFree(pvar->calpwstr.pElems[i]);
786 break;
788 if (pvar->vt & ~VT_VECTOR)
790 /* pick an arbitrary VT_VECTOR structure - they all have the same
791 * memory layout */
792 CoTaskMemFree(pvar->capropvar.pElems);
795 else if (pvar->vt & VT_ARRAY)
796 hr = SafeArrayDestroy(pvar->parray);
797 else
799 WARN("Invalid/unsupported type %d\n", pvar->vt);
800 hr = STG_E_INVALIDPARAMETER;
804 memset(pvar, 0, sizeof(*pvar));
805 return hr;
808 /***********************************************************************
809 * PropVariantCopy (combase.@)
811 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
813 ULONG len;
814 HRESULT hr;
816 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
818 hr = propvar_validatetype(pvarSrc->vt);
819 if (FAILED(hr))
820 return DISP_E_BADVARTYPE;
822 /* this will deal with most cases */
823 *pvarDest = *pvarSrc;
825 switch (pvarSrc->vt)
827 case VT_EMPTY:
828 case VT_NULL:
829 case VT_I1:
830 case VT_UI1:
831 case VT_I2:
832 case VT_UI2:
833 case VT_BOOL:
834 case VT_DECIMAL:
835 case VT_I4:
836 case VT_UI4:
837 case VT_R4:
838 case VT_ERROR:
839 case VT_I8:
840 case VT_UI8:
841 case VT_INT:
842 case VT_UINT:
843 case VT_R8:
844 case VT_CY:
845 case VT_DATE:
846 case VT_FILETIME:
847 break;
848 case VT_DISPATCH:
849 case VT_UNKNOWN:
850 case VT_STREAM:
851 case VT_STREAMED_OBJECT:
852 case VT_STORAGE:
853 case VT_STORED_OBJECT:
854 if (pvarDest->pStream)
855 IStream_AddRef(pvarDest->pStream);
856 break;
857 case VT_CLSID:
858 pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID));
859 *pvarDest->puuid = *pvarSrc->puuid;
860 break;
861 case VT_LPSTR:
862 if (pvarSrc->pszVal)
864 len = strlen(pvarSrc->pszVal);
865 pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
866 CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR));
868 break;
869 case VT_LPWSTR:
870 if (pvarSrc->pwszVal)
872 len = lstrlenW(pvarSrc->pwszVal);
873 pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
874 CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR));
876 break;
877 case VT_BLOB:
878 case VT_BLOB_OBJECT:
879 if (pvarSrc->blob.pBlobData)
881 len = pvarSrc->blob.cbSize;
882 pvarDest->blob.pBlobData = CoTaskMemAlloc(len);
883 CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len);
885 break;
886 case VT_BSTR:
887 pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal);
888 break;
889 case VT_CF:
890 if (pvarSrc->pclipdata)
892 len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt);
893 pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
894 pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize;
895 pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt;
896 pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len);
897 CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len);
899 break;
900 default:
901 if (pvarSrc->vt & VT_VECTOR)
903 int elemSize;
904 ULONG i;
906 switch (pvarSrc->vt & ~VT_VECTOR)
908 case VT_I1: elemSize = sizeof(pvarSrc->cVal); break;
909 case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break;
910 case VT_I2: elemSize = sizeof(pvarSrc->iVal); break;
911 case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break;
912 case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break;
913 case VT_I4: elemSize = sizeof(pvarSrc->lVal); break;
914 case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break;
915 case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break;
916 case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break;
917 case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break;
918 case VT_I8: elemSize = sizeof(pvarSrc->hVal); break;
919 case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break;
920 case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break;
921 case VT_DATE: elemSize = sizeof(pvarSrc->date); break;
922 case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break;
923 case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break;
924 case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break;
925 case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break;
926 case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break;
927 case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break;
928 case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break;
930 default:
931 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
932 return E_INVALIDARG;
934 len = pvarSrc->capropvar.cElems;
935 pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
936 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
938 for (i = 0; i < len; i++)
939 PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]);
941 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
943 FIXME("Copy clipformats\n");
945 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
947 for (i = 0; i < len; i++)
948 pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]);
950 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
952 size_t strLen;
953 for (i = 0; i < len; i++)
955 strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1;
956 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
957 memcpy(pvarDest->calpstr.pElems[i],
958 pvarSrc->calpstr.pElems[i], strLen);
961 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
963 size_t strLen;
964 for (i = 0; i < len; i++)
966 strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) *
967 sizeof(WCHAR);
968 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
969 memcpy(pvarDest->calpstr.pElems[i],
970 pvarSrc->calpstr.pElems[i], strLen);
973 else
974 CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize);
976 else if (pvarSrc->vt & VT_ARRAY)
978 pvarDest->uhVal.QuadPart = 0;
979 return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray);
981 else
982 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
985 return S_OK;
988 /***********************************************************************
989 * CoFileTimeNow (combase.@)
991 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
993 GetSystemTimeAsFileTime(filetime);
994 return S_OK;
997 /******************************************************************************
998 * CoCreateGuid (combase.@)
1000 HRESULT WINAPI CoCreateGuid(GUID *guid)
1002 RPC_STATUS status;
1004 if (!guid) return E_INVALIDARG;
1006 status = UuidCreate(guid);
1007 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1008 return HRESULT_FROM_WIN32(status);
1011 /******************************************************************************
1012 * CoQueryProxyBlanket (combase.@)
1014 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
1015 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
1016 DWORD *imp_level, void **auth_info, DWORD *capabilities)
1018 IClientSecurity *client_security;
1019 HRESULT hr;
1021 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
1022 auth_info, capabilities);
1024 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1025 if (SUCCEEDED(hr))
1027 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
1028 authn_level, imp_level, auth_info, capabilities);
1029 IClientSecurity_Release(client_security);
1032 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1033 return hr;
1036 /******************************************************************************
1037 * CoSetProxyBlanket (combase.@)
1039 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
1040 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
1042 IClientSecurity *client_security;
1043 HRESULT hr;
1045 TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, authz_service, servername,
1046 authn_level, imp_level, auth_info, capabilities);
1048 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1049 if (SUCCEEDED(hr))
1051 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
1052 imp_level, auth_info, capabilities);
1053 IClientSecurity_Release(client_security);
1056 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1057 return hr;
1060 /***********************************************************************
1061 * CoCopyProxy (combase.@)
1063 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
1065 IClientSecurity *client_security;
1066 HRESULT hr;
1068 TRACE("%p, %p.\n", proxy, proxy_copy);
1070 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1071 if (SUCCEEDED(hr))
1073 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
1074 IClientSecurity_Release(client_security);
1077 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1078 return hr;
1081 /***********************************************************************
1082 * CoQueryClientBlanket (combase.@)
1084 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
1085 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
1087 IServerSecurity *server_security;
1088 HRESULT hr;
1090 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
1091 privs, capabilities);
1093 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1094 if (SUCCEEDED(hr))
1096 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
1097 imp_level, privs, capabilities);
1098 IServerSecurity_Release(server_security);
1101 return hr;
1104 /***********************************************************************
1105 * CoImpersonateClient (combase.@)
1107 HRESULT WINAPI CoImpersonateClient(void)
1109 IServerSecurity *server_security;
1110 HRESULT hr;
1112 TRACE("\n");
1114 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1115 if (SUCCEEDED(hr))
1117 hr = IServerSecurity_ImpersonateClient(server_security);
1118 IServerSecurity_Release(server_security);
1121 return hr;
1124 /***********************************************************************
1125 * CoRevertToSelf (combase.@)
1127 HRESULT WINAPI CoRevertToSelf(void)
1129 IServerSecurity *server_security;
1130 HRESULT hr;
1132 TRACE("\n");
1134 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1135 if (SUCCEEDED(hr))
1137 hr = IServerSecurity_RevertToSelf(server_security);
1138 IServerSecurity_Release(server_security);
1141 return hr;
1144 /***********************************************************************
1145 * CoInitializeSecurity (combase.@)
1147 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
1148 SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
1149 DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1151 FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1152 imp_level, reserved2, capabilities, reserved3);
1154 return S_OK;
1157 /***********************************************************************
1158 * CoGetObjectContext (combase.@)
1160 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1162 IObjContext *context;
1163 HRESULT hr;
1165 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1167 *ppv = NULL;
1168 hr = CoGetContextToken((ULONG_PTR *)&context);
1169 if (FAILED(hr))
1170 return hr;
1172 return IObjContext_QueryInterface(context, riid, ppv);
1175 /***********************************************************************
1176 * CoGetDefaultContext (combase.@)
1178 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1180 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1182 return E_NOINTERFACE;
1185 /***********************************************************************
1186 * CoGetCallState (combase.@)
1188 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1190 FIXME("%d, %p.\n", arg1, arg2);
1192 return E_NOTIMPL;
1195 /***********************************************************************
1196 * CoGetActivationState (combase.@)
1198 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1200 FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3);
1202 return E_NOTIMPL;
1205 /******************************************************************************
1206 * CoGetTreatAsClass (combase.@)
1208 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1210 WCHAR buffW[CHARS_IN_GUID];
1211 LONG len = sizeof(buffW);
1212 HRESULT hr = S_OK;
1213 HKEY hkey = NULL;
1215 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1217 if (!clsidOld || !clsidNew)
1218 return E_INVALIDARG;
1220 *clsidNew = *clsidOld;
1222 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1223 if (FAILED(hr))
1225 hr = S_FALSE;
1226 goto done;
1229 if (RegQueryValueW(hkey, NULL, buffW, &len))
1231 hr = S_FALSE;
1232 goto done;
1235 hr = CLSIDFromString(buffW, clsidNew);
1236 if (FAILED(hr))
1237 ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), hr);
1238 done:
1239 if (hkey) RegCloseKey(hkey);
1240 return hr;
1243 /******************************************************************************
1244 * ProgIDFromCLSID (combase.@)
1246 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1248 ACTCTX_SECTION_KEYED_DATA data;
1249 LONG progidlen = 0;
1250 HKEY hkey;
1251 REGSAM opposite = (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1252 BOOL is_wow64;
1253 HRESULT hr;
1255 if (!progid)
1256 return E_INVALIDARG;
1258 *progid = NULL;
1260 data.cbSize = sizeof(data);
1261 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
1262 clsid, &data))
1264 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1265 if (comclass->progid_len)
1267 WCHAR *ptrW;
1269 *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
1270 if (!*progid) return E_OUTOFMEMORY;
1272 ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
1273 memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
1274 return S_OK;
1276 else
1277 return REGDB_E_CLASSNOTREG;
1280 hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
1281 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1283 hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey);
1284 if (FAILED(hr))
1285 return hr;
1288 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1289 hr = REGDB_E_CLASSNOTREG;
1291 if (hr == S_OK)
1293 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1294 if (*progid)
1296 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1298 hr = REGDB_E_CLASSNOTREG;
1299 CoTaskMemFree(*progid);
1300 *progid = NULL;
1303 else
1304 hr = E_OUTOFMEMORY;
1307 RegCloseKey(hkey);
1308 return hr;
1311 static inline BOOL is_valid_hex(WCHAR c)
1313 if (!(((c >= '0') && (c <= '9')) ||
1314 ((c >= 'a') && (c <= 'f')) ||
1315 ((c >= 'A') && (c <= 'F'))))
1316 return FALSE;
1317 return TRUE;
1320 static const BYTE guid_conv_table[256] =
1322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1323 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1324 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1325 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1326 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1327 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1328 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1331 static BOOL guid_from_string(LPCWSTR s, GUID *id)
1333 int i;
1335 if (!s || s[0] != '{')
1337 memset(id, 0, sizeof(*id));
1338 if (!s) return TRUE;
1339 return FALSE;
1342 TRACE("%s -> %p\n", debugstr_w(s), id);
1344 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1346 id->Data1 = 0;
1347 for (i = 1; i < 9; ++i)
1349 if (!is_valid_hex(s[i])) return FALSE;
1350 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1352 if (s[9] != '-') return FALSE;
1354 id->Data2 = 0;
1355 for (i = 10; i < 14; ++i)
1357 if (!is_valid_hex(s[i])) return FALSE;
1358 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1360 if (s[14] != '-') return FALSE;
1362 id->Data3 = 0;
1363 for (i = 15; i < 19; ++i)
1365 if (!is_valid_hex(s[i])) return FALSE;
1366 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1368 if (s[19] != '-') return FALSE;
1370 for (i = 20; i < 37; i += 2)
1372 if (i == 24)
1374 if (s[i] != '-') return FALSE;
1375 i++;
1377 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1378 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1381 if (s[37] == '}' && s[38] == '\0')
1382 return TRUE;
1384 return FALSE;
1387 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1389 WCHAR buf2[CHARS_IN_GUID];
1390 LONG buf2len = sizeof(buf2);
1391 HKEY xhkey;
1392 WCHAR *buf;
1394 memset(clsid, 0, sizeof(*clsid));
1395 buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1396 if (!buf) return E_OUTOFMEMORY;
1398 lstrcpyW(buf, progid);
1399 lstrcatW(buf, L"\\CLSID");
1400 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1402 free(buf);
1403 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1404 return CO_E_CLASSSTRING;
1406 free(buf);
1408 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1410 RegCloseKey(xhkey);
1411 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1412 return CO_E_CLASSSTRING;
1414 RegCloseKey(xhkey);
1415 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1418 /******************************************************************************
1419 * CLSIDFromProgID (combase.@)
1421 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1423 ACTCTX_SECTION_KEYED_DATA data;
1425 if (!progid || !clsid)
1426 return E_INVALIDARG;
1428 data.cbSize = sizeof(data);
1429 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1430 progid, &data))
1432 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1433 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1434 *clsid = *alias;
1435 return S_OK;
1438 return clsid_from_string_reg(progid, clsid);
1441 /******************************************************************************
1442 * CLSIDFromProgIDEx (combase.@)
1444 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1446 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1448 return CLSIDFromProgID(progid, clsid);
1451 /******************************************************************************
1452 * CLSIDFromString (combase.@)
1454 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1456 CLSID tmp_id;
1457 HRESULT hr;
1459 if (!clsid)
1460 return E_INVALIDARG;
1462 if (guid_from_string(str, clsid))
1463 return S_OK;
1465 /* It appears a ProgID is also valid */
1466 hr = clsid_from_string_reg(str, &tmp_id);
1467 if (SUCCEEDED(hr))
1468 *clsid = tmp_id;
1470 return hr;
1473 /******************************************************************************
1474 * IIDFromString (combase.@)
1476 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1478 TRACE("%s, %p\n", debugstr_w(str), iid);
1480 if (!str)
1482 memset(iid, 0, sizeof(*iid));
1483 return S_OK;
1486 /* length mismatch is a special case */
1487 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1488 return E_INVALIDARG;
1490 if (str[0] != '{')
1491 return CO_E_IIDSTRING;
1493 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1496 /******************************************************************************
1497 * StringFromCLSID (combase.@)
1499 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1501 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1502 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1503 return S_OK;
1506 /******************************************************************************
1507 * StringFromGUID2 (combase.@)
1509 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1511 if (!guid || cmax < CHARS_IN_GUID) return 0;
1512 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1513 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1514 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1515 return CHARS_IN_GUID;
1518 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1520 ULONG i;
1522 for (i = 0; i < count; i++)
1524 mqi[i].pItf = NULL;
1525 mqi[i].hr = hr;
1529 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1531 ULONG index = 0, fetched = 0;
1533 if (include_unk)
1535 mqi[0].hr = S_OK;
1536 mqi[0].pItf = unk;
1537 index = fetched = 1;
1540 for (; index < count; index++)
1542 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1543 if (mqi[index].hr == S_OK)
1544 fetched++;
1547 if (!include_unk)
1548 IUnknown_Release(unk);
1550 if (fetched == 0)
1551 return E_NOINTERFACE;
1553 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1556 /***********************************************************************
1557 * CoGetInstanceFromFile (combase.@)
1559 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1560 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1561 MULTI_QI *results)
1563 IPersistFile *pf = NULL;
1564 IUnknown *obj = NULL;
1565 CLSID clsid;
1566 HRESULT hr;
1568 if (!count || !results)
1569 return E_INVALIDARG;
1571 if (server_info)
1572 FIXME("() non-NULL server_info not supported\n");
1574 init_multi_qi(count, results, E_NOINTERFACE);
1576 if (!rclsid)
1578 hr = GetClassFile(filename, &clsid);
1579 if (FAILED(hr))
1581 ERR("Failed to get CLSID from a file.\n");
1582 return hr;
1585 rclsid = &clsid;
1588 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1589 if (hr != S_OK)
1591 init_multi_qi(count, results, hr);
1592 return hr;
1595 /* Init from file */
1596 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1597 if (FAILED(hr))
1599 init_multi_qi(count, results, hr);
1600 IUnknown_Release(obj);
1601 return hr;
1604 hr = IPersistFile_Load(pf, filename, grfmode);
1605 IPersistFile_Release(pf);
1606 if (SUCCEEDED(hr))
1607 return return_multi_qi(obj, count, results, FALSE);
1608 else
1610 init_multi_qi(count, results, hr);
1611 IUnknown_Release(obj);
1612 return hr;
1616 /***********************************************************************
1617 * CoGetInstanceFromIStorage (combase.@)
1619 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1620 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1622 IPersistStorage *ps = NULL;
1623 IUnknown *obj = NULL;
1624 STATSTG stat;
1625 HRESULT hr;
1627 if (!count || !results || !storage)
1628 return E_INVALIDARG;
1630 if (server_info)
1631 FIXME("() non-NULL server_info not supported\n");
1633 init_multi_qi(count, results, E_NOINTERFACE);
1635 if (!rclsid)
1637 memset(&stat.clsid, 0, sizeof(stat.clsid));
1638 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1639 if (FAILED(hr))
1641 ERR("Failed to get CLSID from a storage.\n");
1642 return hr;
1645 rclsid = &stat.clsid;
1648 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1649 if (hr != S_OK)
1650 return hr;
1652 /* Init from IStorage */
1653 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1654 if (FAILED(hr))
1655 ERR("failed to get IPersistStorage\n");
1657 if (ps)
1659 IPersistStorage_Load(ps, storage);
1660 IPersistStorage_Release(ps);
1663 return return_multi_qi(obj, count, results, FALSE);
1666 /***********************************************************************
1667 * CoCreateInstance (combase.@)
1669 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1670 REFIID riid, void **obj)
1672 MULTI_QI multi_qi = { .pIID = riid };
1673 HRESULT hr;
1675 TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1677 if (!obj)
1678 return E_POINTER;
1680 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1681 *obj = multi_qi.pItf;
1682 return hr;
1685 /***********************************************************************
1686 * CoCreateInstanceFromApp (combase.@)
1688 HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1689 void *server_info, ULONG count, MULTI_QI *results)
1691 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1692 count, results);
1694 return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1695 count, results);
1698 static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1699 COSERVERINFO *server_info, REFIID riid, void **obj)
1701 struct class_reg_data clsreg = { 0 };
1702 HRESULT hr = E_UNEXPECTED;
1703 IUnknown *registered_obj;
1704 struct apartment *apt;
1706 if (!obj)
1707 return E_INVALIDARG;
1709 *obj = NULL;
1711 if (!(apt = apartment_get_current_or_mta()))
1713 ERR("apartment not initialised\n");
1714 return CO_E_NOTINITIALIZED;
1717 if (server_info)
1718 FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1720 if (clscontext & CLSCTX_INPROC_SERVER)
1722 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1723 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1724 (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1725 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1727 apartment_release(apt);
1729 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
1730 return get_builtin_class_factory(rclsid, riid, obj);
1731 else
1732 return Ole32DllGetClassObject(rclsid, riid, obj);
1736 if (clscontext & CLSCTX_INPROC)
1738 ACTCTX_SECTION_KEYED_DATA data;
1740 data.cbSize = sizeof(data);
1741 /* search activation context first */
1742 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1743 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1745 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1747 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1748 clsreg.u.actctx.hactctx = data.hActCtx;
1749 clsreg.u.actctx.threading_model = comclass->model;
1750 clsreg.origin = CLASS_REG_ACTCTX;
1752 hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1753 ReleaseActCtx(data.hActCtx);
1754 apartment_release(apt);
1755 return hr;
1760 * First, try and see if we can't match the class ID with one of the
1761 * registered classes.
1763 if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1765 hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1766 IUnknown_Release(registered_obj);
1767 apartment_release(apt);
1768 return hr;
1771 /* First try in-process server */
1772 if (clscontext & CLSCTX_INPROC_SERVER)
1774 HKEY hkey;
1776 hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1777 if (FAILED(hr))
1779 if (hr == REGDB_E_CLASSNOTREG)
1780 ERR("class %s not registered\n", debugstr_guid(rclsid));
1781 else if (hr == REGDB_E_KEYMISSING)
1783 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1784 hr = REGDB_E_CLASSNOTREG;
1788 if (SUCCEEDED(hr))
1790 clsreg.u.hkey = hkey;
1791 clsreg.origin = CLASS_REG_REGISTRY;
1793 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1794 RegCloseKey(hkey);
1797 /* return if we got a class, otherwise fall through to one of the
1798 * other types */
1799 if (SUCCEEDED(hr))
1801 apartment_release(apt);
1802 return hr;
1806 /* Next try in-process handler */
1807 if (clscontext & CLSCTX_INPROC_HANDLER)
1809 HKEY hkey;
1811 hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1812 if (FAILED(hr))
1814 if (hr == REGDB_E_CLASSNOTREG)
1815 ERR("class %s not registered\n", debugstr_guid(rclsid));
1816 else if (hr == REGDB_E_KEYMISSING)
1818 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1819 hr = REGDB_E_CLASSNOTREG;
1823 if (SUCCEEDED(hr))
1825 clsreg.u.hkey = hkey;
1826 clsreg.origin = CLASS_REG_REGISTRY;
1828 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1829 RegCloseKey(hkey);
1832 /* return if we got a class, otherwise fall through to one of the
1833 * other types */
1834 if (SUCCEEDED(hr))
1836 apartment_release(apt);
1837 return hr;
1840 apartment_release(apt);
1842 /* Next try out of process */
1843 if (clscontext & CLSCTX_LOCAL_SERVER)
1845 hr = rpc_get_local_class_object(rclsid, riid, obj);
1846 if (SUCCEEDED(hr))
1847 return hr;
1850 /* Finally try remote: this requires networked DCOM (a lot of work) */
1851 if (clscontext & CLSCTX_REMOTE_SERVER)
1853 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1854 hr = REGDB_E_CLASSNOTREG;
1857 if (FAILED(hr))
1858 ERR("no class object %s could be created for context %#lx\n", debugstr_guid(rclsid), clscontext);
1860 return hr;
1863 /***********************************************************************
1864 * CoCreateInstanceEx (combase.@)
1866 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1867 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1869 IClassFactory *factory;
1870 IUnknown *unk = NULL;
1871 CLSID clsid;
1872 HRESULT hr;
1874 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1876 if (!count || !results)
1877 return E_INVALIDARG;
1879 if (server_info)
1880 FIXME("Server info is not supported.\n");
1882 init_multi_qi(count, results, E_NOINTERFACE);
1884 clsid = *rclsid;
1885 if (!(cls_context & CLSCTX_APPCONTAINER))
1886 CoGetTreatAsClass(rclsid, &clsid);
1888 if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1889 return hr;
1891 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1892 IClassFactory_Release(factory);
1893 if (FAILED(hr))
1895 if (hr == CLASS_E_NOAGGREGATION && outer)
1896 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1897 else
1898 FIXME("no instance created for interface %s of class %s, hr %#lx.\n",
1899 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1900 return hr;
1903 return return_multi_qi(unk, count, results, TRUE);
1906 /***********************************************************************
1907 * CoGetClassObject (combase.@)
1909 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1910 COSERVERINFO *server_info, REFIID riid, void **obj)
1912 TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1914 return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1917 /***********************************************************************
1918 * CoFreeUnusedLibraries (combase.@)
1920 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1922 CoFreeUnusedLibrariesEx(INFINITE, 0);
1925 /***********************************************************************
1926 * CoGetCallContext (combase.@)
1928 HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1930 struct tlsdata *tlsdata;
1931 HRESULT hr;
1933 TRACE("%s, %p\n", debugstr_guid(riid), obj);
1935 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1936 return hr;
1938 if (!tlsdata->call_state)
1939 return RPC_E_CALL_COMPLETE;
1941 return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1944 /***********************************************************************
1945 * CoSwitchCallContext (combase.@)
1947 HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1949 struct tlsdata *tlsdata;
1950 HRESULT hr;
1952 TRACE("%p, %p\n", context, old_context);
1954 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1955 return hr;
1957 /* Reference counts are not touched. */
1958 *old_context = tlsdata->call_state;
1959 tlsdata->call_state = context;
1961 return S_OK;
1964 /******************************************************************************
1965 * CoRegisterInitializeSpy (combase.@)
1967 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1969 struct tlsdata *tlsdata;
1970 struct init_spy *entry;
1971 unsigned int id;
1972 HRESULT hr;
1974 TRACE("%p, %p\n", spy, cookie);
1976 if (!spy || !cookie)
1977 return E_INVALIDARG;
1979 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1980 return hr;
1982 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1983 if (FAILED(hr))
1984 return hr;
1986 entry = malloc(sizeof(*entry));
1987 if (!entry)
1989 IInitializeSpy_Release(spy);
1990 return E_OUTOFMEMORY;
1993 entry->spy = spy;
1995 id = 0;
1996 while (get_spy_entry(tlsdata, id) != NULL)
1998 id++;
2001 entry->id = id;
2002 list_add_head(&tlsdata->spies, &entry->entry);
2004 cookie->u.HighPart = GetCurrentThreadId();
2005 cookie->u.LowPart = entry->id;
2007 return S_OK;
2010 /******************************************************************************
2011 * CoRevokeInitializeSpy (combase.@)
2013 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
2015 struct tlsdata *tlsdata;
2016 struct init_spy *spy;
2017 HRESULT hr;
2019 TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
2021 if (cookie.u.HighPart != GetCurrentThreadId())
2022 return E_INVALIDARG;
2024 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2025 return hr;
2027 if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
2029 IInitializeSpy_Release(spy->spy);
2030 spy->spy = NULL;
2031 if (!tlsdata->spies_lock)
2033 list_remove(&spy->entry);
2034 free(spy);
2036 return S_OK;
2039 static BOOL com_peek_message(struct apartment *apt, MSG *msg)
2041 /* First try to retrieve messages for incoming COM calls to the apartment window */
2042 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
2043 /* Next retrieve other messages necessary for the app to remain responsive */
2044 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
2045 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
2048 /***********************************************************************
2049 * CoWaitForMultipleHandles (combase.@)
2051 HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
2052 DWORD *index)
2054 BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
2055 DWORD start_time, wait_flags = 0;
2056 struct tlsdata *tlsdata;
2057 struct apartment *apt;
2058 UINT exit_code;
2059 HRESULT hr;
2061 TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index);
2063 if (!index)
2064 return E_INVALIDARG;
2066 *index = 0;
2068 if (!handles)
2069 return E_INVALIDARG;
2071 if (!handle_count)
2072 return RPC_E_NO_SYNC;
2074 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2075 return hr;
2077 apt = com_get_current_apt();
2078 message_loop = apt && !apt->multi_threaded;
2080 if (flags & COWAIT_WAITALL)
2081 wait_flags |= MWMO_WAITALL;
2082 if (flags & COWAIT_ALERTABLE)
2083 wait_flags |= MWMO_ALERTABLE;
2085 start_time = GetTickCount();
2087 while (TRUE)
2089 DWORD now = GetTickCount(), res;
2091 if (now - start_time > timeout)
2093 hr = RPC_S_CALLPENDING;
2094 break;
2097 if (message_loop)
2099 TRACE("waiting for rpc completion or window message\n");
2101 res = WAIT_TIMEOUT;
2103 if (check_apc)
2105 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
2106 check_apc = FALSE;
2109 if (res == WAIT_TIMEOUT)
2110 res = MsgWaitForMultipleObjectsEx(handle_count, handles,
2111 timeout == INFINITE ? INFINITE : start_time + timeout - now,
2112 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
2114 if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
2116 int msg_count = 0;
2117 MSG msg;
2119 /* call message filter */
2121 if (apt->filter)
2123 PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
2124 DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
2126 TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled);
2128 switch (be_handled)
2130 case PENDINGMSG_CANCELCALL:
2131 WARN("call canceled\n");
2132 hr = RPC_E_CALL_CANCELED;
2133 break;
2134 case PENDINGMSG_WAITNOPROCESS:
2135 case PENDINGMSG_WAITDEFPROCESS:
2136 default:
2137 /* FIXME: MSDN is very vague about the difference
2138 * between WAITNOPROCESS and WAITDEFPROCESS - there
2139 * appears to be none, so it is possibly a left-over
2140 * from the 16-bit world. */
2141 break;
2145 if (!apt->win)
2147 /* If window is NULL on apartment, peek at messages so that it will not trigger
2148 * MsgWaitForMultipleObjects next time. */
2149 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
2152 /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
2153 * so after processing 100 messages we go back to checking the wait handles */
2154 while (msg_count++ < 100 && com_peek_message(apt, &msg))
2156 if (msg.message == WM_QUIT)
2158 TRACE("Received WM_QUIT message\n");
2159 post_quit = TRUE;
2160 exit_code = msg.wParam;
2162 else
2164 TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2165 TranslateMessage(&msg);
2166 DispatchMessageW(&msg);
2169 continue;
2172 else
2174 TRACE("Waiting for rpc completion\n");
2176 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2177 (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2180 switch (res)
2182 case WAIT_TIMEOUT:
2183 hr = RPC_S_CALLPENDING;
2184 break;
2185 case WAIT_FAILED:
2186 hr = HRESULT_FROM_WIN32(GetLastError());
2187 break;
2188 default:
2189 *index = res;
2190 break;
2192 break;
2194 if (post_quit) PostQuitMessage(exit_code);
2196 TRACE("-- %#lx\n", hr);
2198 return hr;
2201 /******************************************************************************
2202 * CoRegisterMessageFilter (combase.@)
2204 HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2206 IMessageFilter *old_filter;
2207 struct apartment *apt;
2209 TRACE("%p, %p\n", filter, ret_filter);
2211 apt = com_get_current_apt();
2213 /* Can't set a message filter in a multi-threaded apartment */
2214 if (!apt || apt->multi_threaded)
2216 WARN("Can't set message filter in MTA or uninitialized apt\n");
2217 return CO_E_NOT_SUPPORTED;
2220 if (filter)
2221 IMessageFilter_AddRef(filter);
2223 EnterCriticalSection(&apt->cs);
2225 old_filter = apt->filter;
2226 apt->filter = filter;
2228 LeaveCriticalSection(&apt->cs);
2230 if (ret_filter)
2231 *ret_filter = old_filter;
2232 else if (old_filter)
2233 IMessageFilter_Release(old_filter);
2235 return S_OK;
2238 static void com_revoke_all_ps_clsids(void)
2240 struct registered_ps *cur, *cur2;
2242 EnterCriticalSection(&cs_registered_ps);
2244 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2246 list_remove(&cur->entry);
2247 free(cur);
2250 LeaveCriticalSection(&cs_registered_ps);
2253 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2255 WCHAR value[CHARS_IN_GUID];
2256 HKEY hkey;
2257 DWORD len;
2259 access |= KEY_READ;
2261 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2262 return REGDB_E_IIDNOTREG;
2264 len = sizeof(value);
2265 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2266 return REGDB_E_IIDNOTREG;
2267 RegCloseKey(hkey);
2269 if (CLSIDFromString(value, pclsid) != NOERROR)
2270 return REGDB_E_IIDNOTREG;
2272 return S_OK;
2275 /*****************************************************************************
2276 * CoGetPSClsid (combase.@)
2278 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2280 static const WCHAR interfaceW[] = L"Interface\\";
2281 static const WCHAR psW[] = L"\\ProxyStubClsid32";
2282 WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2283 ACTCTX_SECTION_KEYED_DATA data;
2284 struct registered_ps *cur;
2285 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2286 BOOL is_wow64;
2287 HRESULT hr;
2289 TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2291 if (!InternalIsProcessInitialized())
2293 ERR("apartment not initialised\n");
2294 return CO_E_NOTINITIALIZED;
2297 if (!pclsid)
2298 return E_INVALIDARG;
2300 EnterCriticalSection(&cs_registered_ps);
2302 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2304 if (IsEqualIID(&cur->iid, riid))
2306 *pclsid = cur->clsid;
2307 LeaveCriticalSection(&cs_registered_ps);
2308 return S_OK;
2312 LeaveCriticalSection(&cs_registered_ps);
2314 data.cbSize = sizeof(data);
2315 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2316 riid, &data))
2318 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2319 *pclsid = ifaceps->iid;
2320 return S_OK;
2323 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2324 lstrcpyW(path, interfaceW);
2325 StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2326 lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2328 hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid);
2329 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2330 hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid);
2332 if (hr == S_OK)
2333 TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2334 else
2335 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2337 return hr;
2340 /*****************************************************************************
2341 * CoRegisterPSClsid (combase.@)
2343 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2345 struct registered_ps *cur;
2347 TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2349 if (!InternalIsProcessInitialized())
2351 ERR("apartment not initialised\n");
2352 return CO_E_NOTINITIALIZED;
2355 EnterCriticalSection(&cs_registered_ps);
2357 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2359 if (IsEqualIID(&cur->iid, riid))
2361 cur->clsid = *rclsid;
2362 LeaveCriticalSection(&cs_registered_ps);
2363 return S_OK;
2367 cur = malloc(sizeof(*cur));
2368 if (!cur)
2370 LeaveCriticalSection(&cs_registered_ps);
2371 return E_OUTOFMEMORY;
2374 cur->iid = *riid;
2375 cur->clsid = *rclsid;
2376 list_add_head(&registered_proxystubs, &cur->entry);
2378 LeaveCriticalSection(&cs_registered_ps);
2380 return S_OK;
2383 struct thread_context
2385 IComThreadingInfo IComThreadingInfo_iface;
2386 IContextCallback IContextCallback_iface;
2387 IObjContext IObjContext_iface;
2388 LONG refcount;
2391 static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2393 return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2396 static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2398 return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2401 static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2403 return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2406 static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2408 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2410 *obj = NULL;
2412 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2413 IsEqualIID(riid, &IID_IUnknown))
2415 *obj = &context->IComThreadingInfo_iface;
2417 else if (IsEqualIID(riid, &IID_IContextCallback))
2419 *obj = &context->IContextCallback_iface;
2421 else if (IsEqualIID(riid, &IID_IObjContext))
2423 *obj = &context->IObjContext_iface;
2426 if (*obj)
2428 IUnknown_AddRef((IUnknown *)*obj);
2429 return S_OK;
2432 FIXME("interface not implemented %s\n", debugstr_guid(riid));
2433 return E_NOINTERFACE;
2436 static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2438 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2439 return InterlockedIncrement(&context->refcount);
2442 static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2444 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2446 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2447 releasing context while refcount is at 0 destroys it. */
2448 if (!context->refcount)
2450 free(context);
2451 return 0;
2454 return InterlockedDecrement(&context->refcount);
2457 static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2459 APTTYPEQUALIFIER qualifier;
2461 TRACE("%p\n", apttype);
2463 return CoGetApartmentType(apttype, &qualifier);
2466 static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2468 APTTYPEQUALIFIER qualifier;
2469 APTTYPE apttype;
2470 HRESULT hr;
2472 hr = CoGetApartmentType(&apttype, &qualifier);
2473 if (FAILED(hr))
2474 return hr;
2476 TRACE("%p\n", thdtype);
2478 switch (apttype)
2480 case APTTYPE_STA:
2481 case APTTYPE_MAINSTA:
2482 *thdtype = THDTYPE_PROCESSMESSAGES;
2483 break;
2484 default:
2485 *thdtype = THDTYPE_BLOCKMESSAGES;
2486 break;
2488 return S_OK;
2491 static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2493 TRACE("%p\n", logical_thread_id);
2495 return CoGetCurrentLogicalThreadId(logical_thread_id);
2498 static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2500 FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2502 return E_NOTIMPL;
2505 static const IComThreadingInfoVtbl thread_context_info_vtbl =
2507 thread_context_info_QueryInterface,
2508 thread_context_info_AddRef,
2509 thread_context_info_Release,
2510 thread_context_info_GetCurrentApartmentType,
2511 thread_context_info_GetCurrentThreadType,
2512 thread_context_info_GetCurrentLogicalThreadId,
2513 thread_context_info_SetCurrentLogicalThreadId
2516 static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2518 struct thread_context *context = impl_from_IContextCallback(iface);
2519 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2522 static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2524 struct thread_context *context = impl_from_IContextCallback(iface);
2525 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2528 static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2530 struct thread_context *context = impl_from_IContextCallback(iface);
2531 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2534 static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2535 PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2537 FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2539 return E_NOTIMPL;
2542 static const IContextCallbackVtbl thread_context_callback_vtbl =
2544 thread_context_callback_QueryInterface,
2545 thread_context_callback_AddRef,
2546 thread_context_callback_Release,
2547 thread_context_callback_ContextCallback
2550 static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2552 struct thread_context *context = impl_from_IObjContext(iface);
2553 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2556 static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2558 struct thread_context *context = impl_from_IObjContext(iface);
2559 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2562 static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2564 struct thread_context *context = impl_from_IObjContext(iface);
2565 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2568 static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2570 FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk);
2572 return E_NOTIMPL;
2575 static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2577 FIXME("%p, %s\n", iface, debugstr_guid(propid));
2579 return E_NOTIMPL;
2582 static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2584 FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2586 return E_NOTIMPL;
2589 static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2591 FIXME("%p, %p\n", iface, props);
2593 return E_NOTIMPL;
2596 static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2598 FIXME("%p\n", iface);
2601 static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2603 FIXME("%p\n", iface);
2606 static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2608 FIXME("%p\n", iface);
2611 static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2613 FIXME("%p\n", iface);
2616 static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2618 FIXME("%p\n", iface);
2621 static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2623 FIXME("%p\n", iface);
2626 static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2628 FIXME("%p\n", iface);
2631 static const IObjContextVtbl thread_object_context_vtbl =
2633 thread_object_context_QueryInterface,
2634 thread_object_context_AddRef,
2635 thread_object_context_Release,
2636 thread_object_context_SetProperty,
2637 thread_object_context_RemoveProperty,
2638 thread_object_context_GetProperty,
2639 thread_object_context_EnumContextProps,
2640 thread_object_context_Reserved1,
2641 thread_object_context_Reserved2,
2642 thread_object_context_Reserved3,
2643 thread_object_context_Reserved4,
2644 thread_object_context_Reserved5,
2645 thread_object_context_Reserved6,
2646 thread_object_context_Reserved7
2649 /***********************************************************************
2650 * CoGetContextToken (combase.@)
2652 HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2654 struct tlsdata *tlsdata;
2655 HRESULT hr;
2657 TRACE("%p\n", token);
2659 if (!InternalIsProcessInitialized())
2661 ERR("apartment not initialised\n");
2662 return CO_E_NOTINITIALIZED;
2665 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2666 return hr;
2668 if (!token)
2669 return E_POINTER;
2671 if (!tlsdata->context_token)
2673 struct thread_context *context;
2675 context = calloc(1, sizeof(*context));
2676 if (!context)
2677 return E_OUTOFMEMORY;
2679 context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2680 context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2681 context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2682 /* Context token does not take a reference, it's always zero until the
2683 interface is explicitly requested with CoGetObjectContext(). */
2684 context->refcount = 0;
2686 tlsdata->context_token = &context->IObjContext_iface;
2689 *token = (ULONG_PTR)tlsdata->context_token;
2690 TRACE("context_token %p\n", tlsdata->context_token);
2692 return S_OK;
2695 /***********************************************************************
2696 * CoGetCurrentLogicalThreadId (combase.@)
2698 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2700 struct tlsdata *tlsdata;
2701 HRESULT hr;
2703 if (!id)
2704 return E_INVALIDARG;
2706 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2707 return hr;
2709 if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2711 CoCreateGuid(&tlsdata->causality_id);
2712 tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2715 *id = tlsdata->causality_id;
2717 return S_OK;
2720 /******************************************************************************
2721 * CoGetCurrentProcess (combase.@)
2723 DWORD WINAPI CoGetCurrentProcess(void)
2725 struct tlsdata *tlsdata;
2727 if (FAILED(com_get_tlsdata(&tlsdata)))
2728 return 0;
2730 if (!tlsdata->thread_seqid)
2731 rpcss_get_next_seqid(&tlsdata->thread_seqid);
2733 return tlsdata->thread_seqid;
2736 /***********************************************************************
2737 * CoFreeUnusedLibrariesEx (combase.@)
2739 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2741 struct apartment *apt = com_get_current_apt();
2742 if (!apt)
2744 ERR("apartment not initialised\n");
2745 return;
2748 apartment_freeunusedlibraries(apt, unload_delay);
2752 * When locked, don't modify list (unless we add a new head), so that it's
2753 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
2755 static inline void lock_init_spies(struct tlsdata *tlsdata)
2757 tlsdata->spies_lock++;
2760 static void unlock_init_spies(struct tlsdata *tlsdata)
2762 struct init_spy *spy, *next;
2764 if (--tlsdata->spies_lock) return;
2766 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2768 if (spy->spy) continue;
2769 list_remove(&spy->entry);
2770 free(spy);
2774 /******************************************************************************
2775 * CoInitializeWOW (combase.@)
2777 HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2779 FIXME("%#lx, %#lx\n", arg1, arg2);
2781 return S_OK;
2784 /******************************************************************************
2785 * CoInitializeEx (combase.@)
2787 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2789 struct tlsdata *tlsdata;
2790 struct init_spy *cursor;
2791 HRESULT hr;
2793 TRACE("%p, %#lx\n", reserved, model);
2795 if (reserved)
2796 WARN("Unexpected reserved argument %p\n", reserved);
2798 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2799 return hr;
2801 if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2802 TRACE("Initializing the COM libraries\n");
2804 lock_init_spies(tlsdata);
2805 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2807 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2809 unlock_init_spies(tlsdata);
2811 hr = enter_apartment(tlsdata, model);
2813 lock_init_spies(tlsdata);
2814 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2816 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2818 unlock_init_spies(tlsdata);
2820 return hr;
2823 /***********************************************************************
2824 * CoUninitialize (combase.@)
2826 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2828 struct tlsdata *tlsdata;
2829 struct init_spy *cursor, *next;
2830 LONG lockcount;
2832 TRACE("\n");
2834 if (FAILED(com_get_tlsdata(&tlsdata)))
2835 return;
2837 lock_init_spies(tlsdata);
2838 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2840 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2842 unlock_init_spies(tlsdata);
2844 /* sanity check */
2845 if (!tlsdata->inits)
2847 ERR("Mismatched CoUninitialize\n");
2849 lock_init_spies(tlsdata);
2850 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2852 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2854 unlock_init_spies(tlsdata);
2856 return;
2859 leave_apartment(tlsdata);
2862 * Decrease the reference count.
2863 * If we are back to 0 locks on the COM library, make sure we free
2864 * all the associated data structures.
2866 lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2867 if (lockcount == 1)
2869 TRACE("Releasing the COM libraries\n");
2871 com_revoke_all_ps_clsids();
2872 DestroyRunningObjectTable();
2874 else if (lockcount < 1)
2876 ERR("Unbalanced lock count %ld\n", lockcount);
2877 InterlockedExchangeAdd(&com_lockcount, 1);
2880 lock_init_spies(tlsdata);
2881 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2883 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2885 unlock_init_spies(tlsdata);
2888 /***********************************************************************
2889 * CoIncrementMTAUsage (combase.@)
2891 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2893 TRACE("%p\n", cookie);
2895 return apartment_increment_mta_usage(cookie);
2898 /***********************************************************************
2899 * CoDecrementMTAUsage (combase.@)
2901 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2903 TRACE("%p\n", cookie);
2905 apartment_decrement_mta_usage(cookie);
2906 return S_OK;
2909 /***********************************************************************
2910 * CoGetApartmentType (combase.@)
2912 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2914 struct tlsdata *tlsdata;
2915 struct apartment *apt;
2916 HRESULT hr;
2918 TRACE("%p, %p\n", type, qualifier);
2920 if (!type || !qualifier)
2921 return E_INVALIDARG;
2923 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2924 return hr;
2926 if (!tlsdata->apt)
2927 *type = APTTYPE_CURRENT;
2928 else if (tlsdata->apt->multi_threaded)
2929 *type = APTTYPE_MTA;
2930 else if (tlsdata->apt->main)
2931 *type = APTTYPE_MAINSTA;
2932 else
2933 *type = APTTYPE_STA;
2935 *qualifier = APTTYPEQUALIFIER_NONE;
2937 if (!tlsdata->apt && (apt = apartment_get_mta()))
2939 apartment_release(apt);
2940 *type = APTTYPE_MTA;
2941 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2942 return S_OK;
2945 return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2948 /******************************************************************************
2949 * CoRegisterClassObject (combase.@)
2950 * BUGS
2951 * MSDN claims that multiple interface registrations are legal, but we
2952 * can't do that with our current implementation.
2954 HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2955 DWORD flags, DWORD *cookie)
2957 static LONG next_cookie;
2959 struct registered_class *newclass;
2960 IUnknown *found_object;
2961 struct apartment *apt;
2962 HRESULT hr = S_OK;
2964 TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2966 if (!cookie || !object)
2967 return E_INVALIDARG;
2969 if (!(apt = apartment_get_current_or_mta()))
2971 ERR("COM was not initialized\n");
2972 return CO_E_NOTINITIALIZED;
2975 *cookie = 0;
2977 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2978 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2979 if (flags & REGCLS_MULTIPLEUSE)
2980 clscontext |= CLSCTX_INPROC_SERVER;
2983 * First, check if the class is already registered.
2984 * If it is, this should cause an error.
2986 if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2988 if (flags & REGCLS_MULTIPLEUSE)
2990 if (clscontext & CLSCTX_LOCAL_SERVER)
2991 hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2992 IUnknown_Release(found_object);
2993 apartment_release(apt);
2994 return hr;
2997 IUnknown_Release(found_object);
2998 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2999 apartment_release(apt);
3000 return CO_E_OBJISREG;
3003 newclass = calloc(1, sizeof(*newclass));
3004 if (!newclass)
3006 apartment_release(apt);
3007 return E_OUTOFMEMORY;
3010 newclass->clsid = *rclsid;
3011 newclass->apartment_id = apt->oxid;
3012 newclass->clscontext = clscontext;
3013 newclass->flags = flags;
3015 if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
3016 newclass->cookie = InterlockedIncrement(&next_cookie);
3018 newclass->object = object;
3019 IUnknown_AddRef(newclass->object);
3021 EnterCriticalSection(&registered_classes_cs);
3022 list_add_tail(&registered_classes, &newclass->entry);
3023 LeaveCriticalSection(&registered_classes_cs);
3025 *cookie = newclass->cookie;
3027 if (clscontext & CLSCTX_LOCAL_SERVER)
3029 IStream *marshal_stream;
3031 hr = apartment_get_local_server_stream(apt, &marshal_stream);
3032 if(FAILED(hr))
3034 apartment_release(apt);
3035 return hr;
3038 hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
3039 IStream_Release(marshal_stream);
3042 apartment_release(apt);
3043 return S_OK;
3046 static void com_revoke_class_object(struct registered_class *entry)
3048 list_remove(&entry->entry);
3050 if (entry->clscontext & CLSCTX_LOCAL_SERVER)
3051 rpc_revoke_local_server(entry->rpcss_cookie);
3053 IUnknown_Release(entry->object);
3054 free(entry);
3057 /* Cleans up rpcss registry */
3058 static void com_revoke_local_servers(void)
3060 struct registered_class *cur, *cur2;
3062 EnterCriticalSection(&registered_classes_cs);
3064 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3066 if (cur->clscontext & CLSCTX_LOCAL_SERVER)
3067 com_revoke_class_object(cur);
3070 LeaveCriticalSection(&registered_classes_cs);
3073 void apartment_revoke_all_classes(const struct apartment *apt)
3075 struct registered_class *cur, *cur2;
3077 EnterCriticalSection(&registered_classes_cs);
3079 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3081 if (cur->apartment_id == apt->oxid)
3082 com_revoke_class_object(cur);
3085 LeaveCriticalSection(&registered_classes_cs);
3088 /***********************************************************************
3089 * CoRevokeClassObject (combase.@)
3091 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
3093 HRESULT hr = E_INVALIDARG;
3094 struct registered_class *cur;
3095 struct apartment *apt;
3097 TRACE("%#lx\n", cookie);
3099 if (!(apt = apartment_get_current_or_mta()))
3101 ERR("COM was not initialized\n");
3102 return CO_E_NOTINITIALIZED;
3105 EnterCriticalSection(&registered_classes_cs);
3107 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
3109 if (cur->cookie != cookie)
3110 continue;
3112 if (cur->apartment_id == apt->oxid)
3114 com_revoke_class_object(cur);
3115 hr = S_OK;
3117 else
3119 ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
3120 hr = RPC_E_WRONG_THREAD;
3123 break;
3126 LeaveCriticalSection(&registered_classes_cs);
3127 apartment_release(apt);
3129 return hr;
3132 /***********************************************************************
3133 * CoAddRefServerProcess (combase.@)
3135 ULONG WINAPI CoAddRefServerProcess(void)
3137 ULONG refs;
3139 TRACE("\n");
3141 EnterCriticalSection(&registered_classes_cs);
3142 refs = ++com_server_process_refcount;
3143 LeaveCriticalSection(&registered_classes_cs);
3145 TRACE("refs before: %ld\n", refs - 1);
3147 return refs;
3150 /***********************************************************************
3151 * CoReleaseServerProcess [OLE32.@]
3153 ULONG WINAPI CoReleaseServerProcess(void)
3155 ULONG refs;
3157 TRACE("\n");
3159 EnterCriticalSection(&registered_classes_cs);
3161 refs = --com_server_process_refcount;
3162 /* FIXME: suspend objects */
3164 LeaveCriticalSection(&registered_classes_cs);
3166 TRACE("refs after: %ld\n", refs);
3168 return refs;
3171 /******************************************************************************
3172 * CoDisconnectObject (combase.@)
3174 HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3176 struct stub_manager *manager;
3177 struct apartment *apt;
3178 IMarshal *marshal;
3179 HRESULT hr;
3181 TRACE("%p, %#lx\n", object, reserved);
3183 if (!object)
3184 return E_INVALIDARG;
3186 hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3187 if (hr == S_OK)
3189 hr = IMarshal_DisconnectObject(marshal, reserved);
3190 IMarshal_Release(marshal);
3191 return hr;
3194 if (!(apt = apartment_get_current_or_mta()))
3196 ERR("apartment not initialised\n");
3197 return CO_E_NOTINITIALIZED;
3200 manager = get_stub_manager_from_object(apt, object, FALSE);
3201 if (manager)
3203 stub_manager_disconnect(manager);
3204 /* Release stub manager twice, to remove the apartment reference. */
3205 stub_manager_int_release(manager);
3206 stub_manager_int_release(manager);
3209 /* Note: native is pretty broken here because it just silently
3210 * fails, without returning an appropriate error code if the object was
3211 * not found, making apps think that the object was disconnected, when
3212 * it actually wasn't */
3214 apartment_release(apt);
3215 return S_OK;
3218 /******************************************************************************
3219 * CoLockObjectExternal (combase.@)
3221 HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3223 struct stub_manager *stubmgr;
3224 struct apartment *apt;
3226 TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3228 if (!(apt = apartment_get_current_or_mta()))
3230 ERR("apartment not initialised\n");
3231 return CO_E_NOTINITIALIZED;
3234 stubmgr = get_stub_manager_from_object(apt, object, lock);
3235 if (!stubmgr)
3237 WARN("stub object not found %p\n", object);
3238 /* Note: native is pretty broken here because it just silently
3239 * fails, without returning an appropriate error code, making apps
3240 * think that the object was disconnected, when it actually wasn't */
3241 apartment_release(apt);
3242 return S_OK;
3245 if (lock)
3246 stub_manager_ext_addref(stubmgr, 1, FALSE);
3247 else
3248 stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3250 stub_manager_int_release(stubmgr);
3251 apartment_release(apt);
3252 return S_OK;
3255 /***********************************************************************
3256 * CoRegisterChannelHook (combase.@)
3258 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3260 TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3262 return rpc_register_channel_hook(guidExtension, channel_hook);
3265 /***********************************************************************
3266 * CoDisableCallCancellation (combase.@)
3268 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3270 struct tlsdata *tlsdata;
3271 HRESULT hr;
3273 TRACE("%p\n", reserved);
3275 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3276 return hr;
3278 if (!tlsdata->cancelcount)
3279 return CO_E_CANCEL_DISABLED;
3281 tlsdata->cancelcount--;
3283 return S_OK;
3286 /***********************************************************************
3287 * CoEnableCallCancellation (combase.@)
3289 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3291 struct tlsdata *tlsdata;
3292 HRESULT hr;
3294 TRACE("%p\n", reserved);
3296 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3297 return hr;
3299 tlsdata->cancelcount++;
3301 return S_OK;
3304 /***********************************************************************
3305 * CoGetCallerTID (combase.@)
3307 HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3309 FIXME("stub!\n");
3310 return E_NOTIMPL;
3313 /***********************************************************************
3314 * CoIsHandlerConnected (combase.@)
3316 BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3318 FIXME("%p\n", object);
3320 return TRUE;
3323 /***********************************************************************
3324 * CoSuspendClassObjects (combase.@)
3326 HRESULT WINAPI CoSuspendClassObjects(void)
3328 FIXME("\n");
3330 return S_OK;
3333 /***********************************************************************
3334 * CoResumeClassObjects (combase.@)
3336 HRESULT WINAPI CoResumeClassObjects(void)
3338 FIXME("stub\n");
3340 return S_OK;
3343 /***********************************************************************
3344 * CoRegisterSurrogate (combase.@)
3346 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3348 FIXME("%p stub\n", surrogate);
3350 return E_NOTIMPL;
3353 /***********************************************************************
3354 * CoRegisterSurrogateEx (combase.@)
3356 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3358 FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3360 return E_NOTIMPL;
3363 /***********************************************************************
3364 * DllMain (combase.@)
3366 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3368 TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved);
3370 switch (reason)
3372 case DLL_PROCESS_ATTACH:
3373 hProxyDll = hinstDLL;
3374 break;
3375 case DLL_PROCESS_DETACH:
3376 com_revoke_local_servers();
3377 if (reserved) break;
3378 apartment_global_cleanup();
3379 DeleteCriticalSection(&registered_classes_cs);
3380 rpc_unregister_channel_hooks();
3381 break;
3382 case DLL_THREAD_DETACH:
3383 com_cleanup_tlsdata();
3384 break;
3387 return TRUE;
3390 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj)
3392 TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj);
3394 *obj = NULL;
3396 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3397 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
3399 return CLASS_E_CLASSNOTAVAILABLE;