mfmediaengine: Handle Play() when called before topology is set.
[wine.git] / dlls / combase / combase.c
blob4677972656f2e4f0e8637cfc4d41d31ea84dfa75
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 #define NONAMELESSUNION
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #define USE_COM_CONTEXT_DEF
26 #include "objbase.h"
27 #include "ctxtcall.h"
28 #include "oleauto.h"
29 #include "dde.h"
30 #include "winternl.h"
32 #include "combase_private.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 HINSTANCE hProxyDll;
41 static ULONG_PTR global_options[COMGLB_PROPERTIES_RESERVED3 + 1];
43 /* Ole32 exports */
44 extern void WINAPI DestroyRunningObjectTable(void);
45 extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
48 * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
50 static LONG com_lockcount;
52 static LONG com_server_process_refcount;
54 struct comclassredirect_data
56 ULONG size;
57 ULONG flags;
58 DWORD model;
59 GUID clsid;
60 GUID alias;
61 GUID clsid2;
62 GUID tlbid;
63 ULONG name_len;
64 ULONG name_offset;
65 ULONG progid_len;
66 ULONG progid_offset;
67 ULONG clrdata_len;
68 ULONG clrdata_offset;
69 DWORD miscstatus;
70 DWORD miscstatuscontent;
71 DWORD miscstatusthumbnail;
72 DWORD miscstatusicon;
73 DWORD miscstatusdocprint;
76 struct ifacepsredirect_data
78 ULONG size;
79 DWORD mask;
80 GUID iid;
81 ULONG nummethods;
82 GUID tlbid;
83 GUID base;
84 ULONG name_len;
85 ULONG name_offset;
88 struct progidredirect_data
90 ULONG size;
91 DWORD reserved;
92 ULONG clsid_offset;
95 struct init_spy
97 struct list entry;
98 IInitializeSpy *spy;
99 unsigned int id;
102 struct registered_ps
104 struct list entry;
105 IID iid;
106 CLSID clsid;
109 static struct list registered_proxystubs = LIST_INIT(registered_proxystubs);
111 static CRITICAL_SECTION cs_registered_ps;
112 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
114 0, 0, &cs_registered_ps,
115 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
116 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
118 static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
120 struct registered_class
122 struct list entry;
123 CLSID clsid;
124 OXID apartment_id;
125 IUnknown *object;
126 DWORD clscontext;
127 DWORD flags;
128 unsigned int cookie;
129 unsigned int rpcss_cookie;
132 static struct list registered_classes = LIST_INIT(registered_classes);
134 static CRITICAL_SECTION registered_classes_cs;
135 static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
137 0, 0, &registered_classes_cs,
138 { &registered_classes_cs_debug.ProcessLocksList, &registered_classes_cs_debug.ProcessLocksList },
139 0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") }
141 static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
143 IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
145 struct registered_class *cur;
146 IUnknown *object = NULL;
148 EnterCriticalSection(&registered_classes_cs);
150 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
152 if ((apt->oxid == cur->apartment_id) &&
153 (clscontext & cur->clscontext) &&
154 IsEqualGUID(&cur->clsid, rclsid))
156 object = cur->object;
157 IUnknown_AddRef(cur->object);
158 break;
162 LeaveCriticalSection(&registered_classes_cs);
164 return object;
167 static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
169 struct init_spy *spy;
171 LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry)
173 if (id == spy->id && spy->spy)
174 return spy;
177 return NULL;
180 static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
182 NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
184 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
186 HANDLE subkey, root = attr->RootDirectory;
187 WCHAR *buffer = attr->ObjectName->Buffer;
188 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
189 UNICODE_STRING str;
191 while (i < len && buffer[i] != '\\') i++;
192 if (i == len) return status;
194 attrs = attr->Attributes;
195 attr->ObjectName = &str;
197 while (i < len)
199 str.Buffer = buffer + pos;
200 str.Length = (i - pos) * sizeof(WCHAR);
201 status = NtCreateKey(&subkey, access, attr, 0, NULL, 0, NULL);
202 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
203 if (status) return status;
204 attr->RootDirectory = subkey;
205 while (i < len && buffer[i] == '\\') i++;
206 pos = i;
207 while (i < len && buffer[i] != '\\') i++;
209 str.Buffer = buffer + pos;
210 str.Length = (i - pos) * sizeof(WCHAR);
211 attr->Attributes = attrs;
212 status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
213 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
215 return status;
218 static HKEY classes_root_hkey;
220 static HKEY create_classes_root_hkey(DWORD access)
222 HKEY hkey, ret = 0;
223 OBJECT_ATTRIBUTES attr;
224 UNICODE_STRING name;
226 attr.Length = sizeof(attr);
227 attr.RootDirectory = 0;
228 attr.ObjectName = &name;
229 attr.Attributes = 0;
230 attr.SecurityDescriptor = NULL;
231 attr.SecurityQualityOfService = NULL;
232 RtlInitUnicodeString(&name, L"\\Registry\\Machine\\Software\\Classes");
234 if (create_key( &hkey, access, &attr )) return 0;
235 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
237 if (!(access & KEY_WOW64_64KEY))
239 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
240 ret = hkey;
241 else
242 NtClose( hkey ); /* somebody beat us to it */
244 else
245 ret = hkey;
246 return ret;
249 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access);
251 static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
253 OBJECT_ATTRIBUTES attr;
254 UNICODE_STRING nameW;
256 if (!(hkey = get_classes_root_hkey(hkey, access)))
257 return ERROR_INVALID_HANDLE;
259 attr.Length = sizeof(attr);
260 attr.RootDirectory = hkey;
261 attr.ObjectName = &nameW;
262 attr.Attributes = 0;
263 attr.SecurityDescriptor = NULL;
264 attr.SecurityQualityOfService = NULL;
265 RtlInitUnicodeString( &nameW, name );
267 return RtlNtStatusToDosError(create_key(retkey, access, &attr));
270 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access)
272 HKEY ret = hkey;
273 const BOOL is_win64 = sizeof(void*) > sizeof(int);
274 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
276 if (hkey == HKEY_CLASSES_ROOT &&
277 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
278 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
279 if (force_wow32 && ret && ret == classes_root_hkey)
281 access &= ~KEY_WOW64_32KEY;
282 if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey))
283 return 0;
284 ret = hkey;
287 return ret;
290 static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
292 OBJECT_ATTRIBUTES attr;
293 UNICODE_STRING nameW;
295 if (!(hkey = get_classes_root_hkey(hkey, access)))
296 return ERROR_INVALID_HANDLE;
298 attr.Length = sizeof(attr);
299 attr.RootDirectory = hkey;
300 attr.ObjectName = &nameW;
301 attr.Attributes = 0;
302 attr.SecurityDescriptor = NULL;
303 attr.SecurityQualityOfService = NULL;
304 RtlInitUnicodeString( &nameW, name );
306 return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
309 HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
311 static const WCHAR clsidW[] = L"CLSID\\";
312 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
313 LONG res;
314 HKEY key;
316 lstrcpyW(path, clsidW);
317 StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID);
318 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
319 if (res == ERROR_FILE_NOT_FOUND)
320 return REGDB_E_CLASSNOTREG;
321 else if (res != ERROR_SUCCESS)
322 return REGDB_E_READREGDB;
324 if (!keyname)
326 *subkey = key;
327 return S_OK;
330 res = open_classes_key(key, keyname, access, subkey);
331 RegCloseKey(key);
332 if (res == ERROR_FILE_NOT_FOUND)
333 return REGDB_E_KEYMISSING;
334 else if (res != ERROR_SUCCESS)
335 return REGDB_E_READREGDB;
337 return S_OK;
340 /* open HKCR\\AppId\\{string form of appid clsid} key */
341 HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey)
343 static const WCHAR appidkeyW[] = L"AppId\\";
344 DWORD res;
345 WCHAR buf[CHARS_IN_GUID];
346 WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID];
347 DWORD size;
348 HKEY hkey;
349 DWORD type;
350 HRESULT hr;
352 /* read the AppID value under the class's key */
353 hr = open_key_for_clsid(clsid, NULL, KEY_READ, &hkey);
354 if (FAILED(hr))
355 return hr;
357 size = sizeof(buf);
358 res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size);
359 RegCloseKey(hkey);
360 if (res == ERROR_FILE_NOT_FOUND)
361 return REGDB_E_KEYMISSING;
362 else if (res != ERROR_SUCCESS || type!=REG_SZ)
363 return REGDB_E_READREGDB;
365 lstrcpyW(keyname, appidkeyW);
366 lstrcatW(keyname, buf);
367 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
368 if (res == ERROR_FILE_NOT_FOUND)
369 return REGDB_E_KEYMISSING;
370 else if (res != ERROR_SUCCESS)
371 return REGDB_E_READREGDB;
373 return S_OK;
376 /***********************************************************************
377 * InternalIsProcessInitialized (combase.@)
379 BOOL WINAPI InternalIsProcessInitialized(void)
381 struct apartment *apt;
383 if (!(apt = apartment_get_current_or_mta()))
384 return FALSE;
385 apartment_release(apt);
387 return TRUE;
390 /***********************************************************************
391 * InternalTlsAllocData (combase.@)
393 HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data)
395 if (!(*data = heap_alloc_zero(sizeof(**data))))
396 return E_OUTOFMEMORY;
398 list_init(&(*data)->spies);
399 NtCurrentTeb()->ReservedForOle = *data;
401 return S_OK;
404 static void com_cleanup_tlsdata(void)
406 struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle;
407 struct init_spy *cursor, *cursor2;
409 if (!tlsdata)
410 return;
412 if (tlsdata->apt)
413 apartment_release(tlsdata->apt);
414 if (tlsdata->errorinfo)
415 IErrorInfo_Release(tlsdata->errorinfo);
416 if (tlsdata->state)
417 IUnknown_Release(tlsdata->state);
419 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry)
421 list_remove(&cursor->entry);
422 if (cursor->spy)
423 IInitializeSpy_Release(cursor->spy);
424 heap_free(cursor);
427 if (tlsdata->context_token)
428 IObjContext_Release(tlsdata->context_token);
430 heap_free(tlsdata);
431 NtCurrentTeb()->ReservedForOle = NULL;
434 struct global_options
436 IGlobalOptions IGlobalOptions_iface;
437 LONG refcount;
440 static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface)
442 return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface);
445 static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
447 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
449 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
451 *ppv = iface;
453 else
455 *ppv = NULL;
456 return E_NOINTERFACE;
459 IUnknown_AddRef((IUnknown *)*ppv);
460 return S_OK;
463 static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface)
465 struct global_options *options = impl_from_IGlobalOptions(iface);
466 LONG refcount = InterlockedIncrement(&options->refcount);
468 TRACE("%p, refcount %d.\n", iface, refcount);
470 return refcount;
473 static ULONG WINAPI global_options_Release(IGlobalOptions *iface)
475 struct global_options *options = impl_from_IGlobalOptions(iface);
476 LONG refcount = InterlockedDecrement(&options->refcount);
478 TRACE("%p, refcount %d.\n", iface, refcount);
480 if (!refcount)
481 heap_free(options);
483 return refcount;
486 static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
488 FIXME("%p, %u, %lx.\n", iface, property, value);
490 return S_OK;
493 static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
495 TRACE("%p, %u, %p.\n", iface, property, value);
497 if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3)
498 return E_INVALIDARG;
500 *value = global_options[property];
502 return S_OK;
505 static const IGlobalOptionsVtbl global_options_vtbl =
507 global_options_QueryInterface,
508 global_options_AddRef,
509 global_options_Release,
510 global_options_Set,
511 global_options_Query
514 static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
516 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
518 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
520 *ppv = iface;
521 return S_OK;
524 *ppv = NULL;
525 return E_NOINTERFACE;
528 static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
530 return 2;
533 static ULONG WINAPI class_factory_Release(IClassFactory *iface)
535 return 1;
538 static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock)
540 TRACE("%d\n", fLock);
542 return S_OK;
545 static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
547 struct global_options *object;
548 HRESULT hr;
550 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv);
552 if (outer)
553 return E_INVALIDARG;
555 if (!(object = heap_alloc(sizeof(*object))))
556 return E_OUTOFMEMORY;
557 object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl;
558 object->refcount = 1;
560 hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv);
561 IGlobalOptions_Release(&object->IGlobalOptions_iface);
562 return hr;
565 static const IClassFactoryVtbl global_options_factory_vtbl =
567 class_factory_QueryInterface,
568 class_factory_AddRef,
569 class_factory_Release,
570 global_options_CreateInstance,
571 class_factory_LockServer
574 static IClassFactory global_options_factory = { &global_options_factory_vtbl };
576 static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj)
578 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
579 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
580 return E_UNEXPECTED;
583 /***********************************************************************
584 * FreePropVariantArray (combase.@)
586 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
588 ULONG i;
590 TRACE("%u, %p.\n", count, rgvars);
592 if (!rgvars)
593 return E_INVALIDARG;
595 for (i = 0; i < count; ++i)
596 PropVariantClear(&rgvars[i]);
598 return S_OK;
601 static HRESULT propvar_validatetype(VARTYPE vt)
603 switch (vt)
605 case VT_EMPTY:
606 case VT_NULL:
607 case VT_I1:
608 case VT_I2:
609 case VT_I4:
610 case VT_I8:
611 case VT_R4:
612 case VT_R8:
613 case VT_CY:
614 case VT_DATE:
615 case VT_BSTR:
616 case VT_ERROR:
617 case VT_BOOL:
618 case VT_DECIMAL:
619 case VT_UI1:
620 case VT_UI2:
621 case VT_UI4:
622 case VT_UI8:
623 case VT_INT:
624 case VT_UINT:
625 case VT_LPSTR:
626 case VT_LPWSTR:
627 case VT_FILETIME:
628 case VT_BLOB:
629 case VT_DISPATCH:
630 case VT_UNKNOWN:
631 case VT_STREAM:
632 case VT_STORAGE:
633 case VT_STREAMED_OBJECT:
634 case VT_STORED_OBJECT:
635 case VT_BLOB_OBJECT:
636 case VT_CF:
637 case VT_CLSID:
638 case VT_I1|VT_VECTOR:
639 case VT_I2|VT_VECTOR:
640 case VT_I4|VT_VECTOR:
641 case VT_I8|VT_VECTOR:
642 case VT_R4|VT_VECTOR:
643 case VT_R8|VT_VECTOR:
644 case VT_CY|VT_VECTOR:
645 case VT_DATE|VT_VECTOR:
646 case VT_BSTR|VT_VECTOR:
647 case VT_ERROR|VT_VECTOR:
648 case VT_BOOL|VT_VECTOR:
649 case VT_VARIANT|VT_VECTOR:
650 case VT_UI1|VT_VECTOR:
651 case VT_UI2|VT_VECTOR:
652 case VT_UI4|VT_VECTOR:
653 case VT_UI8|VT_VECTOR:
654 case VT_LPSTR|VT_VECTOR:
655 case VT_LPWSTR|VT_VECTOR:
656 case VT_FILETIME|VT_VECTOR:
657 case VT_CF|VT_VECTOR:
658 case VT_CLSID|VT_VECTOR:
659 case VT_ARRAY|VT_I1:
660 case VT_ARRAY|VT_UI1:
661 case VT_ARRAY|VT_I2:
662 case VT_ARRAY|VT_UI2:
663 case VT_ARRAY|VT_I4:
664 case VT_ARRAY|VT_UI4:
665 case VT_ARRAY|VT_INT:
666 case VT_ARRAY|VT_UINT:
667 case VT_ARRAY|VT_R4:
668 case VT_ARRAY|VT_R8:
669 case VT_ARRAY|VT_CY:
670 case VT_ARRAY|VT_DATE:
671 case VT_ARRAY|VT_BSTR:
672 case VT_ARRAY|VT_BOOL:
673 case VT_ARRAY|VT_DECIMAL:
674 case VT_ARRAY|VT_DISPATCH:
675 case VT_ARRAY|VT_UNKNOWN:
676 case VT_ARRAY|VT_ERROR:
677 case VT_ARRAY|VT_VARIANT:
678 return S_OK;
680 WARN("Bad type %d\n", vt);
681 return STG_E_INVALIDPARAMETER;
684 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
686 ULONG i;
687 for (i = 0; i < count; ++i)
688 CoTaskMemFree(data[i].pClipData);
691 /***********************************************************************
692 * PropVariantClear (combase.@)
694 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
696 HRESULT hr;
698 TRACE("%p.\n", pvar);
700 if (!pvar)
701 return S_OK;
703 hr = propvar_validatetype(pvar->vt);
704 if (FAILED(hr))
706 memset(pvar, 0, sizeof(*pvar));
707 return hr;
710 switch (pvar->vt)
712 case VT_EMPTY:
713 case VT_NULL:
714 case VT_I1:
715 case VT_I2:
716 case VT_I4:
717 case VT_I8:
718 case VT_R4:
719 case VT_R8:
720 case VT_CY:
721 case VT_DATE:
722 case VT_ERROR:
723 case VT_BOOL:
724 case VT_DECIMAL:
725 case VT_UI1:
726 case VT_UI2:
727 case VT_UI4:
728 case VT_UI8:
729 case VT_INT:
730 case VT_UINT:
731 case VT_FILETIME:
732 break;
733 case VT_DISPATCH:
734 case VT_UNKNOWN:
735 case VT_STREAM:
736 case VT_STREAMED_OBJECT:
737 case VT_STORAGE:
738 case VT_STORED_OBJECT:
739 if (pvar->pStream)
740 IStream_Release(pvar->pStream);
741 break;
742 case VT_CLSID:
743 case VT_LPSTR:
744 case VT_LPWSTR:
745 /* pick an arbitrary typed pointer - we don't care about the type
746 * as we are just freeing it */
747 CoTaskMemFree(pvar->puuid);
748 break;
749 case VT_BLOB:
750 case VT_BLOB_OBJECT:
751 CoTaskMemFree(pvar->blob.pBlobData);
752 break;
753 case VT_BSTR:
754 SysFreeString(pvar->bstrVal);
755 break;
756 case VT_CF:
757 if (pvar->pclipdata)
759 propvar_free_cf_array(1, pvar->pclipdata);
760 CoTaskMemFree(pvar->pclipdata);
762 break;
763 default:
764 if (pvar->vt & VT_VECTOR)
766 ULONG i;
768 switch (pvar->vt & ~VT_VECTOR)
770 case VT_VARIANT:
771 FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems);
772 break;
773 case VT_CF:
774 propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems);
775 break;
776 case VT_BSTR:
777 for (i = 0; i < pvar->cabstr.cElems; i++)
778 SysFreeString(pvar->cabstr.pElems[i]);
779 break;
780 case VT_LPSTR:
781 for (i = 0; i < pvar->calpstr.cElems; i++)
782 CoTaskMemFree(pvar->calpstr.pElems[i]);
783 break;
784 case VT_LPWSTR:
785 for (i = 0; i < pvar->calpwstr.cElems; i++)
786 CoTaskMemFree(pvar->calpwstr.pElems[i]);
787 break;
789 if (pvar->vt & ~VT_VECTOR)
791 /* pick an arbitrary VT_VECTOR structure - they all have the same
792 * memory layout */
793 CoTaskMemFree(pvar->capropvar.pElems);
796 else if (pvar->vt & VT_ARRAY)
797 hr = SafeArrayDestroy(pvar->parray);
798 else
800 WARN("Invalid/unsupported type %d\n", pvar->vt);
801 hr = STG_E_INVALIDPARAMETER;
805 memset(pvar, 0, sizeof(*pvar));
806 return hr;
809 /***********************************************************************
810 * PropVariantCopy (combase.@)
812 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
814 ULONG len;
815 HRESULT hr;
817 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
819 hr = propvar_validatetype(pvarSrc->vt);
820 if (FAILED(hr))
821 return DISP_E_BADVARTYPE;
823 /* this will deal with most cases */
824 *pvarDest = *pvarSrc;
826 switch (pvarSrc->vt)
828 case VT_EMPTY:
829 case VT_NULL:
830 case VT_I1:
831 case VT_UI1:
832 case VT_I2:
833 case VT_UI2:
834 case VT_BOOL:
835 case VT_DECIMAL:
836 case VT_I4:
837 case VT_UI4:
838 case VT_R4:
839 case VT_ERROR:
840 case VT_I8:
841 case VT_UI8:
842 case VT_INT:
843 case VT_UINT:
844 case VT_R8:
845 case VT_CY:
846 case VT_DATE:
847 case VT_FILETIME:
848 break;
849 case VT_DISPATCH:
850 case VT_UNKNOWN:
851 case VT_STREAM:
852 case VT_STREAMED_OBJECT:
853 case VT_STORAGE:
854 case VT_STORED_OBJECT:
855 if (pvarDest->pStream)
856 IStream_AddRef(pvarDest->pStream);
857 break;
858 case VT_CLSID:
859 pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID));
860 *pvarDest->puuid = *pvarSrc->puuid;
861 break;
862 case VT_LPSTR:
863 if (pvarSrc->pszVal)
865 len = strlen(pvarSrc->pszVal);
866 pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
867 CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR));
869 break;
870 case VT_LPWSTR:
871 if (pvarSrc->pwszVal)
873 len = lstrlenW(pvarSrc->pwszVal);
874 pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
875 CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR));
877 break;
878 case VT_BLOB:
879 case VT_BLOB_OBJECT:
880 if (pvarSrc->blob.pBlobData)
882 len = pvarSrc->blob.cbSize;
883 pvarDest->blob.pBlobData = CoTaskMemAlloc(len);
884 CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len);
886 break;
887 case VT_BSTR:
888 pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal);
889 break;
890 case VT_CF:
891 if (pvarSrc->pclipdata)
893 len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt);
894 pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
895 pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize;
896 pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt;
897 pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len);
898 CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len);
900 break;
901 default:
902 if (pvarSrc->vt & VT_VECTOR)
904 int elemSize;
905 ULONG i;
907 switch (pvarSrc->vt & ~VT_VECTOR)
909 case VT_I1: elemSize = sizeof(pvarSrc->cVal); break;
910 case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break;
911 case VT_I2: elemSize = sizeof(pvarSrc->iVal); break;
912 case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break;
913 case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break;
914 case VT_I4: elemSize = sizeof(pvarSrc->lVal); break;
915 case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break;
916 case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break;
917 case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break;
918 case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break;
919 case VT_I8: elemSize = sizeof(pvarSrc->hVal); break;
920 case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break;
921 case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break;
922 case VT_DATE: elemSize = sizeof(pvarSrc->date); break;
923 case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break;
924 case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break;
925 case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break;
926 case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break;
927 case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break;
928 case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break;
929 case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break;
931 default:
932 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
933 return E_INVALIDARG;
935 len = pvarSrc->capropvar.cElems;
936 pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
937 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
939 for (i = 0; i < len; i++)
940 PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]);
942 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
944 FIXME("Copy clipformats\n");
946 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
948 for (i = 0; i < len; i++)
949 pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]);
951 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
953 size_t strLen;
954 for (i = 0; i < len; i++)
956 strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1;
957 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
958 memcpy(pvarDest->calpstr.pElems[i],
959 pvarSrc->calpstr.pElems[i], strLen);
962 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
964 size_t strLen;
965 for (i = 0; i < len; i++)
967 strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) *
968 sizeof(WCHAR);
969 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
970 memcpy(pvarDest->calpstr.pElems[i],
971 pvarSrc->calpstr.pElems[i], strLen);
974 else
975 CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize);
977 else if (pvarSrc->vt & VT_ARRAY)
979 pvarDest->uhVal.QuadPart = 0;
980 return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray);
982 else
983 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
986 return S_OK;
989 /***********************************************************************
990 * CoFileTimeNow (combase.@)
992 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
994 GetSystemTimeAsFileTime(filetime);
995 return S_OK;
998 /******************************************************************************
999 * CoCreateGuid (combase.@)
1001 HRESULT WINAPI CoCreateGuid(GUID *guid)
1003 RPC_STATUS status;
1005 if (!guid) return E_INVALIDARG;
1007 status = UuidCreate(guid);
1008 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1009 return HRESULT_FROM_WIN32(status);
1012 /******************************************************************************
1013 * CoQueryProxyBlanket (combase.@)
1015 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
1016 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
1017 DWORD *imp_level, void **auth_info, DWORD *capabilities)
1019 IClientSecurity *client_security;
1020 HRESULT hr;
1022 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
1023 auth_info, capabilities);
1025 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1026 if (SUCCEEDED(hr))
1028 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
1029 authn_level, imp_level, auth_info, capabilities);
1030 IClientSecurity_Release(client_security);
1033 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
1034 return hr;
1037 /******************************************************************************
1038 * CoSetProxyBlanket (combase.@)
1040 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
1041 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
1043 IClientSecurity *client_security;
1044 HRESULT hr;
1046 TRACE("%p, %u, %u, %p, %u, %u, %p, %#x.\n", proxy, authn_service, authz_service, servername,
1047 authn_level, imp_level, auth_info, capabilities);
1049 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1050 if (SUCCEEDED(hr))
1052 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
1053 imp_level, auth_info, capabilities);
1054 IClientSecurity_Release(client_security);
1057 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
1058 return hr;
1061 /***********************************************************************
1062 * CoCopyProxy (combase.@)
1064 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
1066 IClientSecurity *client_security;
1067 HRESULT hr;
1069 TRACE("%p, %p.\n", proxy, proxy_copy);
1071 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1072 if (SUCCEEDED(hr))
1074 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
1075 IClientSecurity_Release(client_security);
1078 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
1079 return hr;
1082 /***********************************************************************
1083 * CoQueryClientBlanket (combase.@)
1085 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
1086 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
1088 IServerSecurity *server_security;
1089 HRESULT hr;
1091 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
1092 privs, capabilities);
1094 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1095 if (SUCCEEDED(hr))
1097 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
1098 imp_level, privs, capabilities);
1099 IServerSecurity_Release(server_security);
1102 return hr;
1105 /***********************************************************************
1106 * CoImpersonateClient (combase.@)
1108 HRESULT WINAPI CoImpersonateClient(void)
1110 IServerSecurity *server_security;
1111 HRESULT hr;
1113 TRACE("\n");
1115 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1116 if (SUCCEEDED(hr))
1118 hr = IServerSecurity_ImpersonateClient(server_security);
1119 IServerSecurity_Release(server_security);
1122 return hr;
1125 /***********************************************************************
1126 * CoRevertToSelf (combase.@)
1128 HRESULT WINAPI CoRevertToSelf(void)
1130 IServerSecurity *server_security;
1131 HRESULT hr;
1133 TRACE("\n");
1135 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1136 if (SUCCEEDED(hr))
1138 hr = IServerSecurity_RevertToSelf(server_security);
1139 IServerSecurity_Release(server_security);
1142 return hr;
1145 /***********************************************************************
1146 * CoInitializeSecurity (combase.@)
1148 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
1149 SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
1150 DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1152 FIXME("%p, %d, %p, %p, %d, %d, %p, %d, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1153 imp_level, reserved2, capabilities, reserved3);
1155 return S_OK;
1158 /***********************************************************************
1159 * CoGetObjectContext (combase.@)
1161 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1163 IObjContext *context;
1164 HRESULT hr;
1166 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1168 *ppv = NULL;
1169 hr = CoGetContextToken((ULONG_PTR *)&context);
1170 if (FAILED(hr))
1171 return hr;
1173 return IObjContext_QueryInterface(context, riid, ppv);
1176 /***********************************************************************
1177 * CoGetDefaultContext (combase.@)
1179 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1181 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1183 return E_NOINTERFACE;
1186 /***********************************************************************
1187 * CoGetCallState (combase.@)
1189 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1191 FIXME("%d, %p.\n", arg1, arg2);
1193 return E_NOTIMPL;
1196 /***********************************************************************
1197 * CoGetActivationState (combase.@)
1199 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1201 FIXME("%s, %x, %p.\n", debugstr_guid(&guid), arg2, arg3);
1203 return E_NOTIMPL;
1206 /******************************************************************************
1207 * CoGetTreatAsClass (combase.@)
1209 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1211 WCHAR buffW[CHARS_IN_GUID];
1212 LONG len = sizeof(buffW);
1213 HRESULT hr = S_OK;
1214 HKEY hkey = NULL;
1216 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1218 if (!clsidOld || !clsidNew)
1219 return E_INVALIDARG;
1221 *clsidNew = *clsidOld;
1223 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1224 if (FAILED(hr))
1226 hr = S_FALSE;
1227 goto done;
1230 if (RegQueryValueW(hkey, NULL, buffW, &len))
1232 hr = S_FALSE;
1233 goto done;
1236 hr = CLSIDFromString(buffW, clsidNew);
1237 if (FAILED(hr))
1238 ERR("Failed to get CLSID from string %s, hr %#x.\n", debugstr_w(buffW), hr);
1239 done:
1240 if (hkey) RegCloseKey(hkey);
1241 return hr;
1244 /******************************************************************************
1245 * ProgIDFromCLSID (combase.@)
1247 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1249 ACTCTX_SECTION_KEYED_DATA data;
1250 LONG progidlen = 0;
1251 HKEY hkey;
1252 HRESULT hr;
1254 if (!progid)
1255 return E_INVALIDARG;
1257 *progid = NULL;
1259 data.cbSize = sizeof(data);
1260 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
1261 clsid, &data))
1263 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1264 if (comclass->progid_len)
1266 WCHAR *ptrW;
1268 *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
1269 if (!*progid) return E_OUTOFMEMORY;
1271 ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
1272 memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
1273 return S_OK;
1275 else
1276 return REGDB_E_CLASSNOTREG;
1279 hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
1280 if (FAILED(hr))
1281 return hr;
1283 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1284 hr = REGDB_E_CLASSNOTREG;
1286 if (hr == S_OK)
1288 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1289 if (*progid)
1291 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1293 hr = REGDB_E_CLASSNOTREG;
1294 CoTaskMemFree(*progid);
1295 *progid = NULL;
1298 else
1299 hr = E_OUTOFMEMORY;
1302 RegCloseKey(hkey);
1303 return hr;
1306 static inline BOOL is_valid_hex(WCHAR c)
1308 if (!(((c >= '0') && (c <= '9')) ||
1309 ((c >= 'a') && (c <= 'f')) ||
1310 ((c >= 'A') && (c <= 'F'))))
1311 return FALSE;
1312 return TRUE;
1315 static const BYTE guid_conv_table[256] =
1317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1320 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1321 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1323 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1326 static BOOL guid_from_string(LPCWSTR s, GUID *id)
1328 int i;
1330 if (!s || s[0] != '{')
1332 memset(id, 0, sizeof(*id));
1333 if (!s) return TRUE;
1334 return FALSE;
1337 TRACE("%s -> %p\n", debugstr_w(s), id);
1339 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1341 id->Data1 = 0;
1342 for (i = 1; i < 9; ++i)
1344 if (!is_valid_hex(s[i])) return FALSE;
1345 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1347 if (s[9] != '-') return FALSE;
1349 id->Data2 = 0;
1350 for (i = 10; i < 14; ++i)
1352 if (!is_valid_hex(s[i])) return FALSE;
1353 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1355 if (s[14] != '-') return FALSE;
1357 id->Data3 = 0;
1358 for (i = 15; i < 19; ++i)
1360 if (!is_valid_hex(s[i])) return FALSE;
1361 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1363 if (s[19] != '-') return FALSE;
1365 for (i = 20; i < 37; i += 2)
1367 if (i == 24)
1369 if (s[i] != '-') return FALSE;
1370 i++;
1372 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1373 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1376 if (s[37] == '}' && s[38] == '\0')
1377 return TRUE;
1379 return FALSE;
1382 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1384 WCHAR buf2[CHARS_IN_GUID];
1385 LONG buf2len = sizeof(buf2);
1386 HKEY xhkey;
1387 WCHAR *buf;
1389 memset(clsid, 0, sizeof(*clsid));
1390 buf = heap_alloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1391 if (!buf) return E_OUTOFMEMORY;
1393 lstrcpyW(buf, progid);
1394 lstrcatW(buf, L"\\CLSID");
1395 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1397 heap_free(buf);
1398 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1399 return CO_E_CLASSSTRING;
1401 heap_free(buf);
1403 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1405 RegCloseKey(xhkey);
1406 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1407 return CO_E_CLASSSTRING;
1409 RegCloseKey(xhkey);
1410 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1413 /******************************************************************************
1414 * CLSIDFromProgID (combase.@)
1416 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1418 ACTCTX_SECTION_KEYED_DATA data;
1420 if (!progid || !clsid)
1421 return E_INVALIDARG;
1423 data.cbSize = sizeof(data);
1424 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1425 progid, &data))
1427 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1428 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1429 *clsid = *alias;
1430 return S_OK;
1433 return clsid_from_string_reg(progid, clsid);
1436 /******************************************************************************
1437 * CLSIDFromProgIDEx (combase.@)
1439 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1441 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1443 return CLSIDFromProgID(progid, clsid);
1446 /******************************************************************************
1447 * CLSIDFromString (combase.@)
1449 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1451 CLSID tmp_id;
1452 HRESULT hr;
1454 if (!clsid)
1455 return E_INVALIDARG;
1457 if (guid_from_string(str, clsid))
1458 return S_OK;
1460 /* It appears a ProgID is also valid */
1461 hr = clsid_from_string_reg(str, &tmp_id);
1462 if (SUCCEEDED(hr))
1463 *clsid = tmp_id;
1465 return hr;
1468 /******************************************************************************
1469 * IIDFromString (combase.@)
1471 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1473 TRACE("%s, %p\n", debugstr_w(str), iid);
1475 if (!str)
1477 memset(iid, 0, sizeof(*iid));
1478 return S_OK;
1481 /* length mismatch is a special case */
1482 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1483 return E_INVALIDARG;
1485 if (str[0] != '{')
1486 return CO_E_IIDSTRING;
1488 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1491 /******************************************************************************
1492 * StringFromCLSID (combase.@)
1494 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1496 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1497 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1498 return S_OK;
1501 /******************************************************************************
1502 * StringFromGUID2 (combase.@)
1504 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1506 if (!guid || cmax < CHARS_IN_GUID) return 0;
1507 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1508 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1509 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1510 return CHARS_IN_GUID;
1513 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1515 ULONG i;
1517 for (i = 0; i < count; i++)
1519 mqi[i].pItf = NULL;
1520 mqi[i].hr = hr;
1524 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1526 ULONG index = 0, fetched = 0;
1528 if (include_unk)
1530 mqi[0].hr = S_OK;
1531 mqi[0].pItf = unk;
1532 index = fetched = 1;
1535 for (; index < count; index++)
1537 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1538 if (mqi[index].hr == S_OK)
1539 fetched++;
1542 if (!include_unk)
1543 IUnknown_Release(unk);
1545 if (fetched == 0)
1546 return E_NOINTERFACE;
1548 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1551 /***********************************************************************
1552 * CoGetInstanceFromFile (combase.@)
1554 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1555 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1556 MULTI_QI *results)
1558 IPersistFile *pf = NULL;
1559 IUnknown *obj = NULL;
1560 CLSID clsid;
1561 HRESULT hr;
1563 if (!count || !results)
1564 return E_INVALIDARG;
1566 if (server_info)
1567 FIXME("() non-NULL server_info not supported\n");
1569 init_multi_qi(count, results, E_NOINTERFACE);
1571 if (!rclsid)
1573 hr = GetClassFile(filename, &clsid);
1574 if (FAILED(hr))
1576 ERR("Failed to get CLSID from a file.\n");
1577 return hr;
1580 rclsid = &clsid;
1583 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1584 if (hr != S_OK)
1586 init_multi_qi(count, results, hr);
1587 return hr;
1590 /* Init from file */
1591 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1592 if (FAILED(hr))
1594 init_multi_qi(count, results, hr);
1595 IUnknown_Release(obj);
1596 return hr;
1599 hr = IPersistFile_Load(pf, filename, grfmode);
1600 IPersistFile_Release(pf);
1601 if (SUCCEEDED(hr))
1602 return return_multi_qi(obj, count, results, FALSE);
1603 else
1605 init_multi_qi(count, results, hr);
1606 IUnknown_Release(obj);
1607 return hr;
1611 /***********************************************************************
1612 * CoGetInstanceFromIStorage (combase.@)
1614 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1615 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1617 IPersistStorage *ps = NULL;
1618 IUnknown *obj = NULL;
1619 STATSTG stat;
1620 HRESULT hr;
1622 if (!count || !results || !storage)
1623 return E_INVALIDARG;
1625 if (server_info)
1626 FIXME("() non-NULL server_info not supported\n");
1628 init_multi_qi(count, results, E_NOINTERFACE);
1630 if (!rclsid)
1632 memset(&stat.clsid, 0, sizeof(stat.clsid));
1633 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1634 if (FAILED(hr))
1636 ERR("Failed to get CLSID from a storage.\n");
1637 return hr;
1640 rclsid = &stat.clsid;
1643 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1644 if (hr != S_OK)
1645 return hr;
1647 /* Init from IStorage */
1648 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1649 if (FAILED(hr))
1650 ERR("failed to get IPersistStorage\n");
1652 if (ps)
1654 IPersistStorage_Load(ps, storage);
1655 IPersistStorage_Release(ps);
1658 return return_multi_qi(obj, count, results, FALSE);
1661 /***********************************************************************
1662 * CoCreateInstance (combase.@)
1664 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1665 REFIID riid, void **obj)
1667 MULTI_QI multi_qi = { .pIID = riid };
1668 HRESULT hr;
1670 TRACE("%s, %p, %#x, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1672 if (!obj)
1673 return E_POINTER;
1675 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1676 *obj = multi_qi.pItf;
1677 return hr;
1680 /***********************************************************************
1681 * CoCreateInstanceFromApp (combase.@)
1683 HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1684 void *server_info, ULONG count, MULTI_QI *results)
1686 TRACE("%s, %p, %#x, %p, %u, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1687 count, results);
1689 return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1690 count, results);
1693 static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1694 COSERVERINFO *server_info, REFIID riid, void **obj)
1696 struct class_reg_data clsreg = { 0 };
1697 HRESULT hr = E_UNEXPECTED;
1698 IUnknown *registered_obj;
1699 struct apartment *apt;
1701 if (!obj)
1702 return E_INVALIDARG;
1704 *obj = NULL;
1706 if (!(apt = apartment_get_current_or_mta()))
1708 ERR("apartment not initialised\n");
1709 return CO_E_NOTINITIALIZED;
1712 if (server_info)
1713 FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1715 if (clscontext & CLSCTX_INPROC_SERVER)
1717 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1718 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1719 (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1720 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1722 apartment_release(apt);
1724 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
1725 return get_builtin_class_factory(rclsid, riid, obj);
1726 else
1727 return Ole32DllGetClassObject(rclsid, riid, obj);
1731 if (clscontext & CLSCTX_INPROC)
1733 ACTCTX_SECTION_KEYED_DATA data;
1735 data.cbSize = sizeof(data);
1736 /* search activation context first */
1737 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1738 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1740 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1742 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1743 clsreg.u.actctx.hactctx = data.hActCtx;
1744 clsreg.u.actctx.threading_model = comclass->model;
1745 clsreg.origin = CLASS_REG_ACTCTX;
1747 hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1748 ReleaseActCtx(data.hActCtx);
1749 apartment_release(apt);
1750 return hr;
1755 * First, try and see if we can't match the class ID with one of the
1756 * registered classes.
1758 if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1760 hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1761 IUnknown_Release(registered_obj);
1762 apartment_release(apt);
1763 return hr;
1766 /* First try in-process server */
1767 if (clscontext & CLSCTX_INPROC_SERVER)
1769 HKEY hkey;
1771 hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1772 if (FAILED(hr))
1774 if (hr == REGDB_E_CLASSNOTREG)
1775 ERR("class %s not registered\n", debugstr_guid(rclsid));
1776 else if (hr == REGDB_E_KEYMISSING)
1778 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1779 hr = REGDB_E_CLASSNOTREG;
1783 if (SUCCEEDED(hr))
1785 clsreg.u.hkey = hkey;
1786 clsreg.origin = CLASS_REG_REGISTRY;
1788 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1789 RegCloseKey(hkey);
1792 /* return if we got a class, otherwise fall through to one of the
1793 * other types */
1794 if (SUCCEEDED(hr))
1796 apartment_release(apt);
1797 return hr;
1801 /* Next try in-process handler */
1802 if (clscontext & CLSCTX_INPROC_HANDLER)
1804 HKEY hkey;
1806 hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1807 if (FAILED(hr))
1809 if (hr == REGDB_E_CLASSNOTREG)
1810 ERR("class %s not registered\n", debugstr_guid(rclsid));
1811 else if (hr == REGDB_E_KEYMISSING)
1813 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1814 hr = REGDB_E_CLASSNOTREG;
1818 if (SUCCEEDED(hr))
1820 clsreg.u.hkey = hkey;
1821 clsreg.origin = CLASS_REG_REGISTRY;
1823 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1824 RegCloseKey(hkey);
1827 /* return if we got a class, otherwise fall through to one of the
1828 * other types */
1829 if (SUCCEEDED(hr))
1831 apartment_release(apt);
1832 return hr;
1835 apartment_release(apt);
1837 /* Next try out of process */
1838 if (clscontext & CLSCTX_LOCAL_SERVER)
1840 hr = rpc_get_local_class_object(rclsid, riid, obj);
1841 if (SUCCEEDED(hr))
1842 return hr;
1845 /* Finally try remote: this requires networked DCOM (a lot of work) */
1846 if (clscontext & CLSCTX_REMOTE_SERVER)
1848 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1849 hr = REGDB_E_CLASSNOTREG;
1852 if (FAILED(hr))
1853 ERR("no class object %s could be created for context %#x\n", debugstr_guid(rclsid), clscontext);
1855 return hr;
1858 /***********************************************************************
1859 * CoCreateInstanceEx (combase.@)
1861 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1862 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1864 IClassFactory *factory;
1865 IUnknown *unk = NULL;
1866 CLSID clsid;
1867 HRESULT hr;
1869 TRACE("%s, %p, %#x, %p, %u, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1871 if (!count || !results)
1872 return E_INVALIDARG;
1874 if (server_info)
1875 FIXME("Server info is not supported.\n");
1877 init_multi_qi(count, results, E_NOINTERFACE);
1879 clsid = *rclsid;
1880 if (!(cls_context & CLSCTX_APPCONTAINER))
1881 CoGetTreatAsClass(rclsid, &clsid);
1883 if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1884 return hr;
1886 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1887 IClassFactory_Release(factory);
1888 if (FAILED(hr))
1890 if (hr == CLASS_E_NOAGGREGATION && outer)
1891 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1892 else
1893 FIXME("no instance created for interface %s of class %s, hr %#x.\n",
1894 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1895 return hr;
1898 return return_multi_qi(unk, count, results, TRUE);
1901 /***********************************************************************
1902 * CoGetClassObject (combase.@)
1904 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1905 COSERVERINFO *server_info, REFIID riid, void **obj)
1907 TRACE("%s, %#x, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1909 return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1912 /***********************************************************************
1913 * CoFreeUnusedLibraries (combase.@)
1915 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1917 CoFreeUnusedLibrariesEx(INFINITE, 0);
1920 /***********************************************************************
1921 * CoGetCallContext (combase.@)
1923 HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1925 struct tlsdata *tlsdata;
1926 HRESULT hr;
1928 TRACE("%s, %p\n", debugstr_guid(riid), obj);
1930 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1931 return hr;
1933 if (!tlsdata->call_state)
1934 return RPC_E_CALL_COMPLETE;
1936 return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1939 /***********************************************************************
1940 * CoSwitchCallContext (combase.@)
1942 HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1944 struct tlsdata *tlsdata;
1945 HRESULT hr;
1947 TRACE("%p, %p\n", context, old_context);
1949 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1950 return hr;
1952 /* Reference counts are not touched. */
1953 *old_context = tlsdata->call_state;
1954 tlsdata->call_state = context;
1956 return S_OK;
1959 /******************************************************************************
1960 * CoRegisterInitializeSpy (combase.@)
1962 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1964 struct tlsdata *tlsdata;
1965 struct init_spy *entry;
1966 unsigned int id;
1967 HRESULT hr;
1969 TRACE("%p, %p\n", spy, cookie);
1971 if (!spy || !cookie)
1972 return E_INVALIDARG;
1974 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1975 return hr;
1977 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1978 if (FAILED(hr))
1979 return hr;
1981 entry = heap_alloc(sizeof(*entry));
1982 if (!entry)
1984 IInitializeSpy_Release(spy);
1985 return E_OUTOFMEMORY;
1988 entry->spy = spy;
1990 id = 0;
1991 while (get_spy_entry(tlsdata, id) != NULL)
1993 id++;
1996 entry->id = id;
1997 list_add_head(&tlsdata->spies, &entry->entry);
1999 cookie->u.HighPart = GetCurrentThreadId();
2000 cookie->u.LowPart = entry->id;
2002 return S_OK;
2005 /******************************************************************************
2006 * CoRevokeInitializeSpy (combase.@)
2008 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
2010 struct tlsdata *tlsdata;
2011 struct init_spy *spy;
2012 HRESULT hr;
2014 TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
2016 if (cookie.u.HighPart != GetCurrentThreadId())
2017 return E_INVALIDARG;
2019 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2020 return hr;
2022 if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
2024 IInitializeSpy_Release(spy->spy);
2025 spy->spy = NULL;
2026 if (!tlsdata->spies_lock)
2028 list_remove(&spy->entry);
2029 heap_free(spy);
2031 return S_OK;
2034 static BOOL com_peek_message(struct apartment *apt, MSG *msg)
2036 /* First try to retrieve messages for incoming COM calls to the apartment window */
2037 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
2038 /* Next retrieve other messages necessary for the app to remain responsive */
2039 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
2040 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
2043 /***********************************************************************
2044 * CoWaitForMultipleHandles (combase.@)
2046 HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
2047 DWORD *index)
2049 BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
2050 DWORD start_time, wait_flags = 0;
2051 struct tlsdata *tlsdata;
2052 struct apartment *apt;
2053 UINT exit_code;
2054 HRESULT hr;
2056 TRACE("%#x, %#x, %u, %p, %p\n", flags, timeout, handle_count, handles, index);
2058 if (!index)
2059 return E_INVALIDARG;
2061 *index = 0;
2063 if (!handles)
2064 return E_INVALIDARG;
2066 if (!handle_count)
2067 return RPC_E_NO_SYNC;
2069 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2070 return hr;
2072 apt = com_get_current_apt();
2073 message_loop = apt && !apt->multi_threaded;
2075 if (flags & COWAIT_WAITALL)
2076 wait_flags |= MWMO_WAITALL;
2077 if (flags & COWAIT_ALERTABLE)
2078 wait_flags |= MWMO_ALERTABLE;
2080 start_time = GetTickCount();
2082 while (TRUE)
2084 DWORD now = GetTickCount(), res;
2086 if (now - start_time > timeout)
2088 hr = RPC_S_CALLPENDING;
2089 break;
2092 if (message_loop)
2094 TRACE("waiting for rpc completion or window message\n");
2096 res = WAIT_TIMEOUT;
2098 if (check_apc)
2100 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
2101 check_apc = FALSE;
2104 if (res == WAIT_TIMEOUT)
2105 res = MsgWaitForMultipleObjectsEx(handle_count, handles,
2106 timeout == INFINITE ? INFINITE : start_time + timeout - now,
2107 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
2109 if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
2111 int msg_count = 0;
2112 MSG msg;
2114 /* call message filter */
2116 if (apt->filter)
2118 PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
2119 DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
2121 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
2123 switch (be_handled)
2125 case PENDINGMSG_CANCELCALL:
2126 WARN("call canceled\n");
2127 hr = RPC_E_CALL_CANCELED;
2128 break;
2129 case PENDINGMSG_WAITNOPROCESS:
2130 case PENDINGMSG_WAITDEFPROCESS:
2131 default:
2132 /* FIXME: MSDN is very vague about the difference
2133 * between WAITNOPROCESS and WAITDEFPROCESS - there
2134 * appears to be none, so it is possibly a left-over
2135 * from the 16-bit world. */
2136 break;
2140 if (!apt->win)
2142 /* If window is NULL on apartment, peek at messages so that it will not trigger
2143 * MsgWaitForMultipleObjects next time. */
2144 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
2147 /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
2148 * so after processing 100 messages we go back to checking the wait handles */
2149 while (msg_count++ < 100 && com_peek_message(apt, &msg))
2151 if (msg.message == WM_QUIT)
2153 TRACE("Received WM_QUIT message\n");
2154 post_quit = TRUE;
2155 exit_code = msg.wParam;
2157 else
2159 TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2160 TranslateMessage(&msg);
2161 DispatchMessageW(&msg);
2164 continue;
2167 else
2169 TRACE("Waiting for rpc completion\n");
2171 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2172 (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2175 switch (res)
2177 case WAIT_TIMEOUT:
2178 hr = RPC_S_CALLPENDING;
2179 break;
2180 case WAIT_FAILED:
2181 hr = HRESULT_FROM_WIN32(GetLastError());
2182 break;
2183 default:
2184 *index = res;
2185 break;
2187 break;
2189 if (post_quit) PostQuitMessage(exit_code);
2191 TRACE("-- 0x%08x\n", hr);
2193 return hr;
2196 /******************************************************************************
2197 * CoRegisterMessageFilter (combase.@)
2199 HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2201 IMessageFilter *old_filter;
2202 struct apartment *apt;
2204 TRACE("%p, %p\n", filter, ret_filter);
2206 apt = com_get_current_apt();
2208 /* Can't set a message filter in a multi-threaded apartment */
2209 if (!apt || apt->multi_threaded)
2211 WARN("Can't set message filter in MTA or uninitialized apt\n");
2212 return CO_E_NOT_SUPPORTED;
2215 if (filter)
2216 IMessageFilter_AddRef(filter);
2218 EnterCriticalSection(&apt->cs);
2220 old_filter = apt->filter;
2221 apt->filter = filter;
2223 LeaveCriticalSection(&apt->cs);
2225 if (ret_filter)
2226 *ret_filter = old_filter;
2227 else if (old_filter)
2228 IMessageFilter_Release(old_filter);
2230 return S_OK;
2233 static void com_revoke_all_ps_clsids(void)
2235 struct registered_ps *cur, *cur2;
2237 EnterCriticalSection(&cs_registered_ps);
2239 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2241 list_remove(&cur->entry);
2242 heap_free(cur);
2245 LeaveCriticalSection(&cs_registered_ps);
2248 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2250 WCHAR value[CHARS_IN_GUID];
2251 HKEY hkey;
2252 DWORD len;
2254 access |= KEY_READ;
2256 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2257 return REGDB_E_IIDNOTREG;
2259 len = sizeof(value);
2260 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2261 return REGDB_E_IIDNOTREG;
2262 RegCloseKey(hkey);
2264 if (CLSIDFromString(value, pclsid) != NOERROR)
2265 return REGDB_E_IIDNOTREG;
2267 return S_OK;
2270 /*****************************************************************************
2271 * CoGetPSClsid (combase.@)
2273 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2275 static const WCHAR interfaceW[] = L"Interface\\";
2276 static const WCHAR psW[] = L"\\ProxyStubClsid32";
2277 WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2278 ACTCTX_SECTION_KEYED_DATA data;
2279 struct registered_ps *cur;
2280 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2281 BOOL is_wow64;
2282 HRESULT hr;
2284 TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2286 if (!InternalIsProcessInitialized())
2288 ERR("apartment not initialised\n");
2289 return CO_E_NOTINITIALIZED;
2292 if (!pclsid)
2293 return E_INVALIDARG;
2295 EnterCriticalSection(&cs_registered_ps);
2297 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2299 if (IsEqualIID(&cur->iid, riid))
2301 *pclsid = cur->clsid;
2302 LeaveCriticalSection(&cs_registered_ps);
2303 return S_OK;
2307 LeaveCriticalSection(&cs_registered_ps);
2309 data.cbSize = sizeof(data);
2310 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2311 riid, &data))
2313 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2314 *pclsid = ifaceps->iid;
2315 return S_OK;
2318 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2319 lstrcpyW(path, interfaceW);
2320 StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2321 lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2323 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2324 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2325 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2327 if (hr == S_OK)
2328 TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2329 else
2330 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2332 return hr;
2335 /*****************************************************************************
2336 * CoRegisterPSClsid (combase.@)
2338 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2340 struct registered_ps *cur;
2342 TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2344 if (!InternalIsProcessInitialized())
2346 ERR("apartment not initialised\n");
2347 return CO_E_NOTINITIALIZED;
2350 EnterCriticalSection(&cs_registered_ps);
2352 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2354 if (IsEqualIID(&cur->iid, riid))
2356 cur->clsid = *rclsid;
2357 LeaveCriticalSection(&cs_registered_ps);
2358 return S_OK;
2362 cur = heap_alloc(sizeof(*cur));
2363 if (!cur)
2365 LeaveCriticalSection(&cs_registered_ps);
2366 return E_OUTOFMEMORY;
2369 cur->iid = *riid;
2370 cur->clsid = *rclsid;
2371 list_add_head(&registered_proxystubs, &cur->entry);
2373 LeaveCriticalSection(&cs_registered_ps);
2375 return S_OK;
2378 struct thread_context
2380 IComThreadingInfo IComThreadingInfo_iface;
2381 IContextCallback IContextCallback_iface;
2382 IObjContext IObjContext_iface;
2383 LONG refcount;
2386 static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2388 return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2391 static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2393 return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2396 static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2398 return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2401 static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2403 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2405 *obj = NULL;
2407 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2408 IsEqualIID(riid, &IID_IUnknown))
2410 *obj = &context->IComThreadingInfo_iface;
2412 else if (IsEqualIID(riid, &IID_IContextCallback))
2414 *obj = &context->IContextCallback_iface;
2416 else if (IsEqualIID(riid, &IID_IObjContext))
2418 *obj = &context->IObjContext_iface;
2421 if (*obj)
2423 IUnknown_AddRef((IUnknown *)*obj);
2424 return S_OK;
2427 FIXME("interface not implemented %s\n", debugstr_guid(riid));
2428 return E_NOINTERFACE;
2431 static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2433 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2434 return InterlockedIncrement(&context->refcount);
2437 static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2439 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2441 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2442 releasing context while refcount is at 0 destroys it. */
2443 if (!context->refcount)
2445 heap_free(context);
2446 return 0;
2449 return InterlockedDecrement(&context->refcount);
2452 static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2454 APTTYPEQUALIFIER qualifier;
2456 TRACE("%p\n", apttype);
2458 return CoGetApartmentType(apttype, &qualifier);
2461 static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2463 APTTYPEQUALIFIER qualifier;
2464 APTTYPE apttype;
2465 HRESULT hr;
2467 hr = CoGetApartmentType(&apttype, &qualifier);
2468 if (FAILED(hr))
2469 return hr;
2471 TRACE("%p\n", thdtype);
2473 switch (apttype)
2475 case APTTYPE_STA:
2476 case APTTYPE_MAINSTA:
2477 *thdtype = THDTYPE_PROCESSMESSAGES;
2478 break;
2479 default:
2480 *thdtype = THDTYPE_BLOCKMESSAGES;
2481 break;
2483 return S_OK;
2486 static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2488 TRACE("%p\n", logical_thread_id);
2490 return CoGetCurrentLogicalThreadId(logical_thread_id);
2493 static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2495 FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2497 return E_NOTIMPL;
2500 static const IComThreadingInfoVtbl thread_context_info_vtbl =
2502 thread_context_info_QueryInterface,
2503 thread_context_info_AddRef,
2504 thread_context_info_Release,
2505 thread_context_info_GetCurrentApartmentType,
2506 thread_context_info_GetCurrentThreadType,
2507 thread_context_info_GetCurrentLogicalThreadId,
2508 thread_context_info_SetCurrentLogicalThreadId
2511 static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2513 struct thread_context *context = impl_from_IContextCallback(iface);
2514 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2517 static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2519 struct thread_context *context = impl_from_IContextCallback(iface);
2520 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2523 static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2525 struct thread_context *context = impl_from_IContextCallback(iface);
2526 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2529 static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2530 PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2532 FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2534 return E_NOTIMPL;
2537 static const IContextCallbackVtbl thread_context_callback_vtbl =
2539 thread_context_callback_QueryInterface,
2540 thread_context_callback_AddRef,
2541 thread_context_callback_Release,
2542 thread_context_callback_ContextCallback
2545 static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2547 struct thread_context *context = impl_from_IObjContext(iface);
2548 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2551 static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2553 struct thread_context *context = impl_from_IObjContext(iface);
2554 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2557 static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2559 struct thread_context *context = impl_from_IObjContext(iface);
2560 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2563 static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2565 FIXME("%p, %s, %x, %p\n", iface, debugstr_guid(propid), flags, punk);
2567 return E_NOTIMPL;
2570 static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2572 FIXME("%p, %s\n", iface, debugstr_guid(propid));
2574 return E_NOTIMPL;
2577 static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2579 FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2581 return E_NOTIMPL;
2584 static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2586 FIXME("%p, %p\n", iface, props);
2588 return E_NOTIMPL;
2591 static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2593 FIXME("%p\n", iface);
2596 static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2598 FIXME("%p\n", iface);
2601 static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2603 FIXME("%p\n", iface);
2606 static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2608 FIXME("%p\n", iface);
2611 static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2613 FIXME("%p\n", iface);
2616 static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2618 FIXME("%p\n", iface);
2621 static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2623 FIXME("%p\n", iface);
2626 static const IObjContextVtbl thread_object_context_vtbl =
2628 thread_object_context_QueryInterface,
2629 thread_object_context_AddRef,
2630 thread_object_context_Release,
2631 thread_object_context_SetProperty,
2632 thread_object_context_RemoveProperty,
2633 thread_object_context_GetProperty,
2634 thread_object_context_EnumContextProps,
2635 thread_object_context_Reserved1,
2636 thread_object_context_Reserved2,
2637 thread_object_context_Reserved3,
2638 thread_object_context_Reserved4,
2639 thread_object_context_Reserved5,
2640 thread_object_context_Reserved6,
2641 thread_object_context_Reserved7
2644 /***********************************************************************
2645 * CoGetContextToken (combase.@)
2647 HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2649 struct tlsdata *tlsdata;
2650 HRESULT hr;
2652 TRACE("%p\n", token);
2654 if (!InternalIsProcessInitialized())
2656 ERR("apartment not initialised\n");
2657 return CO_E_NOTINITIALIZED;
2660 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2661 return hr;
2663 if (!token)
2664 return E_POINTER;
2666 if (!tlsdata->context_token)
2668 struct thread_context *context;
2670 context = heap_alloc_zero(sizeof(*context));
2671 if (!context)
2672 return E_OUTOFMEMORY;
2674 context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2675 context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2676 context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2677 /* Context token does not take a reference, it's always zero until the
2678 interface is explicitly requested with CoGetObjectContext(). */
2679 context->refcount = 0;
2681 tlsdata->context_token = &context->IObjContext_iface;
2684 *token = (ULONG_PTR)tlsdata->context_token;
2685 TRACE("context_token %p\n", tlsdata->context_token);
2687 return S_OK;
2690 /***********************************************************************
2691 * CoGetCurrentLogicalThreadId (combase.@)
2693 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2695 struct tlsdata *tlsdata;
2696 HRESULT hr;
2698 if (!id)
2699 return E_INVALIDARG;
2701 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2702 return hr;
2704 if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2706 CoCreateGuid(&tlsdata->causality_id);
2707 tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2710 *id = tlsdata->causality_id;
2712 return S_OK;
2715 /******************************************************************************
2716 * CoGetCurrentProcess (combase.@)
2718 DWORD WINAPI CoGetCurrentProcess(void)
2720 struct tlsdata *tlsdata;
2722 if (FAILED(com_get_tlsdata(&tlsdata)))
2723 return 0;
2725 if (!tlsdata->thread_seqid)
2726 rpcss_get_next_seqid(&tlsdata->thread_seqid);
2728 return tlsdata->thread_seqid;
2731 /***********************************************************************
2732 * CoFreeUnusedLibrariesEx (combase.@)
2734 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2736 struct apartment *apt = com_get_current_apt();
2737 if (!apt)
2739 ERR("apartment not initialised\n");
2740 return;
2743 apartment_freeunusedlibraries(apt, unload_delay);
2747 * When locked, don't modify list (unless we add a new head), so that it's
2748 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
2750 static inline void lock_init_spies(struct tlsdata *tlsdata)
2752 tlsdata->spies_lock++;
2755 static void unlock_init_spies(struct tlsdata *tlsdata)
2757 struct init_spy *spy, *next;
2759 if (--tlsdata->spies_lock) return;
2761 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2763 if (spy->spy) continue;
2764 list_remove(&spy->entry);
2765 heap_free(spy);
2769 /******************************************************************************
2770 * CoInitializeWOW (combase.@)
2772 HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2774 FIXME("%#x, %#x\n", arg1, arg2);
2776 return S_OK;
2779 /******************************************************************************
2780 * CoInitializeEx (combase.@)
2782 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2784 struct tlsdata *tlsdata;
2785 struct init_spy *cursor;
2786 HRESULT hr;
2788 TRACE("%p, %#x\n", reserved, model);
2790 if (reserved)
2791 WARN("Unexpected reserved argument %p\n", reserved);
2793 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2794 return hr;
2796 if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2797 TRACE("Initializing the COM libraries\n");
2799 lock_init_spies(tlsdata);
2800 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2802 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2804 unlock_init_spies(tlsdata);
2806 hr = enter_apartment(tlsdata, model);
2808 lock_init_spies(tlsdata);
2809 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2811 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2813 unlock_init_spies(tlsdata);
2815 return hr;
2818 /***********************************************************************
2819 * CoUninitialize (combase.@)
2821 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2823 struct tlsdata *tlsdata;
2824 struct init_spy *cursor, *next;
2825 LONG lockcount;
2827 TRACE("\n");
2829 if (FAILED(com_get_tlsdata(&tlsdata)))
2830 return;
2832 lock_init_spies(tlsdata);
2833 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2835 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2837 unlock_init_spies(tlsdata);
2839 /* sanity check */
2840 if (!tlsdata->inits)
2842 ERR("Mismatched CoUninitialize\n");
2844 lock_init_spies(tlsdata);
2845 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2847 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2849 unlock_init_spies(tlsdata);
2851 return;
2854 leave_apartment(tlsdata);
2857 * Decrease the reference count.
2858 * If we are back to 0 locks on the COM library, make sure we free
2859 * all the associated data structures.
2861 lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2862 if (lockcount == 1)
2864 TRACE("Releasing the COM libraries\n");
2866 com_revoke_all_ps_clsids();
2867 DestroyRunningObjectTable();
2869 else if (lockcount < 1)
2871 ERR("Unbalanced lock count %d\n", lockcount);
2872 InterlockedExchangeAdd(&com_lockcount, 1);
2875 lock_init_spies(tlsdata);
2876 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2878 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2880 unlock_init_spies(tlsdata);
2883 /***********************************************************************
2884 * CoIncrementMTAUsage (combase.@)
2886 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2888 TRACE("%p\n", cookie);
2890 return apartment_increment_mta_usage(cookie);
2893 /***********************************************************************
2894 * CoDecrementMTAUsage (combase.@)
2896 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2898 TRACE("%p\n", cookie);
2900 apartment_decrement_mta_usage(cookie);
2901 return S_OK;
2904 /***********************************************************************
2905 * CoGetApartmentType (combase.@)
2907 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2909 struct tlsdata *tlsdata;
2910 struct apartment *apt;
2911 HRESULT hr;
2913 TRACE("%p, %p\n", type, qualifier);
2915 if (!type || !qualifier)
2916 return E_INVALIDARG;
2918 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2919 return hr;
2921 if (!tlsdata->apt)
2922 *type = APTTYPE_CURRENT;
2923 else if (tlsdata->apt->multi_threaded)
2924 *type = APTTYPE_MTA;
2925 else if (tlsdata->apt->main)
2926 *type = APTTYPE_MAINSTA;
2927 else
2928 *type = APTTYPE_STA;
2930 *qualifier = APTTYPEQUALIFIER_NONE;
2932 if (!tlsdata->apt && (apt = apartment_get_mta()))
2934 apartment_release(apt);
2935 *type = APTTYPE_MTA;
2936 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2937 return S_OK;
2940 return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2943 /******************************************************************************
2944 * CoRegisterClassObject (combase.@)
2945 * BUGS
2946 * MSDN claims that multiple interface registrations are legal, but we
2947 * can't do that with our current implementation.
2949 HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2950 DWORD flags, DWORD *cookie)
2952 static LONG next_cookie;
2954 struct registered_class *newclass;
2955 IUnknown *found_object;
2956 struct apartment *apt;
2957 HRESULT hr = S_OK;
2959 TRACE("%s, %p, %#x, %#x, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2961 if (!cookie || !object)
2962 return E_INVALIDARG;
2964 if (!(apt = apartment_get_current_or_mta()))
2966 ERR("COM was not initialized\n");
2967 return CO_E_NOTINITIALIZED;
2970 *cookie = 0;
2972 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2973 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2974 if (flags & REGCLS_MULTIPLEUSE)
2975 clscontext |= CLSCTX_INPROC_SERVER;
2978 * First, check if the class is already registered.
2979 * If it is, this should cause an error.
2981 if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2983 if (flags & REGCLS_MULTIPLEUSE)
2985 if (clscontext & CLSCTX_LOCAL_SERVER)
2986 hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2987 IUnknown_Release(found_object);
2988 apartment_release(apt);
2989 return hr;
2992 IUnknown_Release(found_object);
2993 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2994 apartment_release(apt);
2995 return CO_E_OBJISREG;
2998 newclass = heap_alloc_zero(sizeof(*newclass));
2999 if (!newclass)
3001 apartment_release(apt);
3002 return E_OUTOFMEMORY;
3005 newclass->clsid = *rclsid;
3006 newclass->apartment_id = apt->oxid;
3007 newclass->clscontext = clscontext;
3008 newclass->flags = flags;
3010 if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
3011 newclass->cookie = InterlockedIncrement(&next_cookie);
3013 newclass->object = object;
3014 IUnknown_AddRef(newclass->object);
3016 EnterCriticalSection(&registered_classes_cs);
3017 list_add_tail(&registered_classes, &newclass->entry);
3018 LeaveCriticalSection(&registered_classes_cs);
3020 *cookie = newclass->cookie;
3022 if (clscontext & CLSCTX_LOCAL_SERVER)
3024 IStream *marshal_stream;
3026 hr = apartment_get_local_server_stream(apt, &marshal_stream);
3027 if(FAILED(hr))
3029 apartment_release(apt);
3030 return hr;
3033 hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
3034 IStream_Release(marshal_stream);
3037 apartment_release(apt);
3038 return S_OK;
3041 static void com_revoke_class_object(struct registered_class *entry)
3043 list_remove(&entry->entry);
3045 if (entry->clscontext & CLSCTX_LOCAL_SERVER)
3046 rpc_revoke_local_server(entry->rpcss_cookie);
3048 IUnknown_Release(entry->object);
3049 heap_free(entry);
3052 /* Cleans up rpcss registry */
3053 static void com_revoke_local_servers(void)
3055 struct registered_class *cur, *cur2;
3057 EnterCriticalSection(&registered_classes_cs);
3059 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3061 if (cur->clscontext & CLSCTX_LOCAL_SERVER)
3062 com_revoke_class_object(cur);
3065 LeaveCriticalSection(&registered_classes_cs);
3068 void apartment_revoke_all_classes(const struct apartment *apt)
3070 struct registered_class *cur, *cur2;
3072 EnterCriticalSection(&registered_classes_cs);
3074 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3076 if (cur->apartment_id == apt->oxid)
3077 com_revoke_class_object(cur);
3080 LeaveCriticalSection(&registered_classes_cs);
3083 /***********************************************************************
3084 * CoRevokeClassObject (combase.@)
3086 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
3088 HRESULT hr = E_INVALIDARG;
3089 struct registered_class *cur;
3090 struct apartment *apt;
3092 TRACE("%#x\n", cookie);
3094 if (!(apt = apartment_get_current_or_mta()))
3096 ERR("COM was not initialized\n");
3097 return CO_E_NOTINITIALIZED;
3100 EnterCriticalSection(&registered_classes_cs);
3102 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
3104 if (cur->cookie != cookie)
3105 continue;
3107 if (cur->apartment_id == apt->oxid)
3109 com_revoke_class_object(cur);
3110 hr = S_OK;
3112 else
3114 ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
3115 hr = RPC_E_WRONG_THREAD;
3118 break;
3121 LeaveCriticalSection(&registered_classes_cs);
3122 apartment_release(apt);
3124 return hr;
3127 /***********************************************************************
3128 * CoAddRefServerProcess (combase.@)
3130 ULONG WINAPI CoAddRefServerProcess(void)
3132 ULONG refs;
3134 TRACE("\n");
3136 EnterCriticalSection(&registered_classes_cs);
3137 refs = ++com_server_process_refcount;
3138 LeaveCriticalSection(&registered_classes_cs);
3140 TRACE("refs before: %d\n", refs - 1);
3142 return refs;
3145 /***********************************************************************
3146 * CoReleaseServerProcess [OLE32.@]
3148 ULONG WINAPI CoReleaseServerProcess(void)
3150 ULONG refs;
3152 TRACE("\n");
3154 EnterCriticalSection(&registered_classes_cs);
3156 refs = --com_server_process_refcount;
3157 /* FIXME: suspend objects */
3159 LeaveCriticalSection(&registered_classes_cs);
3161 TRACE("refs after: %d\n", refs);
3163 return refs;
3166 /******************************************************************************
3167 * CoDisconnectObject (combase.@)
3169 HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3171 struct stub_manager *manager;
3172 struct apartment *apt;
3173 IMarshal *marshal;
3174 HRESULT hr;
3176 TRACE("%p, %#x\n", object, reserved);
3178 if (!object)
3179 return E_INVALIDARG;
3181 hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3182 if (hr == S_OK)
3184 hr = IMarshal_DisconnectObject(marshal, reserved);
3185 IMarshal_Release(marshal);
3186 return hr;
3189 if (!(apt = apartment_get_current_or_mta()))
3191 ERR("apartment not initialised\n");
3192 return CO_E_NOTINITIALIZED;
3195 manager = get_stub_manager_from_object(apt, object, FALSE);
3196 if (manager)
3198 stub_manager_disconnect(manager);
3199 /* Release stub manager twice, to remove the apartment reference. */
3200 stub_manager_int_release(manager);
3201 stub_manager_int_release(manager);
3204 /* Note: native is pretty broken here because it just silently
3205 * fails, without returning an appropriate error code if the object was
3206 * not found, making apps think that the object was disconnected, when
3207 * it actually wasn't */
3209 apartment_release(apt);
3210 return S_OK;
3213 /******************************************************************************
3214 * CoLockObjectExternal (combase.@)
3216 HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3218 struct stub_manager *stubmgr;
3219 struct apartment *apt;
3221 TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3223 if (!(apt = apartment_get_current_or_mta()))
3225 ERR("apartment not initialised\n");
3226 return CO_E_NOTINITIALIZED;
3229 stubmgr = get_stub_manager_from_object(apt, object, lock);
3230 if (!stubmgr)
3232 WARN("stub object not found %p\n", object);
3233 /* Note: native is pretty broken here because it just silently
3234 * fails, without returning an appropriate error code, making apps
3235 * think that the object was disconnected, when it actually wasn't */
3236 apartment_release(apt);
3237 return S_OK;
3240 if (lock)
3241 stub_manager_ext_addref(stubmgr, 1, FALSE);
3242 else
3243 stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3245 stub_manager_int_release(stubmgr);
3246 apartment_release(apt);
3247 return S_OK;
3250 /***********************************************************************
3251 * CoRegisterChannelHook (combase.@)
3253 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3255 TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3257 return rpc_register_channel_hook(guidExtension, channel_hook);
3260 /***********************************************************************
3261 * CoDisableCallCancellation (combase.@)
3263 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3265 struct tlsdata *tlsdata;
3266 HRESULT hr;
3268 TRACE("%p\n", reserved);
3270 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3271 return hr;
3273 if (!tlsdata->cancelcount)
3274 return CO_E_CANCEL_DISABLED;
3276 tlsdata->cancelcount--;
3278 return S_OK;
3281 /***********************************************************************
3282 * CoEnableCallCancellation (combase.@)
3284 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3286 struct tlsdata *tlsdata;
3287 HRESULT hr;
3289 TRACE("%p\n", reserved);
3291 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3292 return hr;
3294 tlsdata->cancelcount++;
3296 return S_OK;
3299 /***********************************************************************
3300 * CoGetCallerTID (combase.@)
3302 HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3304 FIXME("stub!\n");
3305 return E_NOTIMPL;
3308 /***********************************************************************
3309 * CoIsHandlerConnected (combase.@)
3311 BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3313 FIXME("%p\n", object);
3315 return TRUE;
3318 /***********************************************************************
3319 * CoSuspendClassObjects (combase.@)
3321 HRESULT WINAPI CoSuspendClassObjects(void)
3323 FIXME("\n");
3325 return S_OK;
3328 /***********************************************************************
3329 * CoResumeClassObjects (combase.@)
3331 HRESULT WINAPI CoResumeClassObjects(void)
3333 FIXME("stub\n");
3335 return S_OK;
3338 /***********************************************************************
3339 * CoRegisterSurrogate (combase.@)
3341 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3343 FIXME("%p stub\n", surrogate);
3345 return E_NOTIMPL;
3348 /***********************************************************************
3349 * CoRegisterSurrogateEx (combase.@)
3351 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3353 FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3355 return E_NOTIMPL;
3358 /***********************************************************************
3359 * DllMain (combase.@)
3361 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3363 TRACE("%p 0x%x %p\n", hinstDLL, reason, reserved);
3365 switch (reason)
3367 case DLL_PROCESS_ATTACH:
3368 hProxyDll = hinstDLL;
3369 break;
3370 case DLL_PROCESS_DETACH:
3371 com_revoke_local_servers();
3372 if (reserved) break;
3373 apartment_global_cleanup();
3374 DeleteCriticalSection(&registered_classes_cs);
3375 rpc_unregister_channel_hooks();
3376 break;
3377 case DLL_THREAD_DETACH:
3378 com_cleanup_tlsdata();
3379 break;
3382 return TRUE;
3385 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj)
3387 TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj);
3389 *obj = NULL;
3391 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3392 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
3394 return CLASS_E_CLASSNOTAVAILABLE;