cmd: DIR command outputs free space for the path.
[wine.git] / dlls / combase / combase.c
blobf1b5828e0f8596be0bab4e3c173acf629702c4d1
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->errorinfo)
411 IErrorInfo_Release(tlsdata->errorinfo);
412 if (tlsdata->state)
413 IUnknown_Release(tlsdata->state);
415 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry)
417 list_remove(&cursor->entry);
418 if (cursor->spy)
419 IInitializeSpy_Release(cursor->spy);
420 free(cursor);
423 if (tlsdata->context_token)
424 IObjContext_Release(tlsdata->context_token);
426 free(tlsdata);
427 NtCurrentTeb()->ReservedForOle = NULL;
430 struct global_options
432 IGlobalOptions IGlobalOptions_iface;
433 LONG refcount;
436 static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface)
438 return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface);
441 static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
443 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
445 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
447 *ppv = iface;
449 else
451 *ppv = NULL;
452 return E_NOINTERFACE;
455 IUnknown_AddRef((IUnknown *)*ppv);
456 return S_OK;
459 static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface)
461 struct global_options *options = impl_from_IGlobalOptions(iface);
462 LONG refcount = InterlockedIncrement(&options->refcount);
464 TRACE("%p, refcount %ld.\n", iface, refcount);
466 return refcount;
469 static ULONG WINAPI global_options_Release(IGlobalOptions *iface)
471 struct global_options *options = impl_from_IGlobalOptions(iface);
472 LONG refcount = InterlockedDecrement(&options->refcount);
474 TRACE("%p, refcount %ld.\n", iface, refcount);
476 if (!refcount)
477 free(options);
479 return refcount;
482 static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
484 FIXME("%p, %u, %Ix.\n", iface, property, value);
486 return S_OK;
489 static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
491 TRACE("%p, %u, %p.\n", iface, property, value);
493 if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3)
494 return E_INVALIDARG;
496 *value = global_options[property];
498 return S_OK;
501 static const IGlobalOptionsVtbl global_options_vtbl =
503 global_options_QueryInterface,
504 global_options_AddRef,
505 global_options_Release,
506 global_options_Set,
507 global_options_Query
510 static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
512 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
514 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
516 *ppv = iface;
517 return S_OK;
520 *ppv = NULL;
521 return E_NOINTERFACE;
524 static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
526 return 2;
529 static ULONG WINAPI class_factory_Release(IClassFactory *iface)
531 return 1;
534 static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock)
536 TRACE("%d\n", fLock);
538 return S_OK;
541 static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
543 struct global_options *object;
544 HRESULT hr;
546 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv);
548 if (outer)
549 return E_INVALIDARG;
551 if (!(object = malloc(sizeof(*object))))
552 return E_OUTOFMEMORY;
553 object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl;
554 object->refcount = 1;
556 hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv);
557 IGlobalOptions_Release(&object->IGlobalOptions_iface);
558 return hr;
561 static const IClassFactoryVtbl global_options_factory_vtbl =
563 class_factory_QueryInterface,
564 class_factory_AddRef,
565 class_factory_Release,
566 global_options_CreateInstance,
567 class_factory_LockServer
570 static IClassFactory global_options_factory = { &global_options_factory_vtbl };
572 static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj)
574 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
575 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
576 return E_UNEXPECTED;
579 /***********************************************************************
580 * FreePropVariantArray (combase.@)
582 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
584 ULONG i;
586 TRACE("%lu, %p.\n", count, rgvars);
588 if (!rgvars)
589 return E_INVALIDARG;
591 for (i = 0; i < count; ++i)
592 PropVariantClear(&rgvars[i]);
594 return S_OK;
597 static HRESULT propvar_validatetype(VARTYPE vt)
599 switch (vt)
601 case VT_EMPTY:
602 case VT_NULL:
603 case VT_I1:
604 case VT_I2:
605 case VT_I4:
606 case VT_I8:
607 case VT_R4:
608 case VT_R8:
609 case VT_CY:
610 case VT_DATE:
611 case VT_BSTR:
612 case VT_ERROR:
613 case VT_BOOL:
614 case VT_DECIMAL:
615 case VT_UI1:
616 case VT_UI2:
617 case VT_UI4:
618 case VT_UI8:
619 case VT_INT:
620 case VT_UINT:
621 case VT_LPSTR:
622 case VT_LPWSTR:
623 case VT_FILETIME:
624 case VT_BLOB:
625 case VT_DISPATCH:
626 case VT_UNKNOWN:
627 case VT_STREAM:
628 case VT_STORAGE:
629 case VT_STREAMED_OBJECT:
630 case VT_STORED_OBJECT:
631 case VT_BLOB_OBJECT:
632 case VT_CF:
633 case VT_CLSID:
634 case VT_I1|VT_VECTOR:
635 case VT_I2|VT_VECTOR:
636 case VT_I4|VT_VECTOR:
637 case VT_I8|VT_VECTOR:
638 case VT_R4|VT_VECTOR:
639 case VT_R8|VT_VECTOR:
640 case VT_CY|VT_VECTOR:
641 case VT_DATE|VT_VECTOR:
642 case VT_BSTR|VT_VECTOR:
643 case VT_ERROR|VT_VECTOR:
644 case VT_BOOL|VT_VECTOR:
645 case VT_VARIANT|VT_VECTOR:
646 case VT_UI1|VT_VECTOR:
647 case VT_UI2|VT_VECTOR:
648 case VT_UI4|VT_VECTOR:
649 case VT_UI8|VT_VECTOR:
650 case VT_LPSTR|VT_VECTOR:
651 case VT_LPWSTR|VT_VECTOR:
652 case VT_FILETIME|VT_VECTOR:
653 case VT_CF|VT_VECTOR:
654 case VT_CLSID|VT_VECTOR:
655 case VT_ARRAY|VT_I1:
656 case VT_ARRAY|VT_UI1:
657 case VT_ARRAY|VT_I2:
658 case VT_ARRAY|VT_UI2:
659 case VT_ARRAY|VT_I4:
660 case VT_ARRAY|VT_UI4:
661 case VT_ARRAY|VT_INT:
662 case VT_ARRAY|VT_UINT:
663 case VT_ARRAY|VT_R4:
664 case VT_ARRAY|VT_R8:
665 case VT_ARRAY|VT_CY:
666 case VT_ARRAY|VT_DATE:
667 case VT_ARRAY|VT_BSTR:
668 case VT_ARRAY|VT_BOOL:
669 case VT_ARRAY|VT_DECIMAL:
670 case VT_ARRAY|VT_DISPATCH:
671 case VT_ARRAY|VT_UNKNOWN:
672 case VT_ARRAY|VT_ERROR:
673 case VT_ARRAY|VT_VARIANT:
674 return S_OK;
676 WARN("Bad type %d\n", vt);
677 return STG_E_INVALIDPARAMETER;
680 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
682 ULONG i;
683 for (i = 0; i < count; ++i)
684 CoTaskMemFree(data[i].pClipData);
687 /***********************************************************************
688 * PropVariantClear (combase.@)
690 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
692 HRESULT hr;
694 TRACE("%p.\n", pvar);
696 if (!pvar)
697 return S_OK;
699 hr = propvar_validatetype(pvar->vt);
700 if (FAILED(hr))
702 memset(pvar, 0, sizeof(*pvar));
703 return hr;
706 switch (pvar->vt)
708 case VT_EMPTY:
709 case VT_NULL:
710 case VT_I1:
711 case VT_I2:
712 case VT_I4:
713 case VT_I8:
714 case VT_R4:
715 case VT_R8:
716 case VT_CY:
717 case VT_DATE:
718 case VT_ERROR:
719 case VT_BOOL:
720 case VT_DECIMAL:
721 case VT_UI1:
722 case VT_UI2:
723 case VT_UI4:
724 case VT_UI8:
725 case VT_INT:
726 case VT_UINT:
727 case VT_FILETIME:
728 break;
729 case VT_DISPATCH:
730 case VT_UNKNOWN:
731 case VT_STREAM:
732 case VT_STREAMED_OBJECT:
733 case VT_STORAGE:
734 case VT_STORED_OBJECT:
735 if (pvar->pStream)
736 IStream_Release(pvar->pStream);
737 break;
738 case VT_CLSID:
739 case VT_LPSTR:
740 case VT_LPWSTR:
741 /* pick an arbitrary typed pointer - we don't care about the type
742 * as we are just freeing it */
743 CoTaskMemFree(pvar->puuid);
744 break;
745 case VT_BLOB:
746 case VT_BLOB_OBJECT:
747 CoTaskMemFree(pvar->blob.pBlobData);
748 break;
749 case VT_BSTR:
750 SysFreeString(pvar->bstrVal);
751 break;
752 case VT_CF:
753 if (pvar->pclipdata)
755 propvar_free_cf_array(1, pvar->pclipdata);
756 CoTaskMemFree(pvar->pclipdata);
758 break;
759 default:
760 if (pvar->vt & VT_VECTOR)
762 ULONG i;
764 switch (pvar->vt & ~VT_VECTOR)
766 case VT_VARIANT:
767 FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems);
768 break;
769 case VT_CF:
770 propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems);
771 break;
772 case VT_BSTR:
773 for (i = 0; i < pvar->cabstr.cElems; i++)
774 SysFreeString(pvar->cabstr.pElems[i]);
775 break;
776 case VT_LPSTR:
777 for (i = 0; i < pvar->calpstr.cElems; i++)
778 CoTaskMemFree(pvar->calpstr.pElems[i]);
779 break;
780 case VT_LPWSTR:
781 for (i = 0; i < pvar->calpwstr.cElems; i++)
782 CoTaskMemFree(pvar->calpwstr.pElems[i]);
783 break;
785 if (pvar->vt & ~VT_VECTOR)
787 /* pick an arbitrary VT_VECTOR structure - they all have the same
788 * memory layout */
789 CoTaskMemFree(pvar->capropvar.pElems);
792 else if (pvar->vt & VT_ARRAY)
793 hr = SafeArrayDestroy(pvar->parray);
794 else
796 WARN("Invalid/unsupported type %d\n", pvar->vt);
797 hr = STG_E_INVALIDPARAMETER;
801 memset(pvar, 0, sizeof(*pvar));
802 return hr;
805 /***********************************************************************
806 * PropVariantCopy (combase.@)
808 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
810 ULONG len;
811 HRESULT hr;
813 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
815 hr = propvar_validatetype(pvarSrc->vt);
816 if (FAILED(hr))
817 return DISP_E_BADVARTYPE;
819 /* this will deal with most cases */
820 *pvarDest = *pvarSrc;
822 switch (pvarSrc->vt)
824 case VT_EMPTY:
825 case VT_NULL:
826 case VT_I1:
827 case VT_UI1:
828 case VT_I2:
829 case VT_UI2:
830 case VT_BOOL:
831 case VT_DECIMAL:
832 case VT_I4:
833 case VT_UI4:
834 case VT_R4:
835 case VT_ERROR:
836 case VT_I8:
837 case VT_UI8:
838 case VT_INT:
839 case VT_UINT:
840 case VT_R8:
841 case VT_CY:
842 case VT_DATE:
843 case VT_FILETIME:
844 break;
845 case VT_DISPATCH:
846 case VT_UNKNOWN:
847 case VT_STREAM:
848 case VT_STREAMED_OBJECT:
849 case VT_STORAGE:
850 case VT_STORED_OBJECT:
851 if (pvarDest->pStream)
852 IStream_AddRef(pvarDest->pStream);
853 break;
854 case VT_CLSID:
855 pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID));
856 *pvarDest->puuid = *pvarSrc->puuid;
857 break;
858 case VT_LPSTR:
859 if (pvarSrc->pszVal)
861 len = strlen(pvarSrc->pszVal);
862 pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
863 CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR));
865 break;
866 case VT_LPWSTR:
867 if (pvarSrc->pwszVal)
869 len = lstrlenW(pvarSrc->pwszVal);
870 pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
871 CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR));
873 break;
874 case VT_BLOB:
875 case VT_BLOB_OBJECT:
876 if (pvarSrc->blob.pBlobData)
878 len = pvarSrc->blob.cbSize;
879 pvarDest->blob.pBlobData = CoTaskMemAlloc(len);
880 CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len);
882 break;
883 case VT_BSTR:
884 pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal);
885 break;
886 case VT_CF:
887 if (pvarSrc->pclipdata)
889 len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt);
890 pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
891 pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize;
892 pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt;
893 pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len);
894 CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len);
896 break;
897 default:
898 if (pvarSrc->vt & VT_VECTOR)
900 int elemSize;
901 ULONG i;
903 switch (pvarSrc->vt & ~VT_VECTOR)
905 case VT_I1: elemSize = sizeof(pvarSrc->cVal); break;
906 case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break;
907 case VT_I2: elemSize = sizeof(pvarSrc->iVal); break;
908 case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break;
909 case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break;
910 case VT_I4: elemSize = sizeof(pvarSrc->lVal); break;
911 case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break;
912 case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break;
913 case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break;
914 case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break;
915 case VT_I8: elemSize = sizeof(pvarSrc->hVal); break;
916 case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break;
917 case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break;
918 case VT_DATE: elemSize = sizeof(pvarSrc->date); break;
919 case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break;
920 case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break;
921 case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break;
922 case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break;
923 case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break;
924 case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break;
925 case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break;
927 default:
928 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
929 return E_INVALIDARG;
931 len = pvarSrc->capropvar.cElems;
932 pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
933 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
935 for (i = 0; i < len; i++)
936 PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]);
938 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
940 FIXME("Copy clipformats\n");
942 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
944 for (i = 0; i < len; i++)
945 pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]);
947 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
949 size_t strLen;
950 for (i = 0; i < len; i++)
952 strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1;
953 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
954 memcpy(pvarDest->calpstr.pElems[i],
955 pvarSrc->calpstr.pElems[i], strLen);
958 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
960 size_t strLen;
961 for (i = 0; i < len; i++)
963 strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) *
964 sizeof(WCHAR);
965 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
966 memcpy(pvarDest->calpstr.pElems[i],
967 pvarSrc->calpstr.pElems[i], strLen);
970 else
971 CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize);
973 else if (pvarSrc->vt & VT_ARRAY)
975 pvarDest->uhVal.QuadPart = 0;
976 return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray);
978 else
979 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
982 return S_OK;
985 /***********************************************************************
986 * CoFileTimeNow (combase.@)
988 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
990 GetSystemTimeAsFileTime(filetime);
991 return S_OK;
994 /******************************************************************************
995 * CoCreateGuid (combase.@)
997 HRESULT WINAPI CoCreateGuid(GUID *guid)
999 RPC_STATUS status;
1001 if (!guid) return E_INVALIDARG;
1003 status = UuidCreate(guid);
1004 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1005 return HRESULT_FROM_WIN32(status);
1008 /******************************************************************************
1009 * CoQueryProxyBlanket (combase.@)
1011 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
1012 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
1013 DWORD *imp_level, void **auth_info, DWORD *capabilities)
1015 IClientSecurity *client_security;
1016 HRESULT hr;
1018 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
1019 auth_info, capabilities);
1021 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1022 if (SUCCEEDED(hr))
1024 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
1025 authn_level, imp_level, auth_info, capabilities);
1026 IClientSecurity_Release(client_security);
1029 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1030 return hr;
1033 /******************************************************************************
1034 * CoSetProxyBlanket (combase.@)
1036 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
1037 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
1039 IClientSecurity *client_security;
1040 HRESULT hr;
1042 TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, authz_service, servername,
1043 authn_level, imp_level, auth_info, capabilities);
1045 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1046 if (SUCCEEDED(hr))
1048 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
1049 imp_level, auth_info, capabilities);
1050 IClientSecurity_Release(client_security);
1053 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1054 return hr;
1057 /***********************************************************************
1058 * CoCopyProxy (combase.@)
1060 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
1062 IClientSecurity *client_security;
1063 HRESULT hr;
1065 TRACE("%p, %p.\n", proxy, proxy_copy);
1067 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1068 if (SUCCEEDED(hr))
1070 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
1071 IClientSecurity_Release(client_security);
1074 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1075 return hr;
1078 /***********************************************************************
1079 * CoQueryClientBlanket (combase.@)
1081 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
1082 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
1084 IServerSecurity *server_security;
1085 HRESULT hr;
1087 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
1088 privs, capabilities);
1090 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1091 if (SUCCEEDED(hr))
1093 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
1094 imp_level, privs, capabilities);
1095 IServerSecurity_Release(server_security);
1098 return hr;
1101 /***********************************************************************
1102 * CoImpersonateClient (combase.@)
1104 HRESULT WINAPI CoImpersonateClient(void)
1106 IServerSecurity *server_security;
1107 HRESULT hr;
1109 TRACE("\n");
1111 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1112 if (SUCCEEDED(hr))
1114 hr = IServerSecurity_ImpersonateClient(server_security);
1115 IServerSecurity_Release(server_security);
1118 return hr;
1121 /***********************************************************************
1122 * CoRevertToSelf (combase.@)
1124 HRESULT WINAPI CoRevertToSelf(void)
1126 IServerSecurity *server_security;
1127 HRESULT hr;
1129 TRACE("\n");
1131 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1132 if (SUCCEEDED(hr))
1134 hr = IServerSecurity_RevertToSelf(server_security);
1135 IServerSecurity_Release(server_security);
1138 return hr;
1141 /***********************************************************************
1142 * CoInitializeSecurity (combase.@)
1144 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
1145 SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
1146 DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1148 FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1149 imp_level, reserved2, capabilities, reserved3);
1151 return S_OK;
1154 /***********************************************************************
1155 * CoGetObjectContext (combase.@)
1157 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1159 IObjContext *context;
1160 HRESULT hr;
1162 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1164 *ppv = NULL;
1165 hr = CoGetContextToken((ULONG_PTR *)&context);
1166 if (FAILED(hr))
1167 return hr;
1169 return IObjContext_QueryInterface(context, riid, ppv);
1172 /***********************************************************************
1173 * CoGetDefaultContext (combase.@)
1175 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1177 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1179 return E_NOINTERFACE;
1182 /***********************************************************************
1183 * CoGetCallState (combase.@)
1185 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1187 FIXME("%d, %p.\n", arg1, arg2);
1189 return E_NOTIMPL;
1192 /***********************************************************************
1193 * CoGetActivationState (combase.@)
1195 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1197 FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3);
1199 return E_NOTIMPL;
1202 /******************************************************************************
1203 * CoGetTreatAsClass (combase.@)
1205 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1207 WCHAR buffW[CHARS_IN_GUID];
1208 LONG len = sizeof(buffW);
1209 HRESULT hr = S_OK;
1210 HKEY hkey = NULL;
1212 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1214 if (!clsidOld || !clsidNew)
1215 return E_INVALIDARG;
1217 *clsidNew = *clsidOld;
1219 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1220 if (FAILED(hr))
1222 hr = S_FALSE;
1223 goto done;
1226 if (RegQueryValueW(hkey, NULL, buffW, &len))
1228 hr = S_FALSE;
1229 goto done;
1232 hr = CLSIDFromString(buffW, clsidNew);
1233 if (FAILED(hr))
1234 ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), hr);
1235 done:
1236 if (hkey) RegCloseKey(hkey);
1237 return hr;
1240 /******************************************************************************
1241 * ProgIDFromCLSID (combase.@)
1243 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1245 ACTCTX_SECTION_KEYED_DATA data;
1246 LONG progidlen = 0;
1247 HKEY hkey;
1248 REGSAM opposite = (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1249 BOOL is_wow64;
1250 HRESULT hr;
1252 if (!progid)
1253 return E_INVALIDARG;
1255 *progid = NULL;
1257 data.cbSize = sizeof(data);
1258 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
1259 clsid, &data))
1261 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1262 if (comclass->progid_len)
1264 WCHAR *ptrW;
1266 *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
1267 if (!*progid) return E_OUTOFMEMORY;
1269 ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
1270 memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
1271 return S_OK;
1273 else
1274 return REGDB_E_CLASSNOTREG;
1277 hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
1278 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1280 hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey);
1281 if (FAILED(hr))
1282 return hr;
1285 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1286 hr = REGDB_E_CLASSNOTREG;
1288 if (hr == S_OK)
1290 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1291 if (*progid)
1293 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1295 hr = REGDB_E_CLASSNOTREG;
1296 CoTaskMemFree(*progid);
1297 *progid = NULL;
1300 else
1301 hr = E_OUTOFMEMORY;
1304 RegCloseKey(hkey);
1305 return hr;
1308 static inline BOOL is_valid_hex(WCHAR c)
1310 if (!(((c >= '0') && (c <= '9')) ||
1311 ((c >= 'a') && (c <= 'f')) ||
1312 ((c >= 'A') && (c <= 'F'))))
1313 return FALSE;
1314 return TRUE;
1317 static const BYTE guid_conv_table[256] =
1319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1320 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1322 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1323 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1324 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1325 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1328 static BOOL guid_from_string(LPCWSTR s, GUID *id)
1330 int i;
1332 if (!s || s[0] != '{')
1334 memset(id, 0, sizeof(*id));
1335 if (!s) return TRUE;
1336 return FALSE;
1339 TRACE("%s -> %p\n", debugstr_w(s), id);
1341 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1343 id->Data1 = 0;
1344 for (i = 1; i < 9; ++i)
1346 if (!is_valid_hex(s[i])) return FALSE;
1347 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1349 if (s[9] != '-') return FALSE;
1351 id->Data2 = 0;
1352 for (i = 10; i < 14; ++i)
1354 if (!is_valid_hex(s[i])) return FALSE;
1355 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1357 if (s[14] != '-') return FALSE;
1359 id->Data3 = 0;
1360 for (i = 15; i < 19; ++i)
1362 if (!is_valid_hex(s[i])) return FALSE;
1363 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1365 if (s[19] != '-') return FALSE;
1367 for (i = 20; i < 37; i += 2)
1369 if (i == 24)
1371 if (s[i] != '-') return FALSE;
1372 i++;
1374 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1375 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1378 if (s[37] == '}' && s[38] == '\0')
1379 return TRUE;
1381 return FALSE;
1384 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1386 WCHAR buf2[CHARS_IN_GUID];
1387 LONG buf2len = sizeof(buf2);
1388 HKEY xhkey;
1389 WCHAR *buf;
1391 memset(clsid, 0, sizeof(*clsid));
1392 buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1393 if (!buf) return E_OUTOFMEMORY;
1395 lstrcpyW(buf, progid);
1396 lstrcatW(buf, L"\\CLSID");
1397 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1399 free(buf);
1400 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1401 return CO_E_CLASSSTRING;
1403 free(buf);
1405 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1407 RegCloseKey(xhkey);
1408 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1409 return CO_E_CLASSSTRING;
1411 RegCloseKey(xhkey);
1412 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1415 /******************************************************************************
1416 * CLSIDFromProgID (combase.@)
1418 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1420 ACTCTX_SECTION_KEYED_DATA data;
1422 if (!progid || !clsid)
1423 return E_INVALIDARG;
1425 data.cbSize = sizeof(data);
1426 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1427 progid, &data))
1429 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1430 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1431 *clsid = *alias;
1432 return S_OK;
1435 return clsid_from_string_reg(progid, clsid);
1438 /******************************************************************************
1439 * CLSIDFromProgIDEx (combase.@)
1441 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1443 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1445 return CLSIDFromProgID(progid, clsid);
1448 /******************************************************************************
1449 * CLSIDFromString (combase.@)
1451 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1453 CLSID tmp_id;
1454 HRESULT hr;
1456 if (!clsid)
1457 return E_INVALIDARG;
1459 if (guid_from_string(str, clsid))
1460 return S_OK;
1462 /* It appears a ProgID is also valid */
1463 hr = clsid_from_string_reg(str, &tmp_id);
1464 if (SUCCEEDED(hr))
1465 *clsid = tmp_id;
1467 return hr;
1470 /******************************************************************************
1471 * IIDFromString (combase.@)
1473 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1475 TRACE("%s, %p\n", debugstr_w(str), iid);
1477 if (!str)
1479 memset(iid, 0, sizeof(*iid));
1480 return S_OK;
1483 /* length mismatch is a special case */
1484 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1485 return E_INVALIDARG;
1487 if (str[0] != '{')
1488 return CO_E_IIDSTRING;
1490 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1493 /******************************************************************************
1494 * StringFromCLSID (combase.@)
1496 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1498 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1499 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1500 return S_OK;
1503 /******************************************************************************
1504 * StringFromGUID2 (combase.@)
1506 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1508 if (!guid || cmax < CHARS_IN_GUID) return 0;
1509 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1510 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1511 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1512 return CHARS_IN_GUID;
1515 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1517 ULONG i;
1519 for (i = 0; i < count; i++)
1521 mqi[i].pItf = NULL;
1522 mqi[i].hr = hr;
1526 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1528 ULONG index = 0, fetched = 0;
1530 if (include_unk)
1532 mqi[0].hr = S_OK;
1533 mqi[0].pItf = unk;
1534 index = fetched = 1;
1537 for (; index < count; index++)
1539 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1540 if (mqi[index].hr == S_OK)
1541 fetched++;
1544 if (!include_unk)
1545 IUnknown_Release(unk);
1547 if (fetched == 0)
1548 return E_NOINTERFACE;
1550 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1553 /***********************************************************************
1554 * CoGetInstanceFromFile (combase.@)
1556 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1557 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1558 MULTI_QI *results)
1560 IPersistFile *pf = NULL;
1561 IUnknown *obj = NULL;
1562 CLSID clsid;
1563 HRESULT hr;
1565 if (!count || !results)
1566 return E_INVALIDARG;
1568 if (server_info)
1569 FIXME("() non-NULL server_info not supported\n");
1571 init_multi_qi(count, results, E_NOINTERFACE);
1573 if (!rclsid)
1575 hr = GetClassFile(filename, &clsid);
1576 if (FAILED(hr))
1578 ERR("Failed to get CLSID from a file.\n");
1579 return hr;
1582 rclsid = &clsid;
1585 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1586 if (hr != S_OK)
1588 init_multi_qi(count, results, hr);
1589 return hr;
1592 /* Init from file */
1593 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1594 if (FAILED(hr))
1596 init_multi_qi(count, results, hr);
1597 IUnknown_Release(obj);
1598 return hr;
1601 hr = IPersistFile_Load(pf, filename, grfmode);
1602 IPersistFile_Release(pf);
1603 if (SUCCEEDED(hr))
1604 return return_multi_qi(obj, count, results, FALSE);
1605 else
1607 init_multi_qi(count, results, hr);
1608 IUnknown_Release(obj);
1609 return hr;
1613 /***********************************************************************
1614 * CoGetInstanceFromIStorage (combase.@)
1616 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1617 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1619 IPersistStorage *ps = NULL;
1620 IUnknown *obj = NULL;
1621 STATSTG stat;
1622 HRESULT hr;
1624 if (!count || !results || !storage)
1625 return E_INVALIDARG;
1627 if (server_info)
1628 FIXME("() non-NULL server_info not supported\n");
1630 init_multi_qi(count, results, E_NOINTERFACE);
1632 if (!rclsid)
1634 memset(&stat.clsid, 0, sizeof(stat.clsid));
1635 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1636 if (FAILED(hr))
1638 ERR("Failed to get CLSID from a storage.\n");
1639 return hr;
1642 rclsid = &stat.clsid;
1645 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1646 if (hr != S_OK)
1647 return hr;
1649 /* Init from IStorage */
1650 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1651 if (FAILED(hr))
1652 ERR("failed to get IPersistStorage\n");
1654 if (ps)
1656 IPersistStorage_Load(ps, storage);
1657 IPersistStorage_Release(ps);
1660 return return_multi_qi(obj, count, results, FALSE);
1663 /***********************************************************************
1664 * CoCreateInstance (combase.@)
1666 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1667 REFIID riid, void **obj)
1669 MULTI_QI multi_qi = { .pIID = riid };
1670 HRESULT hr;
1672 TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1674 if (!obj)
1675 return E_POINTER;
1677 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1678 *obj = multi_qi.pItf;
1679 return hr;
1682 /***********************************************************************
1683 * CoCreateInstanceFromApp (combase.@)
1685 HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1686 void *server_info, ULONG count, MULTI_QI *results)
1688 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1689 count, results);
1691 return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1692 count, results);
1695 static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1696 COSERVERINFO *server_info, REFIID riid, void **obj)
1698 struct class_reg_data clsreg = { 0 };
1699 HRESULT hr = E_UNEXPECTED;
1700 IUnknown *registered_obj;
1701 struct apartment *apt;
1703 if (!obj)
1704 return E_INVALIDARG;
1706 *obj = NULL;
1708 if (!(apt = apartment_get_current_or_mta()))
1710 ERR("apartment not initialised\n");
1711 return CO_E_NOTINITIALIZED;
1714 if (server_info)
1715 FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1717 if (clscontext & CLSCTX_INPROC_SERVER)
1719 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1720 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1721 (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1722 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1724 apartment_release(apt);
1726 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
1727 return get_builtin_class_factory(rclsid, riid, obj);
1728 else
1729 return Ole32DllGetClassObject(rclsid, riid, obj);
1733 if (clscontext & CLSCTX_INPROC)
1735 ACTCTX_SECTION_KEYED_DATA data;
1737 data.cbSize = sizeof(data);
1738 /* search activation context first */
1739 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1740 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1742 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1744 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1745 clsreg.u.actctx.hactctx = data.hActCtx;
1746 clsreg.u.actctx.threading_model = comclass->model;
1747 clsreg.origin = CLASS_REG_ACTCTX;
1749 hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1750 ReleaseActCtx(data.hActCtx);
1751 apartment_release(apt);
1752 return hr;
1757 * First, try and see if we can't match the class ID with one of the
1758 * registered classes.
1760 if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1762 hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1763 IUnknown_Release(registered_obj);
1764 apartment_release(apt);
1765 return hr;
1768 /* First try in-process server */
1769 if (clscontext & CLSCTX_INPROC_SERVER)
1771 HKEY hkey;
1773 hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1774 if (FAILED(hr))
1776 if (hr == REGDB_E_CLASSNOTREG)
1777 ERR("class %s not registered\n", debugstr_guid(rclsid));
1778 else if (hr == REGDB_E_KEYMISSING)
1780 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1781 hr = REGDB_E_CLASSNOTREG;
1785 if (SUCCEEDED(hr))
1787 clsreg.u.hkey = hkey;
1788 clsreg.origin = CLASS_REG_REGISTRY;
1790 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1791 RegCloseKey(hkey);
1794 /* return if we got a class, otherwise fall through to one of the
1795 * other types */
1796 if (SUCCEEDED(hr))
1798 apartment_release(apt);
1799 return hr;
1803 /* Next try in-process handler */
1804 if (clscontext & CLSCTX_INPROC_HANDLER)
1806 HKEY hkey;
1808 hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1809 if (FAILED(hr))
1811 if (hr == REGDB_E_CLASSNOTREG)
1812 ERR("class %s not registered\n", debugstr_guid(rclsid));
1813 else if (hr == REGDB_E_KEYMISSING)
1815 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1816 hr = REGDB_E_CLASSNOTREG;
1820 if (SUCCEEDED(hr))
1822 clsreg.u.hkey = hkey;
1823 clsreg.origin = CLASS_REG_REGISTRY;
1825 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1826 RegCloseKey(hkey);
1829 /* return if we got a class, otherwise fall through to one of the
1830 * other types */
1831 if (SUCCEEDED(hr))
1833 apartment_release(apt);
1834 return hr;
1837 apartment_release(apt);
1839 /* Next try out of process */
1840 if (clscontext & CLSCTX_LOCAL_SERVER)
1842 hr = rpc_get_local_class_object(rclsid, riid, obj);
1843 if (SUCCEEDED(hr))
1844 return hr;
1847 /* Finally try remote: this requires networked DCOM (a lot of work) */
1848 if (clscontext & CLSCTX_REMOTE_SERVER)
1850 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1851 hr = REGDB_E_CLASSNOTREG;
1854 if (FAILED(hr))
1855 ERR("no class object %s could be created for context %#lx\n", debugstr_guid(rclsid), clscontext);
1857 return hr;
1860 /***********************************************************************
1861 * CoCreateInstanceEx (combase.@)
1863 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1864 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1866 IClassFactory *factory;
1867 IUnknown *unk = NULL;
1868 CLSID clsid;
1869 HRESULT hr;
1871 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1873 if (!count || !results)
1874 return E_INVALIDARG;
1876 if (server_info)
1877 FIXME("Server info is not supported.\n");
1879 init_multi_qi(count, results, E_NOINTERFACE);
1881 clsid = *rclsid;
1882 if (!(cls_context & CLSCTX_APPCONTAINER))
1883 CoGetTreatAsClass(rclsid, &clsid);
1885 if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1886 return hr;
1888 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1889 IClassFactory_Release(factory);
1890 if (FAILED(hr))
1892 if (hr == CLASS_E_NOAGGREGATION && outer)
1893 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1894 else
1895 FIXME("no instance created for interface %s of class %s, hr %#lx.\n",
1896 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1897 return hr;
1900 return return_multi_qi(unk, count, results, TRUE);
1903 /***********************************************************************
1904 * CoGetClassObject (combase.@)
1906 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1907 COSERVERINFO *server_info, REFIID riid, void **obj)
1909 TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1911 return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1914 /***********************************************************************
1915 * CoFreeUnusedLibraries (combase.@)
1917 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1919 CoFreeUnusedLibrariesEx(INFINITE, 0);
1922 /***********************************************************************
1923 * CoGetCallContext (combase.@)
1925 HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1927 struct tlsdata *tlsdata;
1928 HRESULT hr;
1930 TRACE("%s, %p\n", debugstr_guid(riid), obj);
1932 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1933 return hr;
1935 if (!tlsdata->call_state)
1936 return RPC_E_CALL_COMPLETE;
1938 return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1941 /***********************************************************************
1942 * CoSwitchCallContext (combase.@)
1944 HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1946 struct tlsdata *tlsdata;
1947 HRESULT hr;
1949 TRACE("%p, %p\n", context, old_context);
1951 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1952 return hr;
1954 /* Reference counts are not touched. */
1955 *old_context = tlsdata->call_state;
1956 tlsdata->call_state = context;
1958 return S_OK;
1961 /******************************************************************************
1962 * CoRegisterInitializeSpy (combase.@)
1964 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1966 struct tlsdata *tlsdata;
1967 struct init_spy *entry;
1968 unsigned int id;
1969 HRESULT hr;
1971 TRACE("%p, %p\n", spy, cookie);
1973 if (!spy || !cookie)
1974 return E_INVALIDARG;
1976 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1977 return hr;
1979 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1980 if (FAILED(hr))
1981 return hr;
1983 entry = malloc(sizeof(*entry));
1984 if (!entry)
1986 IInitializeSpy_Release(spy);
1987 return E_OUTOFMEMORY;
1990 entry->spy = spy;
1992 id = 0;
1993 while (get_spy_entry(tlsdata, id) != NULL)
1995 id++;
1998 entry->id = id;
1999 list_add_head(&tlsdata->spies, &entry->entry);
2001 cookie->u.HighPart = GetCurrentThreadId();
2002 cookie->u.LowPart = entry->id;
2004 return S_OK;
2007 /******************************************************************************
2008 * CoRevokeInitializeSpy (combase.@)
2010 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
2012 struct tlsdata *tlsdata;
2013 struct init_spy *spy;
2014 HRESULT hr;
2016 TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
2018 if (cookie.u.HighPart != GetCurrentThreadId())
2019 return E_INVALIDARG;
2021 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2022 return hr;
2024 if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
2026 IInitializeSpy_Release(spy->spy);
2027 spy->spy = NULL;
2028 if (!tlsdata->spies_lock)
2030 list_remove(&spy->entry);
2031 free(spy);
2033 return S_OK;
2036 static BOOL com_peek_message(struct apartment *apt, MSG *msg)
2038 /* First try to retrieve messages for incoming COM calls to the apartment window */
2039 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
2040 /* Next retrieve other messages necessary for the app to remain responsive */
2041 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
2042 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
2045 /***********************************************************************
2046 * CoWaitForMultipleHandles (combase.@)
2048 HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
2049 DWORD *index)
2051 BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
2052 DWORD start_time, wait_flags = 0;
2053 struct tlsdata *tlsdata;
2054 struct apartment *apt;
2055 UINT exit_code;
2056 HRESULT hr;
2058 TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index);
2060 if (!index)
2061 return E_INVALIDARG;
2063 *index = 0;
2065 if (!handles)
2066 return E_INVALIDARG;
2068 if (!handle_count)
2069 return RPC_E_NO_SYNC;
2071 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2072 return hr;
2074 apt = com_get_current_apt();
2075 message_loop = apt && !apt->multi_threaded;
2077 if (flags & COWAIT_WAITALL)
2078 wait_flags |= MWMO_WAITALL;
2079 if (flags & COWAIT_ALERTABLE)
2080 wait_flags |= MWMO_ALERTABLE;
2082 start_time = GetTickCount();
2084 while (TRUE)
2086 DWORD now = GetTickCount(), res;
2088 if (now - start_time > timeout)
2090 hr = RPC_S_CALLPENDING;
2091 break;
2094 if (message_loop)
2096 TRACE("waiting for rpc completion or window message\n");
2098 res = WAIT_TIMEOUT;
2100 if (check_apc)
2102 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
2103 check_apc = FALSE;
2106 if (res == WAIT_TIMEOUT)
2107 res = MsgWaitForMultipleObjectsEx(handle_count, handles,
2108 timeout == INFINITE ? INFINITE : start_time + timeout - now,
2109 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
2111 if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
2113 int msg_count = 0;
2114 MSG msg;
2116 /* call message filter */
2118 if (apt->filter)
2120 PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
2121 DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
2123 TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled);
2125 switch (be_handled)
2127 case PENDINGMSG_CANCELCALL:
2128 WARN("call canceled\n");
2129 hr = RPC_E_CALL_CANCELED;
2130 break;
2131 case PENDINGMSG_WAITNOPROCESS:
2132 case PENDINGMSG_WAITDEFPROCESS:
2133 default:
2134 /* FIXME: MSDN is very vague about the difference
2135 * between WAITNOPROCESS and WAITDEFPROCESS - there
2136 * appears to be none, so it is possibly a left-over
2137 * from the 16-bit world. */
2138 break;
2142 if (!apt->win)
2144 /* If window is NULL on apartment, peek at messages so that it will not trigger
2145 * MsgWaitForMultipleObjects next time. */
2146 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
2149 /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
2150 * so after processing 100 messages we go back to checking the wait handles */
2151 while (msg_count++ < 100 && com_peek_message(apt, &msg))
2153 if (msg.message == WM_QUIT)
2155 TRACE("Received WM_QUIT message\n");
2156 post_quit = TRUE;
2157 exit_code = msg.wParam;
2159 else
2161 TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2162 TranslateMessage(&msg);
2163 DispatchMessageW(&msg);
2166 continue;
2169 else
2171 TRACE("Waiting for rpc completion\n");
2173 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2174 (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2177 switch (res)
2179 case WAIT_TIMEOUT:
2180 hr = RPC_S_CALLPENDING;
2181 break;
2182 case WAIT_FAILED:
2183 hr = HRESULT_FROM_WIN32(GetLastError());
2184 break;
2185 default:
2186 *index = res;
2187 break;
2189 break;
2191 if (post_quit) PostQuitMessage(exit_code);
2193 TRACE("-- %#lx\n", hr);
2195 return hr;
2198 /******************************************************************************
2199 * CoRegisterMessageFilter (combase.@)
2201 HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2203 IMessageFilter *old_filter;
2204 struct apartment *apt;
2206 TRACE("%p, %p\n", filter, ret_filter);
2208 apt = com_get_current_apt();
2210 /* Can't set a message filter in a multi-threaded apartment */
2211 if (!apt || apt->multi_threaded)
2213 WARN("Can't set message filter in MTA or uninitialized apt\n");
2214 return CO_E_NOT_SUPPORTED;
2217 if (filter)
2218 IMessageFilter_AddRef(filter);
2220 EnterCriticalSection(&apt->cs);
2222 old_filter = apt->filter;
2223 apt->filter = filter;
2225 LeaveCriticalSection(&apt->cs);
2227 if (ret_filter)
2228 *ret_filter = old_filter;
2229 else if (old_filter)
2230 IMessageFilter_Release(old_filter);
2232 return S_OK;
2235 static void com_revoke_all_ps_clsids(void)
2237 struct registered_ps *cur, *cur2;
2239 EnterCriticalSection(&cs_registered_ps);
2241 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2243 list_remove(&cur->entry);
2244 free(cur);
2247 LeaveCriticalSection(&cs_registered_ps);
2250 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2252 WCHAR value[CHARS_IN_GUID];
2253 HKEY hkey;
2254 DWORD len;
2256 access |= KEY_READ;
2258 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2259 return REGDB_E_IIDNOTREG;
2261 len = sizeof(value);
2262 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2263 return REGDB_E_IIDNOTREG;
2264 RegCloseKey(hkey);
2266 if (CLSIDFromString(value, pclsid) != NOERROR)
2267 return REGDB_E_IIDNOTREG;
2269 return S_OK;
2272 /*****************************************************************************
2273 * CoGetPSClsid (combase.@)
2275 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2277 static const WCHAR interfaceW[] = L"Interface\\";
2278 static const WCHAR psW[] = L"\\ProxyStubClsid32";
2279 WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2280 ACTCTX_SECTION_KEYED_DATA data;
2281 struct registered_ps *cur;
2282 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2283 BOOL is_wow64;
2284 HRESULT hr;
2286 TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2288 if (!InternalIsProcessInitialized())
2290 ERR("apartment not initialised\n");
2291 return CO_E_NOTINITIALIZED;
2294 if (!pclsid)
2295 return E_INVALIDARG;
2297 EnterCriticalSection(&cs_registered_ps);
2299 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2301 if (IsEqualIID(&cur->iid, riid))
2303 *pclsid = cur->clsid;
2304 LeaveCriticalSection(&cs_registered_ps);
2305 return S_OK;
2309 LeaveCriticalSection(&cs_registered_ps);
2311 data.cbSize = sizeof(data);
2312 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2313 riid, &data))
2315 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2316 *pclsid = ifaceps->iid;
2317 return S_OK;
2320 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2321 lstrcpyW(path, interfaceW);
2322 StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2323 lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2325 hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid);
2326 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2327 hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid);
2329 if (hr == S_OK)
2330 TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2331 else
2332 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2334 return hr;
2337 /*****************************************************************************
2338 * CoRegisterPSClsid (combase.@)
2340 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2342 struct registered_ps *cur;
2344 TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2346 if (!InternalIsProcessInitialized())
2348 ERR("apartment not initialised\n");
2349 return CO_E_NOTINITIALIZED;
2352 EnterCriticalSection(&cs_registered_ps);
2354 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2356 if (IsEqualIID(&cur->iid, riid))
2358 cur->clsid = *rclsid;
2359 LeaveCriticalSection(&cs_registered_ps);
2360 return S_OK;
2364 cur = malloc(sizeof(*cur));
2365 if (!cur)
2367 LeaveCriticalSection(&cs_registered_ps);
2368 return E_OUTOFMEMORY;
2371 cur->iid = *riid;
2372 cur->clsid = *rclsid;
2373 list_add_head(&registered_proxystubs, &cur->entry);
2375 LeaveCriticalSection(&cs_registered_ps);
2377 return S_OK;
2380 struct thread_context
2382 IComThreadingInfo IComThreadingInfo_iface;
2383 IContextCallback IContextCallback_iface;
2384 IObjContext IObjContext_iface;
2385 LONG refcount;
2388 static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2390 return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2393 static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2395 return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2398 static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2400 return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2403 static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2405 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2407 *obj = NULL;
2409 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2410 IsEqualIID(riid, &IID_IUnknown))
2412 *obj = &context->IComThreadingInfo_iface;
2414 else if (IsEqualIID(riid, &IID_IContextCallback))
2416 *obj = &context->IContextCallback_iface;
2418 else if (IsEqualIID(riid, &IID_IObjContext))
2420 *obj = &context->IObjContext_iface;
2423 if (*obj)
2425 IUnknown_AddRef((IUnknown *)*obj);
2426 return S_OK;
2429 FIXME("interface not implemented %s\n", debugstr_guid(riid));
2430 return E_NOINTERFACE;
2433 static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2435 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2436 return InterlockedIncrement(&context->refcount);
2439 static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2441 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2443 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2444 releasing context while refcount is at 0 destroys it. */
2445 if (!context->refcount)
2447 free(context);
2448 return 0;
2451 return InterlockedDecrement(&context->refcount);
2454 static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2456 APTTYPEQUALIFIER qualifier;
2458 TRACE("%p\n", apttype);
2460 return CoGetApartmentType(apttype, &qualifier);
2463 static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2465 APTTYPEQUALIFIER qualifier;
2466 APTTYPE apttype;
2467 HRESULT hr;
2469 hr = CoGetApartmentType(&apttype, &qualifier);
2470 if (FAILED(hr))
2471 return hr;
2473 TRACE("%p\n", thdtype);
2475 switch (apttype)
2477 case APTTYPE_STA:
2478 case APTTYPE_MAINSTA:
2479 *thdtype = THDTYPE_PROCESSMESSAGES;
2480 break;
2481 default:
2482 *thdtype = THDTYPE_BLOCKMESSAGES;
2483 break;
2485 return S_OK;
2488 static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2490 TRACE("%p\n", logical_thread_id);
2492 return CoGetCurrentLogicalThreadId(logical_thread_id);
2495 static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2497 FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2499 return E_NOTIMPL;
2502 static const IComThreadingInfoVtbl thread_context_info_vtbl =
2504 thread_context_info_QueryInterface,
2505 thread_context_info_AddRef,
2506 thread_context_info_Release,
2507 thread_context_info_GetCurrentApartmentType,
2508 thread_context_info_GetCurrentThreadType,
2509 thread_context_info_GetCurrentLogicalThreadId,
2510 thread_context_info_SetCurrentLogicalThreadId
2513 static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2515 struct thread_context *context = impl_from_IContextCallback(iface);
2516 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2519 static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2521 struct thread_context *context = impl_from_IContextCallback(iface);
2522 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2525 static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2527 struct thread_context *context = impl_from_IContextCallback(iface);
2528 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2531 static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2532 PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2534 FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2536 return E_NOTIMPL;
2539 static const IContextCallbackVtbl thread_context_callback_vtbl =
2541 thread_context_callback_QueryInterface,
2542 thread_context_callback_AddRef,
2543 thread_context_callback_Release,
2544 thread_context_callback_ContextCallback
2547 static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2549 struct thread_context *context = impl_from_IObjContext(iface);
2550 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2553 static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2555 struct thread_context *context = impl_from_IObjContext(iface);
2556 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2559 static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2561 struct thread_context *context = impl_from_IObjContext(iface);
2562 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2565 static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2567 FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk);
2569 return E_NOTIMPL;
2572 static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2574 FIXME("%p, %s\n", iface, debugstr_guid(propid));
2576 return E_NOTIMPL;
2579 static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2581 FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2583 return E_NOTIMPL;
2586 static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2588 FIXME("%p, %p\n", iface, props);
2590 return E_NOTIMPL;
2593 static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2595 FIXME("%p\n", iface);
2598 static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2600 FIXME("%p\n", iface);
2603 static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2605 FIXME("%p\n", iface);
2608 static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2610 FIXME("%p\n", iface);
2613 static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2615 FIXME("%p\n", iface);
2618 static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2620 FIXME("%p\n", iface);
2623 static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2625 FIXME("%p\n", iface);
2628 static const IObjContextVtbl thread_object_context_vtbl =
2630 thread_object_context_QueryInterface,
2631 thread_object_context_AddRef,
2632 thread_object_context_Release,
2633 thread_object_context_SetProperty,
2634 thread_object_context_RemoveProperty,
2635 thread_object_context_GetProperty,
2636 thread_object_context_EnumContextProps,
2637 thread_object_context_Reserved1,
2638 thread_object_context_Reserved2,
2639 thread_object_context_Reserved3,
2640 thread_object_context_Reserved4,
2641 thread_object_context_Reserved5,
2642 thread_object_context_Reserved6,
2643 thread_object_context_Reserved7
2646 /***********************************************************************
2647 * CoGetContextToken (combase.@)
2649 HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2651 struct tlsdata *tlsdata;
2652 HRESULT hr;
2654 TRACE("%p\n", token);
2656 if (!InternalIsProcessInitialized())
2658 ERR("apartment not initialised\n");
2659 return CO_E_NOTINITIALIZED;
2662 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2663 return hr;
2665 if (!token)
2666 return E_POINTER;
2668 if (!tlsdata->context_token)
2670 struct thread_context *context;
2672 context = calloc(1, sizeof(*context));
2673 if (!context)
2674 return E_OUTOFMEMORY;
2676 context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2677 context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2678 context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2679 /* Context token does not take a reference, it's always zero until the
2680 interface is explicitly requested with CoGetObjectContext(). */
2681 context->refcount = 0;
2683 tlsdata->context_token = &context->IObjContext_iface;
2686 *token = (ULONG_PTR)tlsdata->context_token;
2687 TRACE("context_token %p\n", tlsdata->context_token);
2689 return S_OK;
2692 /***********************************************************************
2693 * CoGetCurrentLogicalThreadId (combase.@)
2695 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2697 struct tlsdata *tlsdata;
2698 HRESULT hr;
2700 if (!id)
2701 return E_INVALIDARG;
2703 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2704 return hr;
2706 if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2708 CoCreateGuid(&tlsdata->causality_id);
2709 tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2712 *id = tlsdata->causality_id;
2714 return S_OK;
2717 /******************************************************************************
2718 * CoGetCurrentProcess (combase.@)
2720 DWORD WINAPI CoGetCurrentProcess(void)
2722 struct tlsdata *tlsdata;
2724 if (FAILED(com_get_tlsdata(&tlsdata)))
2725 return 0;
2727 if (!tlsdata->thread_seqid)
2728 rpcss_get_next_seqid(&tlsdata->thread_seqid);
2730 return tlsdata->thread_seqid;
2733 /***********************************************************************
2734 * CoFreeUnusedLibrariesEx (combase.@)
2736 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2738 struct apartment *apt = com_get_current_apt();
2739 if (!apt)
2741 ERR("apartment not initialised\n");
2742 return;
2745 apartment_freeunusedlibraries(apt, unload_delay);
2749 * When locked, don't modify list (unless we add a new head), so that it's
2750 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
2752 static inline void lock_init_spies(struct tlsdata *tlsdata)
2754 tlsdata->spies_lock++;
2757 static void unlock_init_spies(struct tlsdata *tlsdata)
2759 struct init_spy *spy, *next;
2761 if (--tlsdata->spies_lock) return;
2763 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2765 if (spy->spy) continue;
2766 list_remove(&spy->entry);
2767 free(spy);
2771 /******************************************************************************
2772 * CoInitializeWOW (combase.@)
2774 HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2776 FIXME("%#lx, %#lx\n", arg1, arg2);
2778 return S_OK;
2781 /******************************************************************************
2782 * CoInitializeEx (combase.@)
2784 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2786 struct tlsdata *tlsdata;
2787 struct init_spy *cursor;
2788 HRESULT hr;
2790 TRACE("%p, %#lx\n", reserved, model);
2792 if (reserved)
2793 WARN("Unexpected reserved argument %p\n", reserved);
2795 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2796 return hr;
2798 if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2799 TRACE("Initializing the COM libraries\n");
2801 lock_init_spies(tlsdata);
2802 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2804 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2806 unlock_init_spies(tlsdata);
2808 hr = enter_apartment(tlsdata, model);
2810 lock_init_spies(tlsdata);
2811 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2813 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2815 unlock_init_spies(tlsdata);
2817 return hr;
2820 /***********************************************************************
2821 * CoUninitialize (combase.@)
2823 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2825 struct tlsdata *tlsdata;
2826 struct init_spy *cursor, *next;
2827 LONG lockcount;
2829 TRACE("\n");
2831 if (FAILED(com_get_tlsdata(&tlsdata)))
2832 return;
2834 lock_init_spies(tlsdata);
2835 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2837 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2839 unlock_init_spies(tlsdata);
2841 /* sanity check */
2842 if (!tlsdata->inits)
2844 ERR("Mismatched CoUninitialize\n");
2846 lock_init_spies(tlsdata);
2847 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2849 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2851 unlock_init_spies(tlsdata);
2853 return;
2856 leave_apartment(tlsdata);
2859 * Decrease the reference count.
2860 * If we are back to 0 locks on the COM library, make sure we free
2861 * all the associated data structures.
2863 lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2864 if (lockcount == 1)
2866 TRACE("Releasing the COM libraries\n");
2868 com_revoke_all_ps_clsids();
2869 DestroyRunningObjectTable();
2871 else if (lockcount < 1)
2873 ERR("Unbalanced lock count %ld\n", lockcount);
2874 InterlockedExchangeAdd(&com_lockcount, 1);
2877 lock_init_spies(tlsdata);
2878 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2880 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2882 unlock_init_spies(tlsdata);
2885 /***********************************************************************
2886 * CoIncrementMTAUsage (combase.@)
2888 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2890 TRACE("%p\n", cookie);
2892 return apartment_increment_mta_usage(cookie);
2895 /***********************************************************************
2896 * CoDecrementMTAUsage (combase.@)
2898 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2900 TRACE("%p\n", cookie);
2902 apartment_decrement_mta_usage(cookie);
2903 return S_OK;
2906 /***********************************************************************
2907 * CoGetApartmentType (combase.@)
2909 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2911 struct tlsdata *tlsdata;
2912 struct apartment *apt;
2913 HRESULT hr;
2915 TRACE("%p, %p\n", type, qualifier);
2917 if (!type || !qualifier)
2918 return E_INVALIDARG;
2920 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2921 return hr;
2923 if (!tlsdata->apt)
2924 *type = APTTYPE_CURRENT;
2925 else if (tlsdata->apt->multi_threaded)
2926 *type = APTTYPE_MTA;
2927 else if (tlsdata->apt->main)
2928 *type = APTTYPE_MAINSTA;
2929 else
2930 *type = APTTYPE_STA;
2932 *qualifier = APTTYPEQUALIFIER_NONE;
2934 if (!tlsdata->apt && (apt = apartment_get_mta()))
2936 apartment_release(apt);
2937 *type = APTTYPE_MTA;
2938 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2939 return S_OK;
2942 return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2945 /******************************************************************************
2946 * CoRegisterClassObject (combase.@)
2947 * BUGS
2948 * MSDN claims that multiple interface registrations are legal, but we
2949 * can't do that with our current implementation.
2951 HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2952 DWORD flags, DWORD *cookie)
2954 static LONG next_cookie;
2956 struct registered_class *newclass;
2957 IUnknown *found_object;
2958 struct apartment *apt;
2959 HRESULT hr = S_OK;
2961 TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2963 if (!cookie || !object)
2964 return E_INVALIDARG;
2966 if (!(apt = apartment_get_current_or_mta()))
2968 ERR("COM was not initialized\n");
2969 return CO_E_NOTINITIALIZED;
2972 *cookie = 0;
2974 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2975 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2976 if (flags & REGCLS_MULTIPLEUSE)
2977 clscontext |= CLSCTX_INPROC_SERVER;
2980 * First, check if the class is already registered.
2981 * If it is, this should cause an error.
2983 if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2985 if (flags & REGCLS_MULTIPLEUSE)
2987 if (clscontext & CLSCTX_LOCAL_SERVER)
2988 hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2989 IUnknown_Release(found_object);
2990 apartment_release(apt);
2991 return hr;
2994 IUnknown_Release(found_object);
2995 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2996 apartment_release(apt);
2997 return CO_E_OBJISREG;
3000 newclass = calloc(1, sizeof(*newclass));
3001 if (!newclass)
3003 apartment_release(apt);
3004 return E_OUTOFMEMORY;
3007 newclass->clsid = *rclsid;
3008 newclass->apartment_id = apt->oxid;
3009 newclass->clscontext = clscontext;
3010 newclass->flags = flags;
3012 if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
3013 newclass->cookie = InterlockedIncrement(&next_cookie);
3015 newclass->object = object;
3016 IUnknown_AddRef(newclass->object);
3018 EnterCriticalSection(&registered_classes_cs);
3019 list_add_tail(&registered_classes, &newclass->entry);
3020 LeaveCriticalSection(&registered_classes_cs);
3022 *cookie = newclass->cookie;
3024 if (clscontext & CLSCTX_LOCAL_SERVER)
3026 IStream *marshal_stream;
3028 hr = apartment_get_local_server_stream(apt, &marshal_stream);
3029 if(FAILED(hr))
3031 apartment_release(apt);
3032 return hr;
3035 hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
3036 IStream_Release(marshal_stream);
3039 apartment_release(apt);
3040 return S_OK;
3043 static void com_revoke_class_object(struct registered_class *entry)
3045 list_remove(&entry->entry);
3047 if (entry->clscontext & CLSCTX_LOCAL_SERVER)
3048 rpc_revoke_local_server(entry->rpcss_cookie);
3050 IUnknown_Release(entry->object);
3051 free(entry);
3054 /* Cleans up rpcss registry */
3055 static void com_revoke_local_servers(void)
3057 struct registered_class *cur, *cur2;
3059 EnterCriticalSection(&registered_classes_cs);
3061 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3063 if (cur->clscontext & CLSCTX_LOCAL_SERVER)
3064 com_revoke_class_object(cur);
3067 LeaveCriticalSection(&registered_classes_cs);
3070 void apartment_revoke_all_classes(const struct apartment *apt)
3072 struct registered_class *cur, *cur2;
3074 EnterCriticalSection(&registered_classes_cs);
3076 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3078 if (cur->apartment_id == apt->oxid)
3079 com_revoke_class_object(cur);
3082 LeaveCriticalSection(&registered_classes_cs);
3085 /***********************************************************************
3086 * CoRevokeClassObject (combase.@)
3088 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
3090 HRESULT hr = E_INVALIDARG;
3091 struct registered_class *cur;
3092 struct apartment *apt;
3094 TRACE("%#lx\n", cookie);
3096 if (!(apt = apartment_get_current_or_mta()))
3098 ERR("COM was not initialized\n");
3099 return CO_E_NOTINITIALIZED;
3102 EnterCriticalSection(&registered_classes_cs);
3104 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
3106 if (cur->cookie != cookie)
3107 continue;
3109 if (cur->apartment_id == apt->oxid)
3111 com_revoke_class_object(cur);
3112 hr = S_OK;
3114 else
3116 ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
3117 hr = RPC_E_WRONG_THREAD;
3120 break;
3123 LeaveCriticalSection(&registered_classes_cs);
3124 apartment_release(apt);
3126 return hr;
3129 /***********************************************************************
3130 * CoAddRefServerProcess (combase.@)
3132 ULONG WINAPI CoAddRefServerProcess(void)
3134 ULONG refs;
3136 TRACE("\n");
3138 EnterCriticalSection(&registered_classes_cs);
3139 refs = ++com_server_process_refcount;
3140 LeaveCriticalSection(&registered_classes_cs);
3142 TRACE("refs before: %ld\n", refs - 1);
3144 return refs;
3147 /***********************************************************************
3148 * CoReleaseServerProcess [OLE32.@]
3150 ULONG WINAPI CoReleaseServerProcess(void)
3152 ULONG refs;
3154 TRACE("\n");
3156 EnterCriticalSection(&registered_classes_cs);
3158 refs = --com_server_process_refcount;
3159 /* FIXME: suspend objects */
3161 LeaveCriticalSection(&registered_classes_cs);
3163 TRACE("refs after: %ld\n", refs);
3165 return refs;
3168 /******************************************************************************
3169 * CoDisconnectObject (combase.@)
3171 HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3173 struct stub_manager *manager;
3174 struct apartment *apt;
3175 IMarshal *marshal;
3176 HRESULT hr;
3178 TRACE("%p, %#lx\n", object, reserved);
3180 if (!object)
3181 return E_INVALIDARG;
3183 hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3184 if (hr == S_OK)
3186 hr = IMarshal_DisconnectObject(marshal, reserved);
3187 IMarshal_Release(marshal);
3188 return hr;
3191 if (!(apt = apartment_get_current_or_mta()))
3193 ERR("apartment not initialised\n");
3194 return CO_E_NOTINITIALIZED;
3197 manager = get_stub_manager_from_object(apt, object, FALSE);
3198 if (manager)
3200 stub_manager_disconnect(manager);
3201 /* Release stub manager twice, to remove the apartment reference. */
3202 stub_manager_int_release(manager);
3203 stub_manager_int_release(manager);
3206 /* Note: native is pretty broken here because it just silently
3207 * fails, without returning an appropriate error code if the object was
3208 * not found, making apps think that the object was disconnected, when
3209 * it actually wasn't */
3211 apartment_release(apt);
3212 return S_OK;
3215 /******************************************************************************
3216 * CoLockObjectExternal (combase.@)
3218 HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3220 struct stub_manager *stubmgr;
3221 struct apartment *apt;
3223 TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3225 if (!(apt = apartment_get_current_or_mta()))
3227 ERR("apartment not initialised\n");
3228 return CO_E_NOTINITIALIZED;
3231 stubmgr = get_stub_manager_from_object(apt, object, lock);
3232 if (!stubmgr)
3234 WARN("stub object not found %p\n", object);
3235 /* Note: native is pretty broken here because it just silently
3236 * fails, without returning an appropriate error code, making apps
3237 * think that the object was disconnected, when it actually wasn't */
3238 apartment_release(apt);
3239 return S_OK;
3242 if (lock)
3243 stub_manager_ext_addref(stubmgr, 1, FALSE);
3244 else
3245 stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3247 stub_manager_int_release(stubmgr);
3248 apartment_release(apt);
3249 return S_OK;
3252 /***********************************************************************
3253 * CoRegisterChannelHook (combase.@)
3255 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3257 TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3259 return rpc_register_channel_hook(guidExtension, channel_hook);
3262 /***********************************************************************
3263 * CoDisableCallCancellation (combase.@)
3265 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3267 struct tlsdata *tlsdata;
3268 HRESULT hr;
3270 TRACE("%p\n", reserved);
3272 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3273 return hr;
3275 if (!tlsdata->cancelcount)
3276 return CO_E_CANCEL_DISABLED;
3278 tlsdata->cancelcount--;
3280 return S_OK;
3283 /***********************************************************************
3284 * CoEnableCallCancellation (combase.@)
3286 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3288 struct tlsdata *tlsdata;
3289 HRESULT hr;
3291 TRACE("%p\n", reserved);
3293 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3294 return hr;
3296 tlsdata->cancelcount++;
3298 return S_OK;
3301 /***********************************************************************
3302 * CoGetCallerTID (combase.@)
3304 HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3306 FIXME("stub!\n");
3307 return E_NOTIMPL;
3310 /***********************************************************************
3311 * CoIsHandlerConnected (combase.@)
3313 BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3315 FIXME("%p\n", object);
3317 return TRUE;
3320 /***********************************************************************
3321 * CoSuspendClassObjects (combase.@)
3323 HRESULT WINAPI CoSuspendClassObjects(void)
3325 FIXME("\n");
3327 return S_OK;
3330 /***********************************************************************
3331 * CoResumeClassObjects (combase.@)
3333 HRESULT WINAPI CoResumeClassObjects(void)
3335 FIXME("stub\n");
3337 return S_OK;
3340 /***********************************************************************
3341 * CoRegisterSurrogate (combase.@)
3343 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3345 FIXME("%p stub\n", surrogate);
3347 return E_NOTIMPL;
3350 /***********************************************************************
3351 * CoRegisterSurrogateEx (combase.@)
3353 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3355 FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3357 return E_NOTIMPL;
3360 /***********************************************************************
3361 * DllMain (combase.@)
3363 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3365 TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved);
3367 switch (reason)
3369 case DLL_PROCESS_ATTACH:
3370 hProxyDll = hinstDLL;
3371 break;
3372 case DLL_PROCESS_DETACH:
3373 com_revoke_local_servers();
3374 if (reserved) break;
3375 apartment_global_cleanup();
3376 DeleteCriticalSection(&registered_classes_cs);
3377 rpc_unregister_channel_hooks();
3378 break;
3379 case DLL_THREAD_DETACH:
3380 com_cleanup_tlsdata();
3381 break;
3384 return TRUE;
3387 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj)
3389 TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj);
3391 *obj = NULL;
3393 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3394 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
3396 return CLASS_E_CLASSNOTAVAILABLE;