winspool: Change CUPS printers print processor to wineps.
[wine.git] / dlls / combase / combase.c
blobd834121e2ef294a12b202a282b9266caf1541e51
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 HINSTANCE hProxyDll;
40 static ULONG_PTR global_options[COMGLB_PROPERTIES_RESERVED3 + 1];
42 /* Ole32 exports */
43 extern void WINAPI DestroyRunningObjectTable(void);
44 extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
47 * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
49 static LONG com_lockcount;
51 static LONG com_server_process_refcount;
53 struct comclassredirect_data
55 ULONG size;
56 ULONG flags;
57 DWORD model;
58 GUID clsid;
59 GUID alias;
60 GUID clsid2;
61 GUID tlbid;
62 ULONG name_len;
63 ULONG name_offset;
64 ULONG progid_len;
65 ULONG progid_offset;
66 ULONG clrdata_len;
67 ULONG clrdata_offset;
68 DWORD miscstatus;
69 DWORD miscstatuscontent;
70 DWORD miscstatusthumbnail;
71 DWORD miscstatusicon;
72 DWORD miscstatusdocprint;
75 struct ifacepsredirect_data
77 ULONG size;
78 DWORD mask;
79 GUID iid;
80 ULONG nummethods;
81 GUID tlbid;
82 GUID base;
83 ULONG name_len;
84 ULONG name_offset;
87 struct progidredirect_data
89 ULONG size;
90 DWORD reserved;
91 ULONG clsid_offset;
94 struct init_spy
96 struct list entry;
97 IInitializeSpy *spy;
98 unsigned int id;
101 struct registered_ps
103 struct list entry;
104 IID iid;
105 CLSID clsid;
108 static struct list registered_proxystubs = LIST_INIT(registered_proxystubs);
110 static CRITICAL_SECTION cs_registered_ps;
111 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
113 0, 0, &cs_registered_ps,
114 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
115 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
117 static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
119 struct registered_class
121 struct list entry;
122 CLSID clsid;
123 OXID apartment_id;
124 IUnknown *object;
125 DWORD clscontext;
126 DWORD flags;
127 unsigned int cookie;
128 unsigned int rpcss_cookie;
131 static struct list registered_classes = LIST_INIT(registered_classes);
133 static CRITICAL_SECTION registered_classes_cs;
134 static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
136 0, 0, &registered_classes_cs,
137 { &registered_classes_cs_debug.ProcessLocksList, &registered_classes_cs_debug.ProcessLocksList },
138 0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") }
140 static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
142 IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
144 struct registered_class *cur;
145 IUnknown *object = NULL;
147 EnterCriticalSection(&registered_classes_cs);
149 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
151 if ((apt->oxid == cur->apartment_id) &&
152 (clscontext & cur->clscontext) &&
153 IsEqualGUID(&cur->clsid, rclsid))
155 object = cur->object;
156 IUnknown_AddRef(cur->object);
157 break;
161 LeaveCriticalSection(&registered_classes_cs);
163 return object;
166 static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
168 struct init_spy *spy;
170 LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry)
172 if (id == spy->id && spy->spy)
173 return spy;
176 return NULL;
179 static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
181 NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
183 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
185 HANDLE subkey, root = attr->RootDirectory;
186 WCHAR *buffer = attr->ObjectName->Buffer;
187 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
188 UNICODE_STRING str;
190 while (i < len && buffer[i] != '\\') i++;
191 if (i == len) return status;
193 attrs = attr->Attributes;
194 attr->ObjectName = &str;
196 while (i < len)
198 str.Buffer = buffer + pos;
199 str.Length = (i - pos) * sizeof(WCHAR);
200 status = NtCreateKey(&subkey, access, attr, 0, NULL, 0, NULL);
201 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
202 if (status) return status;
203 attr->RootDirectory = subkey;
204 while (i < len && buffer[i] == '\\') i++;
205 pos = i;
206 while (i < len && buffer[i] != '\\') i++;
208 str.Buffer = buffer + pos;
209 str.Length = (i - pos) * sizeof(WCHAR);
210 attr->Attributes = attrs;
211 status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
212 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
214 return status;
217 static HKEY classes_root_hkey;
219 static HKEY create_classes_root_hkey(DWORD access)
221 HKEY hkey, ret = 0;
222 OBJECT_ATTRIBUTES attr;
223 UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes");
225 attr.Length = sizeof(attr);
226 attr.RootDirectory = 0;
227 attr.ObjectName = &name;
228 attr.Attributes = 0;
229 attr.SecurityDescriptor = NULL;
230 attr.SecurityQualityOfService = NULL;
232 if (create_key( &hkey, access, &attr )) return 0;
233 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
235 if (!(access & KEY_WOW64_64KEY))
237 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
238 ret = hkey;
239 else
240 NtClose( hkey ); /* somebody beat us to it */
242 else
243 ret = hkey;
244 return ret;
247 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access);
249 static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
251 OBJECT_ATTRIBUTES attr;
252 UNICODE_STRING nameW;
254 if (!(hkey = get_classes_root_hkey(hkey, access)))
255 return ERROR_INVALID_HANDLE;
257 attr.Length = sizeof(attr);
258 attr.RootDirectory = hkey;
259 attr.ObjectName = &nameW;
260 attr.Attributes = 0;
261 attr.SecurityDescriptor = NULL;
262 attr.SecurityQualityOfService = NULL;
263 RtlInitUnicodeString( &nameW, name );
265 return RtlNtStatusToDosError(create_key(retkey, access, &attr));
268 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access)
270 HKEY ret = hkey;
271 const BOOL is_win64 = sizeof(void*) > sizeof(int);
272 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
274 if (hkey == HKEY_CLASSES_ROOT &&
275 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
276 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
277 if (force_wow32 && ret && ret == classes_root_hkey)
279 access &= ~KEY_WOW64_32KEY;
280 if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey))
281 return 0;
282 ret = hkey;
285 return ret;
288 static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
290 OBJECT_ATTRIBUTES attr;
291 UNICODE_STRING nameW;
293 if (!(hkey = get_classes_root_hkey(hkey, access)))
294 return ERROR_INVALID_HANDLE;
296 attr.Length = sizeof(attr);
297 attr.RootDirectory = hkey;
298 attr.ObjectName = &nameW;
299 attr.Attributes = 0;
300 attr.SecurityDescriptor = NULL;
301 attr.SecurityQualityOfService = NULL;
302 RtlInitUnicodeString( &nameW, name );
304 return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
307 HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
309 static const WCHAR clsidW[] = L"CLSID\\";
310 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
311 LONG res;
312 HKEY key;
314 lstrcpyW(path, clsidW);
315 StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID);
316 res = open_classes_key(HKEY_CLASSES_ROOT, path, access, &key);
317 if (res == ERROR_FILE_NOT_FOUND)
318 return REGDB_E_CLASSNOTREG;
319 else if (res != ERROR_SUCCESS)
320 return REGDB_E_READREGDB;
322 if (!keyname)
324 *subkey = key;
325 return S_OK;
328 res = open_classes_key(key, keyname, access, subkey);
329 RegCloseKey(key);
330 if (res == ERROR_FILE_NOT_FOUND)
331 return REGDB_E_KEYMISSING;
332 else if (res != ERROR_SUCCESS)
333 return REGDB_E_READREGDB;
335 return S_OK;
338 /* open HKCR\\AppId\\{string form of appid clsid} key */
339 HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey)
341 static const WCHAR appidkeyW[] = L"AppId\\";
342 DWORD res;
343 WCHAR buf[CHARS_IN_GUID];
344 WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID];
345 DWORD size;
346 HKEY hkey;
347 DWORD type;
348 HRESULT hr;
350 /* read the AppID value under the class's key */
351 hr = open_key_for_clsid(clsid, NULL, access, &hkey);
352 if (FAILED(hr))
353 return hr;
355 size = sizeof(buf);
356 res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size);
357 RegCloseKey(hkey);
358 if (res == ERROR_FILE_NOT_FOUND)
359 return REGDB_E_KEYMISSING;
360 else if (res != ERROR_SUCCESS || type!=REG_SZ)
361 return REGDB_E_READREGDB;
363 lstrcpyW(keyname, appidkeyW);
364 lstrcatW(keyname, buf);
365 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
366 if (res == ERROR_FILE_NOT_FOUND)
367 return REGDB_E_KEYMISSING;
368 else if (res != ERROR_SUCCESS)
369 return REGDB_E_READREGDB;
371 return S_OK;
374 /***********************************************************************
375 * InternalIsProcessInitialized (combase.@)
377 BOOL WINAPI InternalIsProcessInitialized(void)
379 struct apartment *apt;
381 if (!(apt = apartment_get_current_or_mta()))
382 return FALSE;
383 apartment_release(apt);
385 return TRUE;
388 /***********************************************************************
389 * InternalTlsAllocData (combase.@)
391 HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data)
393 if (!(*data = calloc(1, sizeof(**data))))
394 return E_OUTOFMEMORY;
396 list_init(&(*data)->spies);
397 NtCurrentTeb()->ReservedForOle = *data;
399 return S_OK;
402 static void com_cleanup_tlsdata(void)
404 struct tlsdata *tlsdata = NtCurrentTeb()->ReservedForOle;
405 struct init_spy *cursor, *cursor2;
407 if (!tlsdata)
408 return;
410 if (tlsdata->apt)
411 apartment_release(tlsdata->apt);
412 if (tlsdata->errorinfo)
413 IErrorInfo_Release(tlsdata->errorinfo);
414 if (tlsdata->state)
415 IUnknown_Release(tlsdata->state);
417 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &tlsdata->spies, struct init_spy, entry)
419 list_remove(&cursor->entry);
420 if (cursor->spy)
421 IInitializeSpy_Release(cursor->spy);
422 free(cursor);
425 if (tlsdata->context_token)
426 IObjContext_Release(tlsdata->context_token);
428 free(tlsdata);
429 NtCurrentTeb()->ReservedForOle = NULL;
432 struct global_options
434 IGlobalOptions IGlobalOptions_iface;
435 LONG refcount;
438 static inline struct global_options *impl_from_IGlobalOptions(IGlobalOptions *iface)
440 return CONTAINING_RECORD(iface, struct global_options, IGlobalOptions_iface);
443 static HRESULT WINAPI global_options_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
445 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
447 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
449 *ppv = iface;
451 else
453 *ppv = NULL;
454 return E_NOINTERFACE;
457 IUnknown_AddRef((IUnknown *)*ppv);
458 return S_OK;
461 static ULONG WINAPI global_options_AddRef(IGlobalOptions *iface)
463 struct global_options *options = impl_from_IGlobalOptions(iface);
464 LONG refcount = InterlockedIncrement(&options->refcount);
466 TRACE("%p, refcount %ld.\n", iface, refcount);
468 return refcount;
471 static ULONG WINAPI global_options_Release(IGlobalOptions *iface)
473 struct global_options *options = impl_from_IGlobalOptions(iface);
474 LONG refcount = InterlockedDecrement(&options->refcount);
476 TRACE("%p, refcount %ld.\n", iface, refcount);
478 if (!refcount)
479 free(options);
481 return refcount;
484 static HRESULT WINAPI global_options_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
486 FIXME("%p, %u, %Ix.\n", iface, property, value);
488 return S_OK;
491 static HRESULT WINAPI global_options_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
493 TRACE("%p, %u, %p.\n", iface, property, value);
495 if (property < COMGLB_EXCEPTION_HANDLING || property > COMGLB_PROPERTIES_RESERVED3)
496 return E_INVALIDARG;
498 *value = global_options[property];
500 return S_OK;
503 static const IGlobalOptionsVtbl global_options_vtbl =
505 global_options_QueryInterface,
506 global_options_AddRef,
507 global_options_Release,
508 global_options_Set,
509 global_options_Query
512 static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
514 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
516 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
518 *ppv = iface;
519 return S_OK;
522 *ppv = NULL;
523 return E_NOINTERFACE;
526 static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
528 return 2;
531 static ULONG WINAPI class_factory_Release(IClassFactory *iface)
533 return 1;
536 static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL fLock)
538 TRACE("%d\n", fLock);
540 return S_OK;
543 static HRESULT WINAPI global_options_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
545 struct global_options *object;
546 HRESULT hr;
548 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), ppv);
550 if (outer)
551 return E_INVALIDARG;
553 if (!(object = malloc(sizeof(*object))))
554 return E_OUTOFMEMORY;
555 object->IGlobalOptions_iface.lpVtbl = &global_options_vtbl;
556 object->refcount = 1;
558 hr = IGlobalOptions_QueryInterface(&object->IGlobalOptions_iface, riid, ppv);
559 IGlobalOptions_Release(&object->IGlobalOptions_iface);
560 return hr;
563 static const IClassFactoryVtbl global_options_factory_vtbl =
565 class_factory_QueryInterface,
566 class_factory_AddRef,
567 class_factory_Release,
568 global_options_CreateInstance,
569 class_factory_LockServer
572 static IClassFactory global_options_factory = { &global_options_factory_vtbl };
574 static HRESULT get_builtin_class_factory(REFCLSID rclsid, REFIID riid, void **obj)
576 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
577 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
578 return E_UNEXPECTED;
581 /***********************************************************************
582 * FreePropVariantArray (combase.@)
584 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
586 ULONG i;
588 TRACE("%lu, %p.\n", count, rgvars);
590 if (!rgvars)
591 return E_INVALIDARG;
593 for (i = 0; i < count; ++i)
594 PropVariantClear(&rgvars[i]);
596 return S_OK;
599 static HRESULT propvar_validatetype(VARTYPE vt)
601 switch (vt)
603 case VT_EMPTY:
604 case VT_NULL:
605 case VT_I1:
606 case VT_I2:
607 case VT_I4:
608 case VT_I8:
609 case VT_R4:
610 case VT_R8:
611 case VT_CY:
612 case VT_DATE:
613 case VT_BSTR:
614 case VT_ERROR:
615 case VT_BOOL:
616 case VT_DECIMAL:
617 case VT_UI1:
618 case VT_UI2:
619 case VT_UI4:
620 case VT_UI8:
621 case VT_INT:
622 case VT_UINT:
623 case VT_LPSTR:
624 case VT_LPWSTR:
625 case VT_FILETIME:
626 case VT_BLOB:
627 case VT_DISPATCH:
628 case VT_UNKNOWN:
629 case VT_STREAM:
630 case VT_STORAGE:
631 case VT_STREAMED_OBJECT:
632 case VT_STORED_OBJECT:
633 case VT_BLOB_OBJECT:
634 case VT_CF:
635 case VT_CLSID:
636 case VT_I1|VT_VECTOR:
637 case VT_I2|VT_VECTOR:
638 case VT_I4|VT_VECTOR:
639 case VT_I8|VT_VECTOR:
640 case VT_R4|VT_VECTOR:
641 case VT_R8|VT_VECTOR:
642 case VT_CY|VT_VECTOR:
643 case VT_DATE|VT_VECTOR:
644 case VT_BSTR|VT_VECTOR:
645 case VT_ERROR|VT_VECTOR:
646 case VT_BOOL|VT_VECTOR:
647 case VT_VARIANT|VT_VECTOR:
648 case VT_UI1|VT_VECTOR:
649 case VT_UI2|VT_VECTOR:
650 case VT_UI4|VT_VECTOR:
651 case VT_UI8|VT_VECTOR:
652 case VT_LPSTR|VT_VECTOR:
653 case VT_LPWSTR|VT_VECTOR:
654 case VT_FILETIME|VT_VECTOR:
655 case VT_CF|VT_VECTOR:
656 case VT_CLSID|VT_VECTOR:
657 case VT_ARRAY|VT_I1:
658 case VT_ARRAY|VT_UI1:
659 case VT_ARRAY|VT_I2:
660 case VT_ARRAY|VT_UI2:
661 case VT_ARRAY|VT_I4:
662 case VT_ARRAY|VT_UI4:
663 case VT_ARRAY|VT_INT:
664 case VT_ARRAY|VT_UINT:
665 case VT_ARRAY|VT_R4:
666 case VT_ARRAY|VT_R8:
667 case VT_ARRAY|VT_CY:
668 case VT_ARRAY|VT_DATE:
669 case VT_ARRAY|VT_BSTR:
670 case VT_ARRAY|VT_BOOL:
671 case VT_ARRAY|VT_DECIMAL:
672 case VT_ARRAY|VT_DISPATCH:
673 case VT_ARRAY|VT_UNKNOWN:
674 case VT_ARRAY|VT_ERROR:
675 case VT_ARRAY|VT_VARIANT:
676 return S_OK;
678 WARN("Bad type %d\n", vt);
679 return STG_E_INVALIDPARAMETER;
682 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
684 ULONG i;
685 for (i = 0; i < count; ++i)
686 CoTaskMemFree(data[i].pClipData);
689 /***********************************************************************
690 * PropVariantClear (combase.@)
692 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
694 HRESULT hr;
696 TRACE("%p.\n", pvar);
698 if (!pvar)
699 return S_OK;
701 hr = propvar_validatetype(pvar->vt);
702 if (FAILED(hr))
704 memset(pvar, 0, sizeof(*pvar));
705 return hr;
708 switch (pvar->vt)
710 case VT_EMPTY:
711 case VT_NULL:
712 case VT_I1:
713 case VT_I2:
714 case VT_I4:
715 case VT_I8:
716 case VT_R4:
717 case VT_R8:
718 case VT_CY:
719 case VT_DATE:
720 case VT_ERROR:
721 case VT_BOOL:
722 case VT_DECIMAL:
723 case VT_UI1:
724 case VT_UI2:
725 case VT_UI4:
726 case VT_UI8:
727 case VT_INT:
728 case VT_UINT:
729 case VT_FILETIME:
730 break;
731 case VT_DISPATCH:
732 case VT_UNKNOWN:
733 case VT_STREAM:
734 case VT_STREAMED_OBJECT:
735 case VT_STORAGE:
736 case VT_STORED_OBJECT:
737 if (pvar->pStream)
738 IStream_Release(pvar->pStream);
739 break;
740 case VT_CLSID:
741 case VT_LPSTR:
742 case VT_LPWSTR:
743 /* pick an arbitrary typed pointer - we don't care about the type
744 * as we are just freeing it */
745 CoTaskMemFree(pvar->puuid);
746 break;
747 case VT_BLOB:
748 case VT_BLOB_OBJECT:
749 CoTaskMemFree(pvar->blob.pBlobData);
750 break;
751 case VT_BSTR:
752 SysFreeString(pvar->bstrVal);
753 break;
754 case VT_CF:
755 if (pvar->pclipdata)
757 propvar_free_cf_array(1, pvar->pclipdata);
758 CoTaskMemFree(pvar->pclipdata);
760 break;
761 default:
762 if (pvar->vt & VT_VECTOR)
764 ULONG i;
766 switch (pvar->vt & ~VT_VECTOR)
768 case VT_VARIANT:
769 FreePropVariantArray(pvar->capropvar.cElems, pvar->capropvar.pElems);
770 break;
771 case VT_CF:
772 propvar_free_cf_array(pvar->caclipdata.cElems, pvar->caclipdata.pElems);
773 break;
774 case VT_BSTR:
775 for (i = 0; i < pvar->cabstr.cElems; i++)
776 SysFreeString(pvar->cabstr.pElems[i]);
777 break;
778 case VT_LPSTR:
779 for (i = 0; i < pvar->calpstr.cElems; i++)
780 CoTaskMemFree(pvar->calpstr.pElems[i]);
781 break;
782 case VT_LPWSTR:
783 for (i = 0; i < pvar->calpwstr.cElems; i++)
784 CoTaskMemFree(pvar->calpwstr.pElems[i]);
785 break;
787 if (pvar->vt & ~VT_VECTOR)
789 /* pick an arbitrary VT_VECTOR structure - they all have the same
790 * memory layout */
791 CoTaskMemFree(pvar->capropvar.pElems);
794 else if (pvar->vt & VT_ARRAY)
795 hr = SafeArrayDestroy(pvar->parray);
796 else
798 WARN("Invalid/unsupported type %d\n", pvar->vt);
799 hr = STG_E_INVALIDPARAMETER;
803 memset(pvar, 0, sizeof(*pvar));
804 return hr;
807 /***********************************************************************
808 * PropVariantCopy (combase.@)
810 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
812 ULONG len;
813 HRESULT hr;
815 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
817 hr = propvar_validatetype(pvarSrc->vt);
818 if (FAILED(hr))
819 return DISP_E_BADVARTYPE;
821 /* this will deal with most cases */
822 *pvarDest = *pvarSrc;
824 switch (pvarSrc->vt)
826 case VT_EMPTY:
827 case VT_NULL:
828 case VT_I1:
829 case VT_UI1:
830 case VT_I2:
831 case VT_UI2:
832 case VT_BOOL:
833 case VT_DECIMAL:
834 case VT_I4:
835 case VT_UI4:
836 case VT_R4:
837 case VT_ERROR:
838 case VT_I8:
839 case VT_UI8:
840 case VT_INT:
841 case VT_UINT:
842 case VT_R8:
843 case VT_CY:
844 case VT_DATE:
845 case VT_FILETIME:
846 break;
847 case VT_DISPATCH:
848 case VT_UNKNOWN:
849 case VT_STREAM:
850 case VT_STREAMED_OBJECT:
851 case VT_STORAGE:
852 case VT_STORED_OBJECT:
853 if (pvarDest->pStream)
854 IStream_AddRef(pvarDest->pStream);
855 break;
856 case VT_CLSID:
857 pvarDest->puuid = CoTaskMemAlloc(sizeof(CLSID));
858 *pvarDest->puuid = *pvarSrc->puuid;
859 break;
860 case VT_LPSTR:
861 if (pvarSrc->pszVal)
863 len = strlen(pvarSrc->pszVal);
864 pvarDest->pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
865 CopyMemory(pvarDest->pszVal, pvarSrc->pszVal, (len+1)*sizeof(CHAR));
867 break;
868 case VT_LPWSTR:
869 if (pvarSrc->pwszVal)
871 len = lstrlenW(pvarSrc->pwszVal);
872 pvarDest->pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
873 CopyMemory(pvarDest->pwszVal, pvarSrc->pwszVal, (len+1)*sizeof(WCHAR));
875 break;
876 case VT_BLOB:
877 case VT_BLOB_OBJECT:
878 if (pvarSrc->blob.pBlobData)
880 len = pvarSrc->blob.cbSize;
881 pvarDest->blob.pBlobData = CoTaskMemAlloc(len);
882 CopyMemory(pvarDest->blob.pBlobData, pvarSrc->blob.pBlobData, len);
884 break;
885 case VT_BSTR:
886 pvarDest->bstrVal = SysAllocString(pvarSrc->bstrVal);
887 break;
888 case VT_CF:
889 if (pvarSrc->pclipdata)
891 len = pvarSrc->pclipdata->cbSize - sizeof(pvarSrc->pclipdata->ulClipFmt);
892 pvarDest->pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
893 pvarDest->pclipdata->cbSize = pvarSrc->pclipdata->cbSize;
894 pvarDest->pclipdata->ulClipFmt = pvarSrc->pclipdata->ulClipFmt;
895 pvarDest->pclipdata->pClipData = CoTaskMemAlloc(len);
896 CopyMemory(pvarDest->pclipdata->pClipData, pvarSrc->pclipdata->pClipData, len);
898 break;
899 default:
900 if (pvarSrc->vt & VT_VECTOR)
902 int elemSize;
903 ULONG i;
905 switch (pvarSrc->vt & ~VT_VECTOR)
907 case VT_I1: elemSize = sizeof(pvarSrc->cVal); break;
908 case VT_UI1: elemSize = sizeof(pvarSrc->bVal); break;
909 case VT_I2: elemSize = sizeof(pvarSrc->iVal); break;
910 case VT_UI2: elemSize = sizeof(pvarSrc->uiVal); break;
911 case VT_BOOL: elemSize = sizeof(pvarSrc->boolVal); break;
912 case VT_I4: elemSize = sizeof(pvarSrc->lVal); break;
913 case VT_UI4: elemSize = sizeof(pvarSrc->ulVal); break;
914 case VT_R4: elemSize = sizeof(pvarSrc->fltVal); break;
915 case VT_R8: elemSize = sizeof(pvarSrc->dblVal); break;
916 case VT_ERROR: elemSize = sizeof(pvarSrc->scode); break;
917 case VT_I8: elemSize = sizeof(pvarSrc->hVal); break;
918 case VT_UI8: elemSize = sizeof(pvarSrc->uhVal); break;
919 case VT_CY: elemSize = sizeof(pvarSrc->cyVal); break;
920 case VT_DATE: elemSize = sizeof(pvarSrc->date); break;
921 case VT_FILETIME: elemSize = sizeof(pvarSrc->filetime); break;
922 case VT_CLSID: elemSize = sizeof(*pvarSrc->puuid); break;
923 case VT_CF: elemSize = sizeof(*pvarSrc->pclipdata); break;
924 case VT_BSTR: elemSize = sizeof(pvarSrc->bstrVal); break;
925 case VT_LPSTR: elemSize = sizeof(pvarSrc->pszVal); break;
926 case VT_LPWSTR: elemSize = sizeof(pvarSrc->pwszVal); break;
927 case VT_VARIANT: elemSize = sizeof(*pvarSrc->pvarVal); break;
929 default:
930 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
931 return E_INVALIDARG;
933 len = pvarSrc->capropvar.cElems;
934 pvarDest->capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
935 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
937 for (i = 0; i < len; i++)
938 PropVariantCopy(&pvarDest->capropvar.pElems[i], &pvarSrc->capropvar.pElems[i]);
940 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
942 FIXME("Copy clipformats\n");
944 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
946 for (i = 0; i < len; i++)
947 pvarDest->cabstr.pElems[i] = SysAllocString(pvarSrc->cabstr.pElems[i]);
949 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
951 size_t strLen;
952 for (i = 0; i < len; i++)
954 strLen = lstrlenA(pvarSrc->calpstr.pElems[i]) + 1;
955 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
956 memcpy(pvarDest->calpstr.pElems[i],
957 pvarSrc->calpstr.pElems[i], strLen);
960 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
962 size_t strLen;
963 for (i = 0; i < len; i++)
965 strLen = (lstrlenW(pvarSrc->calpwstr.pElems[i]) + 1) *
966 sizeof(WCHAR);
967 pvarDest->calpstr.pElems[i] = CoTaskMemAlloc(strLen);
968 memcpy(pvarDest->calpstr.pElems[i],
969 pvarSrc->calpstr.pElems[i], strLen);
972 else
973 CopyMemory(pvarDest->capropvar.pElems, pvarSrc->capropvar.pElems, len * elemSize);
975 else if (pvarSrc->vt & VT_ARRAY)
977 pvarDest->uhVal.QuadPart = 0;
978 return SafeArrayCopy(pvarSrc->parray, &pvarDest->parray);
980 else
981 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
984 return S_OK;
987 /***********************************************************************
988 * CoFileTimeNow (combase.@)
990 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
992 GetSystemTimeAsFileTime(filetime);
993 return S_OK;
996 /******************************************************************************
997 * CoCreateGuid (combase.@)
999 HRESULT WINAPI CoCreateGuid(GUID *guid)
1001 RPC_STATUS status;
1003 if (!guid) return E_INVALIDARG;
1005 status = UuidCreate(guid);
1006 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1007 return HRESULT_FROM_WIN32(status);
1010 /******************************************************************************
1011 * CoQueryProxyBlanket (combase.@)
1013 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
1014 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
1015 DWORD *imp_level, void **auth_info, DWORD *capabilities)
1017 IClientSecurity *client_security;
1018 HRESULT hr;
1020 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
1021 auth_info, capabilities);
1023 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1024 if (SUCCEEDED(hr))
1026 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
1027 authn_level, imp_level, auth_info, capabilities);
1028 IClientSecurity_Release(client_security);
1031 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1032 return hr;
1035 /******************************************************************************
1036 * CoSetProxyBlanket (combase.@)
1038 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
1039 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
1041 IClientSecurity *client_security;
1042 HRESULT hr;
1044 TRACE("%p, %lu, %lu, %p, %lu, %lu, %p, %#lx.\n", proxy, authn_service, authz_service, servername,
1045 authn_level, imp_level, auth_info, capabilities);
1047 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1048 if (SUCCEEDED(hr))
1050 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
1051 imp_level, auth_info, capabilities);
1052 IClientSecurity_Release(client_security);
1055 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1056 return hr;
1059 /***********************************************************************
1060 * CoCopyProxy (combase.@)
1062 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
1064 IClientSecurity *client_security;
1065 HRESULT hr;
1067 TRACE("%p, %p.\n", proxy, proxy_copy);
1069 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
1070 if (SUCCEEDED(hr))
1072 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
1073 IClientSecurity_Release(client_security);
1076 if (FAILED(hr)) ERR("-- failed with %#lx.\n", hr);
1077 return hr;
1080 /***********************************************************************
1081 * CoQueryClientBlanket (combase.@)
1083 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
1084 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
1086 IServerSecurity *server_security;
1087 HRESULT hr;
1089 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
1090 privs, capabilities);
1092 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1093 if (SUCCEEDED(hr))
1095 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
1096 imp_level, privs, capabilities);
1097 IServerSecurity_Release(server_security);
1100 return hr;
1103 /***********************************************************************
1104 * CoImpersonateClient (combase.@)
1106 HRESULT WINAPI CoImpersonateClient(void)
1108 IServerSecurity *server_security;
1109 HRESULT hr;
1111 TRACE("\n");
1113 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1114 if (SUCCEEDED(hr))
1116 hr = IServerSecurity_ImpersonateClient(server_security);
1117 IServerSecurity_Release(server_security);
1120 return hr;
1123 /***********************************************************************
1124 * CoRevertToSelf (combase.@)
1126 HRESULT WINAPI CoRevertToSelf(void)
1128 IServerSecurity *server_security;
1129 HRESULT hr;
1131 TRACE("\n");
1133 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
1134 if (SUCCEEDED(hr))
1136 hr = IServerSecurity_RevertToSelf(server_security);
1137 IServerSecurity_Release(server_security);
1140 return hr;
1143 /***********************************************************************
1144 * CoInitializeSecurity (combase.@)
1146 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
1147 SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
1148 DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1150 FIXME("%p, %ld, %p, %p, %ld, %ld, %p, %ld, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1151 imp_level, reserved2, capabilities, reserved3);
1153 return S_OK;
1156 /***********************************************************************
1157 * CoGetObjectContext (combase.@)
1159 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1161 IObjContext *context;
1162 HRESULT hr;
1164 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1166 *ppv = NULL;
1167 hr = CoGetContextToken((ULONG_PTR *)&context);
1168 if (FAILED(hr))
1169 return hr;
1171 return IObjContext_QueryInterface(context, riid, ppv);
1174 /***********************************************************************
1175 * CoGetDefaultContext (combase.@)
1177 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1179 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1181 return E_NOINTERFACE;
1184 /***********************************************************************
1185 * CoGetCallState (combase.@)
1187 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1189 FIXME("%d, %p.\n", arg1, arg2);
1191 return E_NOTIMPL;
1194 /***********************************************************************
1195 * CoGetActivationState (combase.@)
1197 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1199 FIXME("%s, %lx, %p.\n", debugstr_guid(&guid), arg2, arg3);
1201 return E_NOTIMPL;
1204 /******************************************************************************
1205 * CoGetTreatAsClass (combase.@)
1207 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1209 WCHAR buffW[CHARS_IN_GUID];
1210 LONG len = sizeof(buffW);
1211 HRESULT hr = S_OK;
1212 HKEY hkey = NULL;
1214 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1216 if (!clsidOld || !clsidNew)
1217 return E_INVALIDARG;
1219 *clsidNew = *clsidOld;
1221 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1222 if (FAILED(hr))
1224 hr = S_FALSE;
1225 goto done;
1228 if (RegQueryValueW(hkey, NULL, buffW, &len))
1230 hr = S_FALSE;
1231 goto done;
1234 hr = CLSIDFromString(buffW, clsidNew);
1235 if (FAILED(hr))
1236 ERR("Failed to get CLSID from string %s, hr %#lx.\n", debugstr_w(buffW), hr);
1237 done:
1238 if (hkey) RegCloseKey(hkey);
1239 return hr;
1242 /******************************************************************************
1243 * ProgIDFromCLSID (combase.@)
1245 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1247 ACTCTX_SECTION_KEYED_DATA data;
1248 LONG progidlen = 0;
1249 HKEY hkey;
1250 REGSAM opposite = (sizeof(void *) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
1251 BOOL is_wow64;
1252 HRESULT hr;
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) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
1282 hr = open_key_for_clsid(clsid, L"ProgID", opposite | KEY_READ, &hkey);
1283 if (FAILED(hr))
1284 return hr;
1287 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1288 hr = REGDB_E_CLASSNOTREG;
1290 if (hr == S_OK)
1292 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1293 if (*progid)
1295 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1297 hr = REGDB_E_CLASSNOTREG;
1298 CoTaskMemFree(*progid);
1299 *progid = NULL;
1302 else
1303 hr = E_OUTOFMEMORY;
1306 RegCloseKey(hkey);
1307 return hr;
1310 static inline BOOL is_valid_hex(WCHAR c)
1312 if (!(((c >= '0') && (c <= '9')) ||
1313 ((c >= 'a') && (c <= 'f')) ||
1314 ((c >= 'A') && (c <= 'F'))))
1315 return FALSE;
1316 return TRUE;
1319 static const BYTE guid_conv_table[256] =
1321 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1323 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1324 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1325 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1326 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1327 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1330 static BOOL guid_from_string(LPCWSTR s, GUID *id)
1332 int i;
1334 if (!s || s[0] != '{')
1336 memset(id, 0, sizeof(*id));
1337 if (!s) return TRUE;
1338 return FALSE;
1341 TRACE("%s -> %p\n", debugstr_w(s), id);
1343 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1345 id->Data1 = 0;
1346 for (i = 1; i < 9; ++i)
1348 if (!is_valid_hex(s[i])) return FALSE;
1349 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1351 if (s[9] != '-') return FALSE;
1353 id->Data2 = 0;
1354 for (i = 10; i < 14; ++i)
1356 if (!is_valid_hex(s[i])) return FALSE;
1357 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1359 if (s[14] != '-') return FALSE;
1361 id->Data3 = 0;
1362 for (i = 15; i < 19; ++i)
1364 if (!is_valid_hex(s[i])) return FALSE;
1365 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1367 if (s[19] != '-') return FALSE;
1369 for (i = 20; i < 37; i += 2)
1371 if (i == 24)
1373 if (s[i] != '-') return FALSE;
1374 i++;
1376 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1377 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1380 if (s[37] == '}' && s[38] == '\0')
1381 return TRUE;
1383 return FALSE;
1386 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1388 WCHAR buf2[CHARS_IN_GUID];
1389 LONG buf2len = sizeof(buf2);
1390 HKEY xhkey;
1391 WCHAR *buf;
1393 memset(clsid, 0, sizeof(*clsid));
1394 buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1395 if (!buf) return E_OUTOFMEMORY;
1397 lstrcpyW(buf, progid);
1398 lstrcatW(buf, L"\\CLSID");
1399 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1401 free(buf);
1402 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1403 return CO_E_CLASSSTRING;
1405 free(buf);
1407 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1409 RegCloseKey(xhkey);
1410 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1411 return CO_E_CLASSSTRING;
1413 RegCloseKey(xhkey);
1414 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1417 /******************************************************************************
1418 * CLSIDFromProgID (combase.@)
1420 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1422 ACTCTX_SECTION_KEYED_DATA data;
1424 if (!progid || !clsid)
1425 return E_INVALIDARG;
1427 data.cbSize = sizeof(data);
1428 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1429 progid, &data))
1431 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1432 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1433 *clsid = *alias;
1434 return S_OK;
1437 return clsid_from_string_reg(progid, clsid);
1440 /******************************************************************************
1441 * CLSIDFromProgIDEx (combase.@)
1443 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1445 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1447 return CLSIDFromProgID(progid, clsid);
1450 /******************************************************************************
1451 * CLSIDFromString (combase.@)
1453 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1455 CLSID tmp_id;
1456 HRESULT hr;
1458 if (!clsid)
1459 return E_INVALIDARG;
1461 if (guid_from_string(str, clsid))
1462 return S_OK;
1464 /* It appears a ProgID is also valid */
1465 hr = clsid_from_string_reg(str, &tmp_id);
1466 if (SUCCEEDED(hr))
1467 *clsid = tmp_id;
1469 return hr;
1472 /******************************************************************************
1473 * IIDFromString (combase.@)
1475 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1477 TRACE("%s, %p\n", debugstr_w(str), iid);
1479 if (!str)
1481 memset(iid, 0, sizeof(*iid));
1482 return S_OK;
1485 /* length mismatch is a special case */
1486 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1487 return E_INVALIDARG;
1489 if (str[0] != '{')
1490 return CO_E_IIDSTRING;
1492 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1495 /******************************************************************************
1496 * StringFromCLSID (combase.@)
1498 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1500 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1501 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1502 return S_OK;
1505 /******************************************************************************
1506 * StringFromGUID2 (combase.@)
1508 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1510 if (!guid || cmax < CHARS_IN_GUID) return 0;
1511 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1512 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1513 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1514 return CHARS_IN_GUID;
1517 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1519 ULONG i;
1521 for (i = 0; i < count; i++)
1523 mqi[i].pItf = NULL;
1524 mqi[i].hr = hr;
1528 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1530 ULONG index = 0, fetched = 0;
1532 if (include_unk)
1534 mqi[0].hr = S_OK;
1535 mqi[0].pItf = unk;
1536 index = fetched = 1;
1539 for (; index < count; index++)
1541 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1542 if (mqi[index].hr == S_OK)
1543 fetched++;
1546 if (!include_unk)
1547 IUnknown_Release(unk);
1549 if (fetched == 0)
1550 return E_NOINTERFACE;
1552 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1555 /***********************************************************************
1556 * CoGetInstanceFromFile (combase.@)
1558 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1559 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1560 MULTI_QI *results)
1562 IPersistFile *pf = NULL;
1563 IUnknown *obj = NULL;
1564 CLSID clsid;
1565 HRESULT hr;
1567 if (!count || !results)
1568 return E_INVALIDARG;
1570 if (server_info)
1571 FIXME("() non-NULL server_info not supported\n");
1573 init_multi_qi(count, results, E_NOINTERFACE);
1575 if (!rclsid)
1577 hr = GetClassFile(filename, &clsid);
1578 if (FAILED(hr))
1580 ERR("Failed to get CLSID from a file.\n");
1581 return hr;
1584 rclsid = &clsid;
1587 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1588 if (hr != S_OK)
1590 init_multi_qi(count, results, hr);
1591 return hr;
1594 /* Init from file */
1595 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1596 if (FAILED(hr))
1598 init_multi_qi(count, results, hr);
1599 IUnknown_Release(obj);
1600 return hr;
1603 hr = IPersistFile_Load(pf, filename, grfmode);
1604 IPersistFile_Release(pf);
1605 if (SUCCEEDED(hr))
1606 return return_multi_qi(obj, count, results, FALSE);
1607 else
1609 init_multi_qi(count, results, hr);
1610 IUnknown_Release(obj);
1611 return hr;
1615 /***********************************************************************
1616 * CoGetInstanceFromIStorage (combase.@)
1618 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1619 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1621 IPersistStorage *ps = NULL;
1622 IUnknown *obj = NULL;
1623 STATSTG stat;
1624 HRESULT hr;
1626 if (!count || !results || !storage)
1627 return E_INVALIDARG;
1629 if (server_info)
1630 FIXME("() non-NULL server_info not supported\n");
1632 init_multi_qi(count, results, E_NOINTERFACE);
1634 if (!rclsid)
1636 memset(&stat.clsid, 0, sizeof(stat.clsid));
1637 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1638 if (FAILED(hr))
1640 ERR("Failed to get CLSID from a storage.\n");
1641 return hr;
1644 rclsid = &stat.clsid;
1647 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1648 if (hr != S_OK)
1649 return hr;
1651 /* Init from IStorage */
1652 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1653 if (FAILED(hr))
1654 ERR("failed to get IPersistStorage\n");
1656 if (ps)
1658 IPersistStorage_Load(ps, storage);
1659 IPersistStorage_Release(ps);
1662 return return_multi_qi(obj, count, results, FALSE);
1665 /***********************************************************************
1666 * CoCreateInstance (combase.@)
1668 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1669 REFIID riid, void **obj)
1671 MULTI_QI multi_qi = { .pIID = riid };
1672 HRESULT hr;
1674 TRACE("%s, %p, %#lx, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1676 if (!obj)
1677 return E_POINTER;
1679 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1680 *obj = multi_qi.pItf;
1681 return hr;
1684 /***********************************************************************
1685 * CoCreateInstanceFromApp (combase.@)
1687 HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1688 void *server_info, ULONG count, MULTI_QI *results)
1690 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1691 count, results);
1693 return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1694 count, results);
1697 static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1698 COSERVERINFO *server_info, REFIID riid, void **obj)
1700 struct class_reg_data clsreg = { 0 };
1701 HRESULT hr = E_UNEXPECTED;
1702 IUnknown *registered_obj;
1703 struct apartment *apt;
1705 if (!obj)
1706 return E_INVALIDARG;
1708 *obj = NULL;
1710 if (!(apt = apartment_get_current_or_mta()))
1712 ERR("apartment not initialised\n");
1713 return CO_E_NOTINITIALIZED;
1716 if (server_info)
1717 FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1719 if (clscontext & CLSCTX_INPROC_SERVER)
1721 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1722 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1723 (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1724 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1726 apartment_release(apt);
1728 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
1729 return get_builtin_class_factory(rclsid, riid, obj);
1730 else
1731 return Ole32DllGetClassObject(rclsid, riid, obj);
1735 if (clscontext & CLSCTX_INPROC)
1737 ACTCTX_SECTION_KEYED_DATA data;
1739 data.cbSize = sizeof(data);
1740 /* search activation context first */
1741 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1742 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1744 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1746 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1747 clsreg.u.actctx.hactctx = data.hActCtx;
1748 clsreg.u.actctx.threading_model = comclass->model;
1749 clsreg.origin = CLASS_REG_ACTCTX;
1751 hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1752 ReleaseActCtx(data.hActCtx);
1753 apartment_release(apt);
1754 return hr;
1759 * First, try and see if we can't match the class ID with one of the
1760 * registered classes.
1762 if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1764 hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1765 IUnknown_Release(registered_obj);
1766 apartment_release(apt);
1767 return hr;
1770 /* First try in-process server */
1771 if (clscontext & CLSCTX_INPROC_SERVER)
1773 HKEY hkey;
1775 hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1776 if (FAILED(hr))
1778 if (hr == REGDB_E_CLASSNOTREG)
1779 ERR("class %s not registered\n", debugstr_guid(rclsid));
1780 else if (hr == REGDB_E_KEYMISSING)
1782 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1783 hr = REGDB_E_CLASSNOTREG;
1787 if (SUCCEEDED(hr))
1789 clsreg.u.hkey = hkey;
1790 clsreg.origin = CLASS_REG_REGISTRY;
1792 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1793 RegCloseKey(hkey);
1796 /* return if we got a class, otherwise fall through to one of the
1797 * other types */
1798 if (SUCCEEDED(hr))
1800 apartment_release(apt);
1801 return hr;
1805 /* Next try in-process handler */
1806 if (clscontext & CLSCTX_INPROC_HANDLER)
1808 HKEY hkey;
1810 hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1811 if (FAILED(hr))
1813 if (hr == REGDB_E_CLASSNOTREG)
1814 ERR("class %s not registered\n", debugstr_guid(rclsid));
1815 else if (hr == REGDB_E_KEYMISSING)
1817 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1818 hr = REGDB_E_CLASSNOTREG;
1822 if (SUCCEEDED(hr))
1824 clsreg.u.hkey = hkey;
1825 clsreg.origin = CLASS_REG_REGISTRY;
1827 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1828 RegCloseKey(hkey);
1831 /* return if we got a class, otherwise fall through to one of the
1832 * other types */
1833 if (SUCCEEDED(hr))
1835 apartment_release(apt);
1836 return hr;
1839 apartment_release(apt);
1841 /* Next try out of process */
1842 if (clscontext & CLSCTX_LOCAL_SERVER)
1844 hr = rpc_get_local_class_object(rclsid, riid, obj);
1845 if (SUCCEEDED(hr))
1846 return hr;
1849 /* Finally try remote: this requires networked DCOM (a lot of work) */
1850 if (clscontext & CLSCTX_REMOTE_SERVER)
1852 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1853 hr = REGDB_E_CLASSNOTREG;
1856 if (FAILED(hr))
1857 ERR("no class object %s could be created for context %#lx\n", debugstr_guid(rclsid), clscontext);
1859 return hr;
1862 /***********************************************************************
1863 * CoCreateInstanceEx (combase.@)
1865 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1866 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1868 IClassFactory *factory;
1869 IUnknown *unk = NULL;
1870 CLSID clsid;
1871 HRESULT hr;
1873 TRACE("%s, %p, %#lx, %p, %lu, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1875 if (!count || !results)
1876 return E_INVALIDARG;
1878 if (server_info)
1879 FIXME("Server info is not supported.\n");
1881 init_multi_qi(count, results, E_NOINTERFACE);
1883 clsid = *rclsid;
1884 if (!(cls_context & CLSCTX_APPCONTAINER))
1885 CoGetTreatAsClass(rclsid, &clsid);
1887 if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1888 return hr;
1890 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1891 IClassFactory_Release(factory);
1892 if (FAILED(hr))
1894 if (hr == CLASS_E_NOAGGREGATION && outer)
1895 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1896 else
1897 FIXME("no instance created for interface %s of class %s, hr %#lx.\n",
1898 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1899 return hr;
1902 return return_multi_qi(unk, count, results, TRUE);
1905 /***********************************************************************
1906 * CoGetClassObject (combase.@)
1908 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1909 COSERVERINFO *server_info, REFIID riid, void **obj)
1911 TRACE("%s, %#lx, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1913 return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1916 /***********************************************************************
1917 * CoFreeUnusedLibraries (combase.@)
1919 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1921 CoFreeUnusedLibrariesEx(INFINITE, 0);
1924 /***********************************************************************
1925 * CoGetCallContext (combase.@)
1927 HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1929 struct tlsdata *tlsdata;
1930 HRESULT hr;
1932 TRACE("%s, %p\n", debugstr_guid(riid), obj);
1934 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1935 return hr;
1937 if (!tlsdata->call_state)
1938 return RPC_E_CALL_COMPLETE;
1940 return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1943 /***********************************************************************
1944 * CoSwitchCallContext (combase.@)
1946 HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1948 struct tlsdata *tlsdata;
1949 HRESULT hr;
1951 TRACE("%p, %p\n", context, old_context);
1953 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1954 return hr;
1956 /* Reference counts are not touched. */
1957 *old_context = tlsdata->call_state;
1958 tlsdata->call_state = context;
1960 return S_OK;
1963 /******************************************************************************
1964 * CoRegisterInitializeSpy (combase.@)
1966 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1968 struct tlsdata *tlsdata;
1969 struct init_spy *entry;
1970 unsigned int id;
1971 HRESULT hr;
1973 TRACE("%p, %p\n", spy, cookie);
1975 if (!spy || !cookie)
1976 return E_INVALIDARG;
1978 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1979 return hr;
1981 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1982 if (FAILED(hr))
1983 return hr;
1985 entry = malloc(sizeof(*entry));
1986 if (!entry)
1988 IInitializeSpy_Release(spy);
1989 return E_OUTOFMEMORY;
1992 entry->spy = spy;
1994 id = 0;
1995 while (get_spy_entry(tlsdata, id) != NULL)
1997 id++;
2000 entry->id = id;
2001 list_add_head(&tlsdata->spies, &entry->entry);
2003 cookie->u.HighPart = GetCurrentThreadId();
2004 cookie->u.LowPart = entry->id;
2006 return S_OK;
2009 /******************************************************************************
2010 * CoRevokeInitializeSpy (combase.@)
2012 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
2014 struct tlsdata *tlsdata;
2015 struct init_spy *spy;
2016 HRESULT hr;
2018 TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
2020 if (cookie.u.HighPart != GetCurrentThreadId())
2021 return E_INVALIDARG;
2023 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2024 return hr;
2026 if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
2028 IInitializeSpy_Release(spy->spy);
2029 spy->spy = NULL;
2030 if (!tlsdata->spies_lock)
2032 list_remove(&spy->entry);
2033 free(spy);
2035 return S_OK;
2038 static BOOL com_peek_message(struct apartment *apt, MSG *msg)
2040 /* First try to retrieve messages for incoming COM calls to the apartment window */
2041 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
2042 /* Next retrieve other messages necessary for the app to remain responsive */
2043 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
2044 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
2047 /***********************************************************************
2048 * CoWaitForMultipleHandles (combase.@)
2050 HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
2051 DWORD *index)
2053 BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
2054 DWORD start_time, wait_flags = 0;
2055 struct tlsdata *tlsdata;
2056 struct apartment *apt;
2057 UINT exit_code;
2058 HRESULT hr;
2060 TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index);
2062 if (!index)
2063 return E_INVALIDARG;
2065 *index = 0;
2067 if (!handles)
2068 return E_INVALIDARG;
2070 if (!handle_count)
2071 return RPC_E_NO_SYNC;
2073 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2074 return hr;
2076 apt = com_get_current_apt();
2077 message_loop = apt && !apt->multi_threaded;
2079 if (flags & COWAIT_WAITALL)
2080 wait_flags |= MWMO_WAITALL;
2081 if (flags & COWAIT_ALERTABLE)
2082 wait_flags |= MWMO_ALERTABLE;
2084 start_time = GetTickCount();
2086 while (TRUE)
2088 DWORD now = GetTickCount(), res;
2090 if (now - start_time > timeout)
2092 hr = RPC_S_CALLPENDING;
2093 break;
2096 if (message_loop)
2098 TRACE("waiting for rpc completion or window message\n");
2100 res = WAIT_TIMEOUT;
2102 if (check_apc)
2104 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
2105 check_apc = FALSE;
2108 if (res == WAIT_TIMEOUT)
2109 res = MsgWaitForMultipleObjectsEx(handle_count, handles,
2110 timeout == INFINITE ? INFINITE : start_time + timeout - now,
2111 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
2113 if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
2115 int msg_count = 0;
2116 MSG msg;
2118 /* call message filter */
2120 if (apt->filter)
2122 PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
2123 DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
2125 TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled);
2127 switch (be_handled)
2129 case PENDINGMSG_CANCELCALL:
2130 WARN("call canceled\n");
2131 hr = RPC_E_CALL_CANCELED;
2132 break;
2133 case PENDINGMSG_WAITNOPROCESS:
2134 case PENDINGMSG_WAITDEFPROCESS:
2135 default:
2136 /* FIXME: MSDN is very vague about the difference
2137 * between WAITNOPROCESS and WAITDEFPROCESS - there
2138 * appears to be none, so it is possibly a left-over
2139 * from the 16-bit world. */
2140 break;
2144 if (!apt->win)
2146 /* If window is NULL on apartment, peek at messages so that it will not trigger
2147 * MsgWaitForMultipleObjects next time. */
2148 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
2151 /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
2152 * so after processing 100 messages we go back to checking the wait handles */
2153 while (msg_count++ < 100 && com_peek_message(apt, &msg))
2155 if (msg.message == WM_QUIT)
2157 TRACE("Received WM_QUIT message\n");
2158 post_quit = TRUE;
2159 exit_code = msg.wParam;
2161 else
2163 TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2164 TranslateMessage(&msg);
2165 DispatchMessageW(&msg);
2168 continue;
2171 else
2173 TRACE("Waiting for rpc completion\n");
2175 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2176 (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2179 switch (res)
2181 case WAIT_TIMEOUT:
2182 hr = RPC_S_CALLPENDING;
2183 break;
2184 case WAIT_FAILED:
2185 hr = HRESULT_FROM_WIN32(GetLastError());
2186 break;
2187 default:
2188 *index = res;
2189 break;
2191 break;
2193 if (post_quit) PostQuitMessage(exit_code);
2195 TRACE("-- %#lx\n", hr);
2197 return hr;
2200 /******************************************************************************
2201 * CoRegisterMessageFilter (combase.@)
2203 HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2205 IMessageFilter *old_filter;
2206 struct apartment *apt;
2208 TRACE("%p, %p\n", filter, ret_filter);
2210 apt = com_get_current_apt();
2212 /* Can't set a message filter in a multi-threaded apartment */
2213 if (!apt || apt->multi_threaded)
2215 WARN("Can't set message filter in MTA or uninitialized apt\n");
2216 return CO_E_NOT_SUPPORTED;
2219 if (filter)
2220 IMessageFilter_AddRef(filter);
2222 EnterCriticalSection(&apt->cs);
2224 old_filter = apt->filter;
2225 apt->filter = filter;
2227 LeaveCriticalSection(&apt->cs);
2229 if (ret_filter)
2230 *ret_filter = old_filter;
2231 else if (old_filter)
2232 IMessageFilter_Release(old_filter);
2234 return S_OK;
2237 static void com_revoke_all_ps_clsids(void)
2239 struct registered_ps *cur, *cur2;
2241 EnterCriticalSection(&cs_registered_ps);
2243 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2245 list_remove(&cur->entry);
2246 free(cur);
2249 LeaveCriticalSection(&cs_registered_ps);
2252 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2254 WCHAR value[CHARS_IN_GUID];
2255 HKEY hkey;
2256 DWORD len;
2258 access |= KEY_READ;
2260 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2261 return REGDB_E_IIDNOTREG;
2263 len = sizeof(value);
2264 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2265 return REGDB_E_IIDNOTREG;
2266 RegCloseKey(hkey);
2268 if (CLSIDFromString(value, pclsid) != NOERROR)
2269 return REGDB_E_IIDNOTREG;
2271 return S_OK;
2274 /*****************************************************************************
2275 * CoGetPSClsid (combase.@)
2277 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2279 static const WCHAR interfaceW[] = L"Interface\\";
2280 static const WCHAR psW[] = L"\\ProxyStubClsid32";
2281 WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2282 ACTCTX_SECTION_KEYED_DATA data;
2283 struct registered_ps *cur;
2284 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2285 BOOL is_wow64;
2286 HRESULT hr;
2288 TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2290 if (!InternalIsProcessInitialized())
2292 ERR("apartment not initialised\n");
2293 return CO_E_NOTINITIALIZED;
2296 if (!pclsid)
2297 return E_INVALIDARG;
2299 EnterCriticalSection(&cs_registered_ps);
2301 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2303 if (IsEqualIID(&cur->iid, riid))
2305 *pclsid = cur->clsid;
2306 LeaveCriticalSection(&cs_registered_ps);
2307 return S_OK;
2311 LeaveCriticalSection(&cs_registered_ps);
2313 data.cbSize = sizeof(data);
2314 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2315 riid, &data))
2317 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2318 *pclsid = ifaceps->iid;
2319 return S_OK;
2322 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2323 lstrcpyW(path, interfaceW);
2324 StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2325 lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2327 hr = get_ps_clsid_from_registry(path, KEY_READ, pclsid);
2328 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2329 hr = get_ps_clsid_from_registry(path, opposite | KEY_READ, pclsid);
2331 if (hr == S_OK)
2332 TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2333 else
2334 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2336 return hr;
2339 /*****************************************************************************
2340 * CoRegisterPSClsid (combase.@)
2342 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2344 struct registered_ps *cur;
2346 TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2348 if (!InternalIsProcessInitialized())
2350 ERR("apartment not initialised\n");
2351 return CO_E_NOTINITIALIZED;
2354 EnterCriticalSection(&cs_registered_ps);
2356 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2358 if (IsEqualIID(&cur->iid, riid))
2360 cur->clsid = *rclsid;
2361 LeaveCriticalSection(&cs_registered_ps);
2362 return S_OK;
2366 cur = malloc(sizeof(*cur));
2367 if (!cur)
2369 LeaveCriticalSection(&cs_registered_ps);
2370 return E_OUTOFMEMORY;
2373 cur->iid = *riid;
2374 cur->clsid = *rclsid;
2375 list_add_head(&registered_proxystubs, &cur->entry);
2377 LeaveCriticalSection(&cs_registered_ps);
2379 return S_OK;
2382 struct thread_context
2384 IComThreadingInfo IComThreadingInfo_iface;
2385 IContextCallback IContextCallback_iface;
2386 IObjContext IObjContext_iface;
2387 LONG refcount;
2390 static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2392 return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2395 static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2397 return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2400 static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2402 return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2405 static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2407 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2409 *obj = NULL;
2411 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2412 IsEqualIID(riid, &IID_IUnknown))
2414 *obj = &context->IComThreadingInfo_iface;
2416 else if (IsEqualIID(riid, &IID_IContextCallback))
2418 *obj = &context->IContextCallback_iface;
2420 else if (IsEqualIID(riid, &IID_IObjContext))
2422 *obj = &context->IObjContext_iface;
2425 if (*obj)
2427 IUnknown_AddRef((IUnknown *)*obj);
2428 return S_OK;
2431 FIXME("interface not implemented %s\n", debugstr_guid(riid));
2432 return E_NOINTERFACE;
2435 static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2437 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2438 return InterlockedIncrement(&context->refcount);
2441 static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2443 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2445 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2446 releasing context while refcount is at 0 destroys it. */
2447 if (!context->refcount)
2449 free(context);
2450 return 0;
2453 return InterlockedDecrement(&context->refcount);
2456 static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2458 APTTYPEQUALIFIER qualifier;
2460 TRACE("%p\n", apttype);
2462 return CoGetApartmentType(apttype, &qualifier);
2465 static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2467 APTTYPEQUALIFIER qualifier;
2468 APTTYPE apttype;
2469 HRESULT hr;
2471 hr = CoGetApartmentType(&apttype, &qualifier);
2472 if (FAILED(hr))
2473 return hr;
2475 TRACE("%p\n", thdtype);
2477 switch (apttype)
2479 case APTTYPE_STA:
2480 case APTTYPE_MAINSTA:
2481 *thdtype = THDTYPE_PROCESSMESSAGES;
2482 break;
2483 default:
2484 *thdtype = THDTYPE_BLOCKMESSAGES;
2485 break;
2487 return S_OK;
2490 static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2492 TRACE("%p\n", logical_thread_id);
2494 return CoGetCurrentLogicalThreadId(logical_thread_id);
2497 static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2499 FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2501 return E_NOTIMPL;
2504 static const IComThreadingInfoVtbl thread_context_info_vtbl =
2506 thread_context_info_QueryInterface,
2507 thread_context_info_AddRef,
2508 thread_context_info_Release,
2509 thread_context_info_GetCurrentApartmentType,
2510 thread_context_info_GetCurrentThreadType,
2511 thread_context_info_GetCurrentLogicalThreadId,
2512 thread_context_info_SetCurrentLogicalThreadId
2515 static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2517 struct thread_context *context = impl_from_IContextCallback(iface);
2518 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2521 static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2523 struct thread_context *context = impl_from_IContextCallback(iface);
2524 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2527 static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2529 struct thread_context *context = impl_from_IContextCallback(iface);
2530 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2533 static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2534 PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2536 FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2538 return E_NOTIMPL;
2541 static const IContextCallbackVtbl thread_context_callback_vtbl =
2543 thread_context_callback_QueryInterface,
2544 thread_context_callback_AddRef,
2545 thread_context_callback_Release,
2546 thread_context_callback_ContextCallback
2549 static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2551 struct thread_context *context = impl_from_IObjContext(iface);
2552 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2555 static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2557 struct thread_context *context = impl_from_IObjContext(iface);
2558 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2561 static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2563 struct thread_context *context = impl_from_IObjContext(iface);
2564 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2567 static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2569 FIXME("%p, %s, %lx, %p\n", iface, debugstr_guid(propid), flags, punk);
2571 return E_NOTIMPL;
2574 static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2576 FIXME("%p, %s\n", iface, debugstr_guid(propid));
2578 return E_NOTIMPL;
2581 static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2583 FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2585 return E_NOTIMPL;
2588 static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2590 FIXME("%p, %p\n", iface, props);
2592 return E_NOTIMPL;
2595 static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2597 FIXME("%p\n", iface);
2600 static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2602 FIXME("%p\n", iface);
2605 static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2607 FIXME("%p\n", iface);
2610 static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2612 FIXME("%p\n", iface);
2615 static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2617 FIXME("%p\n", iface);
2620 static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2622 FIXME("%p\n", iface);
2625 static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2627 FIXME("%p\n", iface);
2630 static const IObjContextVtbl thread_object_context_vtbl =
2632 thread_object_context_QueryInterface,
2633 thread_object_context_AddRef,
2634 thread_object_context_Release,
2635 thread_object_context_SetProperty,
2636 thread_object_context_RemoveProperty,
2637 thread_object_context_GetProperty,
2638 thread_object_context_EnumContextProps,
2639 thread_object_context_Reserved1,
2640 thread_object_context_Reserved2,
2641 thread_object_context_Reserved3,
2642 thread_object_context_Reserved4,
2643 thread_object_context_Reserved5,
2644 thread_object_context_Reserved6,
2645 thread_object_context_Reserved7
2648 /***********************************************************************
2649 * CoGetContextToken (combase.@)
2651 HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2653 struct tlsdata *tlsdata;
2654 HRESULT hr;
2656 TRACE("%p\n", token);
2658 if (!InternalIsProcessInitialized())
2660 ERR("apartment not initialised\n");
2661 return CO_E_NOTINITIALIZED;
2664 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2665 return hr;
2667 if (!token)
2668 return E_POINTER;
2670 if (!tlsdata->context_token)
2672 struct thread_context *context;
2674 context = calloc(1, sizeof(*context));
2675 if (!context)
2676 return E_OUTOFMEMORY;
2678 context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2679 context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2680 context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2681 /* Context token does not take a reference, it's always zero until the
2682 interface is explicitly requested with CoGetObjectContext(). */
2683 context->refcount = 0;
2685 tlsdata->context_token = &context->IObjContext_iface;
2688 *token = (ULONG_PTR)tlsdata->context_token;
2689 TRACE("context_token %p\n", tlsdata->context_token);
2691 return S_OK;
2694 /***********************************************************************
2695 * CoGetCurrentLogicalThreadId (combase.@)
2697 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2699 struct tlsdata *tlsdata;
2700 HRESULT hr;
2702 if (!id)
2703 return E_INVALIDARG;
2705 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2706 return hr;
2708 if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2710 CoCreateGuid(&tlsdata->causality_id);
2711 tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2714 *id = tlsdata->causality_id;
2716 return S_OK;
2719 /******************************************************************************
2720 * CoGetCurrentProcess (combase.@)
2722 DWORD WINAPI CoGetCurrentProcess(void)
2724 struct tlsdata *tlsdata;
2726 if (FAILED(com_get_tlsdata(&tlsdata)))
2727 return 0;
2729 if (!tlsdata->thread_seqid)
2730 rpcss_get_next_seqid(&tlsdata->thread_seqid);
2732 return tlsdata->thread_seqid;
2735 /***********************************************************************
2736 * CoFreeUnusedLibrariesEx (combase.@)
2738 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2740 struct apartment *apt = com_get_current_apt();
2741 if (!apt)
2743 ERR("apartment not initialised\n");
2744 return;
2747 apartment_freeunusedlibraries(apt, unload_delay);
2751 * When locked, don't modify list (unless we add a new head), so that it's
2752 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
2754 static inline void lock_init_spies(struct tlsdata *tlsdata)
2756 tlsdata->spies_lock++;
2759 static void unlock_init_spies(struct tlsdata *tlsdata)
2761 struct init_spy *spy, *next;
2763 if (--tlsdata->spies_lock) return;
2765 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2767 if (spy->spy) continue;
2768 list_remove(&spy->entry);
2769 free(spy);
2773 /******************************************************************************
2774 * CoInitializeWOW (combase.@)
2776 HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2778 FIXME("%#lx, %#lx\n", arg1, arg2);
2780 return S_OK;
2783 /******************************************************************************
2784 * CoInitializeEx (combase.@)
2786 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2788 struct tlsdata *tlsdata;
2789 struct init_spy *cursor;
2790 HRESULT hr;
2792 TRACE("%p, %#lx\n", reserved, model);
2794 if (reserved)
2795 WARN("Unexpected reserved argument %p\n", reserved);
2797 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2798 return hr;
2800 if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2801 TRACE("Initializing the COM libraries\n");
2803 lock_init_spies(tlsdata);
2804 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2806 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2808 unlock_init_spies(tlsdata);
2810 hr = enter_apartment(tlsdata, model);
2812 lock_init_spies(tlsdata);
2813 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2815 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2817 unlock_init_spies(tlsdata);
2819 return hr;
2822 /***********************************************************************
2823 * CoUninitialize (combase.@)
2825 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2827 struct tlsdata *tlsdata;
2828 struct init_spy *cursor, *next;
2829 LONG lockcount;
2831 TRACE("\n");
2833 if (FAILED(com_get_tlsdata(&tlsdata)))
2834 return;
2836 lock_init_spies(tlsdata);
2837 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2839 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2841 unlock_init_spies(tlsdata);
2843 /* sanity check */
2844 if (!tlsdata->inits)
2846 ERR("Mismatched CoUninitialize\n");
2848 lock_init_spies(tlsdata);
2849 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2851 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2853 unlock_init_spies(tlsdata);
2855 return;
2858 leave_apartment(tlsdata);
2861 * Decrease the reference count.
2862 * If we are back to 0 locks on the COM library, make sure we free
2863 * all the associated data structures.
2865 lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2866 if (lockcount == 1)
2868 TRACE("Releasing the COM libraries\n");
2870 com_revoke_all_ps_clsids();
2871 DestroyRunningObjectTable();
2873 else if (lockcount < 1)
2875 ERR("Unbalanced lock count %ld\n", lockcount);
2876 InterlockedExchangeAdd(&com_lockcount, 1);
2879 lock_init_spies(tlsdata);
2880 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2882 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2884 unlock_init_spies(tlsdata);
2887 /***********************************************************************
2888 * CoIncrementMTAUsage (combase.@)
2890 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2892 TRACE("%p\n", cookie);
2894 return apartment_increment_mta_usage(cookie);
2897 /***********************************************************************
2898 * CoDecrementMTAUsage (combase.@)
2900 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2902 TRACE("%p\n", cookie);
2904 apartment_decrement_mta_usage(cookie);
2905 return S_OK;
2908 /***********************************************************************
2909 * CoGetApartmentType (combase.@)
2911 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2913 struct tlsdata *tlsdata;
2914 struct apartment *apt;
2915 HRESULT hr;
2917 TRACE("%p, %p\n", type, qualifier);
2919 if (!type || !qualifier)
2920 return E_INVALIDARG;
2922 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2923 return hr;
2925 if (!tlsdata->apt)
2926 *type = APTTYPE_CURRENT;
2927 else if (tlsdata->apt->multi_threaded)
2928 *type = APTTYPE_MTA;
2929 else if (tlsdata->apt->main)
2930 *type = APTTYPE_MAINSTA;
2931 else
2932 *type = APTTYPE_STA;
2934 *qualifier = APTTYPEQUALIFIER_NONE;
2936 if (!tlsdata->apt && (apt = apartment_get_mta()))
2938 apartment_release(apt);
2939 *type = APTTYPE_MTA;
2940 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2941 return S_OK;
2944 return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2947 /******************************************************************************
2948 * CoRegisterClassObject (combase.@)
2949 * BUGS
2950 * MSDN claims that multiple interface registrations are legal, but we
2951 * can't do that with our current implementation.
2953 HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2954 DWORD flags, DWORD *cookie)
2956 static LONG next_cookie;
2958 struct registered_class *newclass;
2959 IUnknown *found_object;
2960 struct apartment *apt;
2961 HRESULT hr = S_OK;
2963 TRACE("%s, %p, %#lx, %#lx, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2965 if (!cookie || !object)
2966 return E_INVALIDARG;
2968 if (!(apt = apartment_get_current_or_mta()))
2970 ERR("COM was not initialized\n");
2971 return CO_E_NOTINITIALIZED;
2974 *cookie = 0;
2976 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2977 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2978 if (flags & REGCLS_MULTIPLEUSE)
2979 clscontext |= CLSCTX_INPROC_SERVER;
2982 * First, check if the class is already registered.
2983 * If it is, this should cause an error.
2985 if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2987 if (flags & REGCLS_MULTIPLEUSE)
2989 if (clscontext & CLSCTX_LOCAL_SERVER)
2990 hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2991 IUnknown_Release(found_object);
2992 apartment_release(apt);
2993 return hr;
2996 IUnknown_Release(found_object);
2997 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2998 apartment_release(apt);
2999 return CO_E_OBJISREG;
3002 newclass = calloc(1, sizeof(*newclass));
3003 if (!newclass)
3005 apartment_release(apt);
3006 return E_OUTOFMEMORY;
3009 newclass->clsid = *rclsid;
3010 newclass->apartment_id = apt->oxid;
3011 newclass->clscontext = clscontext;
3012 newclass->flags = flags;
3014 if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
3015 newclass->cookie = InterlockedIncrement(&next_cookie);
3017 newclass->object = object;
3018 IUnknown_AddRef(newclass->object);
3020 EnterCriticalSection(&registered_classes_cs);
3021 list_add_tail(&registered_classes, &newclass->entry);
3022 LeaveCriticalSection(&registered_classes_cs);
3024 *cookie = newclass->cookie;
3026 if (clscontext & CLSCTX_LOCAL_SERVER)
3028 IStream *marshal_stream;
3030 hr = apartment_get_local_server_stream(apt, &marshal_stream);
3031 if(FAILED(hr))
3033 apartment_release(apt);
3034 return hr;
3037 hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
3038 IStream_Release(marshal_stream);
3041 apartment_release(apt);
3042 return S_OK;
3045 static void com_revoke_class_object(struct registered_class *entry)
3047 list_remove(&entry->entry);
3049 if (entry->clscontext & CLSCTX_LOCAL_SERVER)
3050 rpc_revoke_local_server(entry->rpcss_cookie);
3052 IUnknown_Release(entry->object);
3053 free(entry);
3056 /* Cleans up rpcss registry */
3057 static void com_revoke_local_servers(void)
3059 struct registered_class *cur, *cur2;
3061 EnterCriticalSection(&registered_classes_cs);
3063 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3065 if (cur->clscontext & CLSCTX_LOCAL_SERVER)
3066 com_revoke_class_object(cur);
3069 LeaveCriticalSection(&registered_classes_cs);
3072 void apartment_revoke_all_classes(const struct apartment *apt)
3074 struct registered_class *cur, *cur2;
3076 EnterCriticalSection(&registered_classes_cs);
3078 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
3080 if (cur->apartment_id == apt->oxid)
3081 com_revoke_class_object(cur);
3084 LeaveCriticalSection(&registered_classes_cs);
3087 /***********************************************************************
3088 * CoRevokeClassObject (combase.@)
3090 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
3092 HRESULT hr = E_INVALIDARG;
3093 struct registered_class *cur;
3094 struct apartment *apt;
3096 TRACE("%#lx\n", cookie);
3098 if (!(apt = apartment_get_current_or_mta()))
3100 ERR("COM was not initialized\n");
3101 return CO_E_NOTINITIALIZED;
3104 EnterCriticalSection(&registered_classes_cs);
3106 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
3108 if (cur->cookie != cookie)
3109 continue;
3111 if (cur->apartment_id == apt->oxid)
3113 com_revoke_class_object(cur);
3114 hr = S_OK;
3116 else
3118 ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
3119 hr = RPC_E_WRONG_THREAD;
3122 break;
3125 LeaveCriticalSection(&registered_classes_cs);
3126 apartment_release(apt);
3128 return hr;
3131 /***********************************************************************
3132 * CoAddRefServerProcess (combase.@)
3134 ULONG WINAPI CoAddRefServerProcess(void)
3136 ULONG refs;
3138 TRACE("\n");
3140 EnterCriticalSection(&registered_classes_cs);
3141 refs = ++com_server_process_refcount;
3142 LeaveCriticalSection(&registered_classes_cs);
3144 TRACE("refs before: %ld\n", refs - 1);
3146 return refs;
3149 /***********************************************************************
3150 * CoReleaseServerProcess [OLE32.@]
3152 ULONG WINAPI CoReleaseServerProcess(void)
3154 ULONG refs;
3156 TRACE("\n");
3158 EnterCriticalSection(&registered_classes_cs);
3160 refs = --com_server_process_refcount;
3161 /* FIXME: suspend objects */
3163 LeaveCriticalSection(&registered_classes_cs);
3165 TRACE("refs after: %ld\n", refs);
3167 return refs;
3170 /******************************************************************************
3171 * CoDisconnectObject (combase.@)
3173 HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3175 struct stub_manager *manager;
3176 struct apartment *apt;
3177 IMarshal *marshal;
3178 HRESULT hr;
3180 TRACE("%p, %#lx\n", object, reserved);
3182 if (!object)
3183 return E_INVALIDARG;
3185 hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3186 if (hr == S_OK)
3188 hr = IMarshal_DisconnectObject(marshal, reserved);
3189 IMarshal_Release(marshal);
3190 return hr;
3193 if (!(apt = apartment_get_current_or_mta()))
3195 ERR("apartment not initialised\n");
3196 return CO_E_NOTINITIALIZED;
3199 manager = get_stub_manager_from_object(apt, object, FALSE);
3200 if (manager)
3202 stub_manager_disconnect(manager);
3203 /* Release stub manager twice, to remove the apartment reference. */
3204 stub_manager_int_release(manager);
3205 stub_manager_int_release(manager);
3208 /* Note: native is pretty broken here because it just silently
3209 * fails, without returning an appropriate error code if the object was
3210 * not found, making apps think that the object was disconnected, when
3211 * it actually wasn't */
3213 apartment_release(apt);
3214 return S_OK;
3217 /******************************************************************************
3218 * CoLockObjectExternal (combase.@)
3220 HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3222 struct stub_manager *stubmgr;
3223 struct apartment *apt;
3225 TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3227 if (!(apt = apartment_get_current_or_mta()))
3229 ERR("apartment not initialised\n");
3230 return CO_E_NOTINITIALIZED;
3233 stubmgr = get_stub_manager_from_object(apt, object, lock);
3234 if (!stubmgr)
3236 WARN("stub object not found %p\n", object);
3237 /* Note: native is pretty broken here because it just silently
3238 * fails, without returning an appropriate error code, making apps
3239 * think that the object was disconnected, when it actually wasn't */
3240 apartment_release(apt);
3241 return S_OK;
3244 if (lock)
3245 stub_manager_ext_addref(stubmgr, 1, FALSE);
3246 else
3247 stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3249 stub_manager_int_release(stubmgr);
3250 apartment_release(apt);
3251 return S_OK;
3254 /***********************************************************************
3255 * CoRegisterChannelHook (combase.@)
3257 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3259 TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3261 return rpc_register_channel_hook(guidExtension, channel_hook);
3264 /***********************************************************************
3265 * CoDisableCallCancellation (combase.@)
3267 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3269 struct tlsdata *tlsdata;
3270 HRESULT hr;
3272 TRACE("%p\n", reserved);
3274 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3275 return hr;
3277 if (!tlsdata->cancelcount)
3278 return CO_E_CANCEL_DISABLED;
3280 tlsdata->cancelcount--;
3282 return S_OK;
3285 /***********************************************************************
3286 * CoEnableCallCancellation (combase.@)
3288 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3290 struct tlsdata *tlsdata;
3291 HRESULT hr;
3293 TRACE("%p\n", reserved);
3295 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3296 return hr;
3298 tlsdata->cancelcount++;
3300 return S_OK;
3303 /***********************************************************************
3304 * CoGetCallerTID (combase.@)
3306 HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3308 FIXME("stub!\n");
3309 return E_NOTIMPL;
3312 /***********************************************************************
3313 * CoIsHandlerConnected (combase.@)
3315 BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3317 FIXME("%p\n", object);
3319 return TRUE;
3322 /***********************************************************************
3323 * CoSuspendClassObjects (combase.@)
3325 HRESULT WINAPI CoSuspendClassObjects(void)
3327 FIXME("\n");
3329 return S_OK;
3332 /***********************************************************************
3333 * CoResumeClassObjects (combase.@)
3335 HRESULT WINAPI CoResumeClassObjects(void)
3337 FIXME("stub\n");
3339 return S_OK;
3342 /***********************************************************************
3343 * CoRegisterSurrogate (combase.@)
3345 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3347 FIXME("%p stub\n", surrogate);
3349 return E_NOTIMPL;
3352 /***********************************************************************
3353 * CoRegisterSurrogateEx (combase.@)
3355 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3357 FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3359 return E_NOTIMPL;
3362 /***********************************************************************
3363 * DllMain (combase.@)
3365 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3367 TRACE("%p, %#lx, %p\n", hinstDLL, reason, reserved);
3369 switch (reason)
3371 case DLL_PROCESS_ATTACH:
3372 hProxyDll = hinstDLL;
3373 break;
3374 case DLL_PROCESS_DETACH:
3375 com_revoke_local_servers();
3376 if (reserved) break;
3377 apartment_global_cleanup();
3378 DeleteCriticalSection(&registered_classes_cs);
3379 rpc_unregister_channel_hooks();
3380 break;
3381 case DLL_THREAD_DETACH:
3382 com_cleanup_tlsdata();
3383 break;
3386 return TRUE;
3389 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj)
3391 TRACE("%s, %s, %p.\n", debugstr_guid(rclsid), debugstr_guid(riid), obj);
3393 *obj = NULL;
3395 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3396 return IClassFactory_QueryInterface(&global_options_factory, riid, obj);
3398 return CLASS_E_CLASSNOTAVAILABLE;