dcomp: Add DCompositionCreateDevice() stub.
[wine.git] / dlls / combase / combase.c
blob72ff6cc31f971bab29c8afa9a0f6c82704990e67
1 /*
2 * Copyright 2005 Juan Lang
3 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define COBJMACROS
21 #define NONAMELESSUNION
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #define USE_COM_CONTEXT_DEF
26 #include "objbase.h"
27 #include "ctxtcall.h"
28 #include "oleauto.h"
29 #include "dde.h"
30 #include "winternl.h"
32 #include "combase_private.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 HINSTANCE hProxyDll;
41 /* Ole32 exports */
42 extern void WINAPI DestroyRunningObjectTable(void);
43 extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
46 * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
48 static LONG com_lockcount;
50 static LONG com_server_process_refcount;
52 struct comclassredirect_data
54 ULONG size;
55 ULONG flags;
56 DWORD model;
57 GUID clsid;
58 GUID alias;
59 GUID clsid2;
60 GUID tlbid;
61 ULONG name_len;
62 ULONG name_offset;
63 ULONG progid_len;
64 ULONG progid_offset;
65 ULONG clrdata_len;
66 ULONG clrdata_offset;
67 DWORD miscstatus;
68 DWORD miscstatuscontent;
69 DWORD miscstatusthumbnail;
70 DWORD miscstatusicon;
71 DWORD miscstatusdocprint;
74 struct ifacepsredirect_data
76 ULONG size;
77 DWORD mask;
78 GUID iid;
79 ULONG nummethods;
80 GUID tlbid;
81 GUID base;
82 ULONG name_len;
83 ULONG name_offset;
86 struct progidredirect_data
88 ULONG size;
89 DWORD reserved;
90 ULONG clsid_offset;
93 struct init_spy
95 struct list entry;
96 IInitializeSpy *spy;
97 unsigned int id;
100 struct registered_ps
102 struct list entry;
103 IID iid;
104 CLSID clsid;
107 static struct list registered_proxystubs = LIST_INIT(registered_proxystubs);
109 static CRITICAL_SECTION cs_registered_ps;
110 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
112 0, 0, &cs_registered_ps,
113 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
114 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
116 static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
118 struct registered_class
120 struct list entry;
121 CLSID clsid;
122 OXID apartment_id;
123 IUnknown *object;
124 DWORD clscontext;
125 DWORD flags;
126 unsigned int cookie;
127 unsigned int rpcss_cookie;
130 static struct list registered_classes = LIST_INIT(registered_classes);
132 static CRITICAL_SECTION registered_classes_cs;
133 static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
135 0, 0, &registered_classes_cs,
136 { &registered_classes_cs_debug.ProcessLocksList, &registered_classes_cs_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") }
139 static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
141 IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
143 struct registered_class *cur;
144 IUnknown *object = NULL;
146 EnterCriticalSection(&registered_classes_cs);
148 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
150 if ((apt->oxid == cur->apartment_id) &&
151 (clscontext & cur->clscontext) &&
152 IsEqualGUID(&cur->clsid, rclsid))
154 object = cur->object;
155 IUnknown_AddRef(cur->object);
156 break;
160 LeaveCriticalSection(&registered_classes_cs);
162 return object;
165 static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
167 struct init_spy *spy;
169 LIST_FOR_EACH_ENTRY(spy, &tlsdata->spies, struct init_spy, entry)
171 if (id == spy->id && spy->spy)
172 return spy;
175 return NULL;
178 static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
180 NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
182 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
184 HANDLE subkey, root = attr->RootDirectory;
185 WCHAR *buffer = attr->ObjectName->Buffer;
186 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
187 UNICODE_STRING str;
189 while (i < len && buffer[i] != '\\') i++;
190 if (i == len) return status;
192 attrs = attr->Attributes;
193 attr->ObjectName = &str;
195 while (i < len)
197 str.Buffer = buffer + pos;
198 str.Length = (i - pos) * sizeof(WCHAR);
199 status = NtCreateKey(&subkey, access, attr, 0, NULL, 0, NULL);
200 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
201 if (status) return status;
202 attr->RootDirectory = subkey;
203 while (i < len && buffer[i] == '\\') i++;
204 pos = i;
205 while (i < len && buffer[i] != '\\') i++;
207 str.Buffer = buffer + pos;
208 str.Length = (i - pos) * sizeof(WCHAR);
209 attr->Attributes = attrs;
210 status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
211 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
213 return status;
216 static HKEY classes_root_hkey;
218 static HKEY create_classes_root_hkey(DWORD access)
220 HKEY hkey, ret = 0;
221 OBJECT_ATTRIBUTES attr;
222 UNICODE_STRING name;
224 attr.Length = sizeof(attr);
225 attr.RootDirectory = 0;
226 attr.ObjectName = &name;
227 attr.Attributes = 0;
228 attr.SecurityDescriptor = NULL;
229 attr.SecurityQualityOfService = NULL;
230 RtlInitUnicodeString(&name, L"\\Registry\\Machine\\Software\\Classes");
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, keyname ? KEY_READ : 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, KEY_READ, &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 = heap_alloc_zero(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 heap_free(cursor);
425 if (tlsdata->context_token)
426 IObjContext_Release(tlsdata->context_token);
428 heap_free(tlsdata);
429 NtCurrentTeb()->ReservedForOle = NULL;
432 /***********************************************************************
433 * FreePropVariantArray (combase.@)
435 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
437 ULONG i;
439 TRACE("%u, %p.\n", count, rgvars);
441 if (!rgvars)
442 return E_INVALIDARG;
444 for (i = 0; i < count; ++i)
445 PropVariantClear(&rgvars[i]);
447 return S_OK;
450 static HRESULT propvar_validatetype(VARTYPE vt)
452 switch (vt)
454 case VT_EMPTY:
455 case VT_NULL:
456 case VT_I1:
457 case VT_I2:
458 case VT_I4:
459 case VT_I8:
460 case VT_R4:
461 case VT_R8:
462 case VT_CY:
463 case VT_DATE:
464 case VT_BSTR:
465 case VT_ERROR:
466 case VT_BOOL:
467 case VT_DECIMAL:
468 case VT_UI1:
469 case VT_UI2:
470 case VT_UI4:
471 case VT_UI8:
472 case VT_INT:
473 case VT_UINT:
474 case VT_LPSTR:
475 case VT_LPWSTR:
476 case VT_FILETIME:
477 case VT_BLOB:
478 case VT_DISPATCH:
479 case VT_UNKNOWN:
480 case VT_STREAM:
481 case VT_STORAGE:
482 case VT_STREAMED_OBJECT:
483 case VT_STORED_OBJECT:
484 case VT_BLOB_OBJECT:
485 case VT_CF:
486 case VT_CLSID:
487 case VT_I1|VT_VECTOR:
488 case VT_I2|VT_VECTOR:
489 case VT_I4|VT_VECTOR:
490 case VT_I8|VT_VECTOR:
491 case VT_R4|VT_VECTOR:
492 case VT_R8|VT_VECTOR:
493 case VT_CY|VT_VECTOR:
494 case VT_DATE|VT_VECTOR:
495 case VT_BSTR|VT_VECTOR:
496 case VT_ERROR|VT_VECTOR:
497 case VT_BOOL|VT_VECTOR:
498 case VT_VARIANT|VT_VECTOR:
499 case VT_UI1|VT_VECTOR:
500 case VT_UI2|VT_VECTOR:
501 case VT_UI4|VT_VECTOR:
502 case VT_UI8|VT_VECTOR:
503 case VT_LPSTR|VT_VECTOR:
504 case VT_LPWSTR|VT_VECTOR:
505 case VT_FILETIME|VT_VECTOR:
506 case VT_CF|VT_VECTOR:
507 case VT_CLSID|VT_VECTOR:
508 case VT_ARRAY|VT_I1:
509 case VT_ARRAY|VT_UI1:
510 case VT_ARRAY|VT_I2:
511 case VT_ARRAY|VT_UI2:
512 case VT_ARRAY|VT_I4:
513 case VT_ARRAY|VT_UI4:
514 case VT_ARRAY|VT_INT:
515 case VT_ARRAY|VT_UINT:
516 case VT_ARRAY|VT_R4:
517 case VT_ARRAY|VT_R8:
518 case VT_ARRAY|VT_CY:
519 case VT_ARRAY|VT_DATE:
520 case VT_ARRAY|VT_BSTR:
521 case VT_ARRAY|VT_BOOL:
522 case VT_ARRAY|VT_DECIMAL:
523 case VT_ARRAY|VT_DISPATCH:
524 case VT_ARRAY|VT_UNKNOWN:
525 case VT_ARRAY|VT_ERROR:
526 case VT_ARRAY|VT_VARIANT:
527 return S_OK;
529 WARN("Bad type %d\n", vt);
530 return STG_E_INVALIDPARAMETER;
533 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
535 ULONG i;
536 for (i = 0; i < count; ++i)
537 CoTaskMemFree(data[i].pClipData);
540 /***********************************************************************
541 * PropVariantClear (combase.@)
543 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
545 HRESULT hr;
547 TRACE("%p.\n", pvar);
549 if (!pvar)
550 return S_OK;
552 hr = propvar_validatetype(pvar->vt);
553 if (FAILED(hr))
555 memset(pvar, 0, sizeof(*pvar));
556 return hr;
559 switch (pvar->vt)
561 case VT_EMPTY:
562 case VT_NULL:
563 case VT_I1:
564 case VT_I2:
565 case VT_I4:
566 case VT_I8:
567 case VT_R4:
568 case VT_R8:
569 case VT_CY:
570 case VT_DATE:
571 case VT_ERROR:
572 case VT_BOOL:
573 case VT_DECIMAL:
574 case VT_UI1:
575 case VT_UI2:
576 case VT_UI4:
577 case VT_UI8:
578 case VT_INT:
579 case VT_UINT:
580 case VT_FILETIME:
581 break;
582 case VT_DISPATCH:
583 case VT_UNKNOWN:
584 case VT_STREAM:
585 case VT_STREAMED_OBJECT:
586 case VT_STORAGE:
587 case VT_STORED_OBJECT:
588 if (pvar->u.pStream)
589 IStream_Release(pvar->u.pStream);
590 break;
591 case VT_CLSID:
592 case VT_LPSTR:
593 case VT_LPWSTR:
594 /* pick an arbitrary typed pointer - we don't care about the type
595 * as we are just freeing it */
596 CoTaskMemFree(pvar->u.puuid);
597 break;
598 case VT_BLOB:
599 case VT_BLOB_OBJECT:
600 CoTaskMemFree(pvar->u.blob.pBlobData);
601 break;
602 case VT_BSTR:
603 SysFreeString(pvar->u.bstrVal);
604 break;
605 case VT_CF:
606 if (pvar->u.pclipdata)
608 propvar_free_cf_array(1, pvar->u.pclipdata);
609 CoTaskMemFree(pvar->u.pclipdata);
611 break;
612 default:
613 if (pvar->vt & VT_VECTOR)
615 ULONG i;
617 switch (pvar->vt & ~VT_VECTOR)
619 case VT_VARIANT:
620 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
621 break;
622 case VT_CF:
623 propvar_free_cf_array(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
624 break;
625 case VT_BSTR:
626 for (i = 0; i < pvar->u.cabstr.cElems; i++)
627 SysFreeString(pvar->u.cabstr.pElems[i]);
628 break;
629 case VT_LPSTR:
630 for (i = 0; i < pvar->u.calpstr.cElems; i++)
631 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
632 break;
633 case VT_LPWSTR:
634 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
635 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
636 break;
638 if (pvar->vt & ~VT_VECTOR)
640 /* pick an arbitrary VT_VECTOR structure - they all have the same
641 * memory layout */
642 CoTaskMemFree(pvar->u.capropvar.pElems);
645 else if (pvar->vt & VT_ARRAY)
646 hr = SafeArrayDestroy(pvar->u.parray);
647 else
649 WARN("Invalid/unsupported type %d\n", pvar->vt);
650 hr = STG_E_INVALIDPARAMETER;
654 memset(pvar, 0, sizeof(*pvar));
655 return hr;
658 /***********************************************************************
659 * PropVariantCopy (combase.@)
661 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
663 ULONG len;
664 HRESULT hr;
666 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
668 hr = propvar_validatetype(pvarSrc->vt);
669 if (FAILED(hr))
670 return DISP_E_BADVARTYPE;
672 /* this will deal with most cases */
673 *pvarDest = *pvarSrc;
675 switch (pvarSrc->vt)
677 case VT_EMPTY:
678 case VT_NULL:
679 case VT_I1:
680 case VT_UI1:
681 case VT_I2:
682 case VT_UI2:
683 case VT_BOOL:
684 case VT_DECIMAL:
685 case VT_I4:
686 case VT_UI4:
687 case VT_R4:
688 case VT_ERROR:
689 case VT_I8:
690 case VT_UI8:
691 case VT_INT:
692 case VT_UINT:
693 case VT_R8:
694 case VT_CY:
695 case VT_DATE:
696 case VT_FILETIME:
697 break;
698 case VT_DISPATCH:
699 case VT_UNKNOWN:
700 case VT_STREAM:
701 case VT_STREAMED_OBJECT:
702 case VT_STORAGE:
703 case VT_STORED_OBJECT:
704 if (pvarDest->u.pStream)
705 IStream_AddRef(pvarDest->u.pStream);
706 break;
707 case VT_CLSID:
708 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
709 *pvarDest->u.puuid = *pvarSrc->u.puuid;
710 break;
711 case VT_LPSTR:
712 if (pvarSrc->u.pszVal)
714 len = strlen(pvarSrc->u.pszVal);
715 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
716 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
718 break;
719 case VT_LPWSTR:
720 if (pvarSrc->u.pwszVal)
722 len = lstrlenW(pvarSrc->u.pwszVal);
723 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
724 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
726 break;
727 case VT_BLOB:
728 case VT_BLOB_OBJECT:
729 if (pvarSrc->u.blob.pBlobData)
731 len = pvarSrc->u.blob.cbSize;
732 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
733 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
735 break;
736 case VT_BSTR:
737 pvarDest->u.bstrVal = SysAllocString(pvarSrc->u.bstrVal);
738 break;
739 case VT_CF:
740 if (pvarSrc->u.pclipdata)
742 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
743 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
744 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
745 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
746 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
747 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
749 break;
750 default:
751 if (pvarSrc->vt & VT_VECTOR)
753 int elemSize;
754 ULONG i;
756 switch (pvarSrc->vt & ~VT_VECTOR)
758 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
759 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
760 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
761 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
762 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
763 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
764 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
765 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
766 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
767 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
768 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
769 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
770 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
771 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
772 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
773 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
774 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
775 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
776 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
777 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
778 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
780 default:
781 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
782 return E_INVALIDARG;
784 len = pvarSrc->u.capropvar.cElems;
785 pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
786 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
788 for (i = 0; i < len; i++)
789 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
791 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
793 FIXME("Copy clipformats\n");
795 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
797 for (i = 0; i < len; i++)
798 pvarDest->u.cabstr.pElems[i] = SysAllocString(pvarSrc->u.cabstr.pElems[i]);
800 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
802 size_t strLen;
803 for (i = 0; i < len; i++)
805 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
806 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
807 memcpy(pvarDest->u.calpstr.pElems[i],
808 pvarSrc->u.calpstr.pElems[i], strLen);
811 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
813 size_t strLen;
814 for (i = 0; i < len; i++)
816 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
817 sizeof(WCHAR);
818 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
819 memcpy(pvarDest->u.calpstr.pElems[i],
820 pvarSrc->u.calpstr.pElems[i], strLen);
823 else
824 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
826 else if (pvarSrc->vt & VT_ARRAY)
828 pvarDest->u.uhVal.QuadPart = 0;
829 return SafeArrayCopy(pvarSrc->u.parray, &pvarDest->u.parray);
831 else
832 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
835 return S_OK;
838 /***********************************************************************
839 * CoFileTimeNow (combase.@)
841 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
843 GetSystemTimeAsFileTime(filetime);
844 return S_OK;
847 /******************************************************************************
848 * CoCreateGuid (combase.@)
850 HRESULT WINAPI CoCreateGuid(GUID *guid)
852 RPC_STATUS status;
854 if (!guid) return E_INVALIDARG;
856 status = UuidCreate(guid);
857 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
858 return HRESULT_FROM_WIN32(status);
861 /******************************************************************************
862 * CoQueryProxyBlanket (combase.@)
864 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
865 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
866 DWORD *imp_level, void **auth_info, DWORD *capabilities)
868 IClientSecurity *client_security;
869 HRESULT hr;
871 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
872 auth_info, capabilities);
874 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
875 if (SUCCEEDED(hr))
877 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
878 authn_level, imp_level, auth_info, capabilities);
879 IClientSecurity_Release(client_security);
882 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
883 return hr;
886 /******************************************************************************
887 * CoSetProxyBlanket (combase.@)
889 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
890 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
892 IClientSecurity *client_security;
893 HRESULT hr;
895 TRACE("%p, %u, %u, %p, %u, %u, %p, %#x.\n", proxy, authn_service, authz_service, servername,
896 authn_level, imp_level, auth_info, capabilities);
898 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
899 if (SUCCEEDED(hr))
901 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
902 imp_level, auth_info, capabilities);
903 IClientSecurity_Release(client_security);
906 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
907 return hr;
910 /***********************************************************************
911 * CoCopyProxy (combase.@)
913 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
915 IClientSecurity *client_security;
916 HRESULT hr;
918 TRACE("%p, %p.\n", proxy, proxy_copy);
920 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
921 if (SUCCEEDED(hr))
923 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
924 IClientSecurity_Release(client_security);
927 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
928 return hr;
931 /***********************************************************************
932 * CoQueryClientBlanket (combase.@)
934 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
935 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
937 IServerSecurity *server_security;
938 HRESULT hr;
940 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
941 privs, capabilities);
943 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
944 if (SUCCEEDED(hr))
946 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
947 imp_level, privs, capabilities);
948 IServerSecurity_Release(server_security);
951 return hr;
954 /***********************************************************************
955 * CoImpersonateClient (combase.@)
957 HRESULT WINAPI CoImpersonateClient(void)
959 IServerSecurity *server_security;
960 HRESULT hr;
962 TRACE("\n");
964 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
965 if (SUCCEEDED(hr))
967 hr = IServerSecurity_ImpersonateClient(server_security);
968 IServerSecurity_Release(server_security);
971 return hr;
974 /***********************************************************************
975 * CoRevertToSelf (combase.@)
977 HRESULT WINAPI CoRevertToSelf(void)
979 IServerSecurity *server_security;
980 HRESULT hr;
982 TRACE("\n");
984 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
985 if (SUCCEEDED(hr))
987 hr = IServerSecurity_RevertToSelf(server_security);
988 IServerSecurity_Release(server_security);
991 return hr;
994 /***********************************************************************
995 * CoInitializeSecurity (combase.@)
997 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR sd, LONG cAuthSvc,
998 SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *reserved1, DWORD authn_level,
999 DWORD imp_level, void *reserved2, DWORD capabilities, void *reserved3)
1001 FIXME("%p, %d, %p, %p, %d, %d, %p, %d, %p stub\n", sd, cAuthSvc, asAuthSvc, reserved1, authn_level,
1002 imp_level, reserved2, capabilities, reserved3);
1004 return S_OK;
1007 /***********************************************************************
1008 * CoGetObjectContext (combase.@)
1010 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
1012 IObjContext *context;
1013 HRESULT hr;
1015 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
1017 *ppv = NULL;
1018 hr = CoGetContextToken((ULONG_PTR *)&context);
1019 if (FAILED(hr))
1020 return hr;
1022 return IObjContext_QueryInterface(context, riid, ppv);
1025 /***********************************************************************
1026 * CoGetDefaultContext (combase.@)
1028 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
1030 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
1032 return E_NOINTERFACE;
1035 /***********************************************************************
1036 * CoGetCallState (combase.@)
1038 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
1040 FIXME("%d, %p.\n", arg1, arg2);
1042 return E_NOTIMPL;
1045 /***********************************************************************
1046 * CoGetActivationState (combase.@)
1048 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
1050 FIXME("%s, %x, %p.\n", debugstr_guid(&guid), arg2, arg3);
1052 return E_NOTIMPL;
1055 /******************************************************************************
1056 * CoGetTreatAsClass (combase.@)
1058 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
1060 WCHAR buffW[CHARS_IN_GUID];
1061 LONG len = sizeof(buffW);
1062 HRESULT hr = S_OK;
1063 HKEY hkey = NULL;
1065 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
1067 if (!clsidOld || !clsidNew)
1068 return E_INVALIDARG;
1070 *clsidNew = *clsidOld;
1072 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
1073 if (FAILED(hr))
1075 hr = S_FALSE;
1076 goto done;
1079 if (RegQueryValueW(hkey, NULL, buffW, &len))
1081 hr = S_FALSE;
1082 goto done;
1085 hr = CLSIDFromString(buffW, clsidNew);
1086 if (FAILED(hr))
1087 ERR("Failed to get CLSID from string %s, hr %#x.\n", debugstr_w(buffW), hr);
1088 done:
1089 if (hkey) RegCloseKey(hkey);
1090 return hr;
1093 /******************************************************************************
1094 * ProgIDFromCLSID (combase.@)
1096 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
1098 ACTCTX_SECTION_KEYED_DATA data;
1099 LONG progidlen = 0;
1100 HKEY hkey;
1101 HRESULT hr;
1103 if (!progid)
1104 return E_INVALIDARG;
1106 *progid = NULL;
1108 data.cbSize = sizeof(data);
1109 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
1110 clsid, &data))
1112 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1113 if (comclass->progid_len)
1115 WCHAR *ptrW;
1117 *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
1118 if (!*progid) return E_OUTOFMEMORY;
1120 ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
1121 memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
1122 return S_OK;
1124 else
1125 return REGDB_E_CLASSNOTREG;
1128 hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
1129 if (FAILED(hr))
1130 return hr;
1132 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1133 hr = REGDB_E_CLASSNOTREG;
1135 if (hr == S_OK)
1137 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1138 if (*progid)
1140 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
1142 hr = REGDB_E_CLASSNOTREG;
1143 CoTaskMemFree(*progid);
1144 *progid = NULL;
1147 else
1148 hr = E_OUTOFMEMORY;
1151 RegCloseKey(hkey);
1152 return hr;
1155 static inline BOOL is_valid_hex(WCHAR c)
1157 if (!(((c >= '0') && (c <= '9')) ||
1158 ((c >= 'a') && (c <= 'f')) ||
1159 ((c >= 'A') && (c <= 'F'))))
1160 return FALSE;
1161 return TRUE;
1164 static const BYTE guid_conv_table[256] =
1166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
1167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
1168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1169 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
1170 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1172 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
1175 static BOOL guid_from_string(LPCWSTR s, GUID *id)
1177 int i;
1179 if (!s || s[0] != '{')
1181 memset(id, 0, sizeof(*id));
1182 if (!s) return TRUE;
1183 return FALSE;
1186 TRACE("%s -> %p\n", debugstr_w(s), id);
1188 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1190 id->Data1 = 0;
1191 for (i = 1; i < 9; ++i)
1193 if (!is_valid_hex(s[i])) return FALSE;
1194 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
1196 if (s[9] != '-') return FALSE;
1198 id->Data2 = 0;
1199 for (i = 10; i < 14; ++i)
1201 if (!is_valid_hex(s[i])) return FALSE;
1202 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
1204 if (s[14] != '-') return FALSE;
1206 id->Data3 = 0;
1207 for (i = 15; i < 19; ++i)
1209 if (!is_valid_hex(s[i])) return FALSE;
1210 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
1212 if (s[19] != '-') return FALSE;
1214 for (i = 20; i < 37; i += 2)
1216 if (i == 24)
1218 if (s[i] != '-') return FALSE;
1219 i++;
1221 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1222 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1225 if (s[37] == '}' && s[38] == '\0')
1226 return TRUE;
1228 return FALSE;
1231 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1233 WCHAR buf2[CHARS_IN_GUID];
1234 LONG buf2len = sizeof(buf2);
1235 HKEY xhkey;
1236 WCHAR *buf;
1238 memset(clsid, 0, sizeof(*clsid));
1239 buf = heap_alloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1240 if (!buf) return E_OUTOFMEMORY;
1242 lstrcpyW(buf, progid);
1243 lstrcatW(buf, L"\\CLSID");
1244 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1246 heap_free(buf);
1247 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1248 return CO_E_CLASSSTRING;
1250 heap_free(buf);
1252 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1254 RegCloseKey(xhkey);
1255 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1256 return CO_E_CLASSSTRING;
1258 RegCloseKey(xhkey);
1259 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1262 /******************************************************************************
1263 * CLSIDFromProgID (combase.@)
1265 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1267 ACTCTX_SECTION_KEYED_DATA data;
1269 if (!progid || !clsid)
1270 return E_INVALIDARG;
1272 data.cbSize = sizeof(data);
1273 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1274 progid, &data))
1276 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1277 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1278 *clsid = *alias;
1279 return S_OK;
1282 return clsid_from_string_reg(progid, clsid);
1285 /******************************************************************************
1286 * CLSIDFromProgIDEx (combase.@)
1288 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1290 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1292 return CLSIDFromProgID(progid, clsid);
1295 /******************************************************************************
1296 * CLSIDFromString (combase.@)
1298 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1300 CLSID tmp_id;
1301 HRESULT hr;
1303 if (!clsid)
1304 return E_INVALIDARG;
1306 if (guid_from_string(str, clsid))
1307 return S_OK;
1309 /* It appears a ProgID is also valid */
1310 hr = clsid_from_string_reg(str, &tmp_id);
1311 if (SUCCEEDED(hr))
1312 *clsid = tmp_id;
1314 return hr;
1317 /******************************************************************************
1318 * IIDFromString (combase.@)
1320 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1322 TRACE("%s, %p\n", debugstr_w(str), iid);
1324 if (!str)
1326 memset(iid, 0, sizeof(*iid));
1327 return S_OK;
1330 /* length mismatch is a special case */
1331 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1332 return E_INVALIDARG;
1334 if (str[0] != '{')
1335 return CO_E_IIDSTRING;
1337 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1340 /******************************************************************************
1341 * StringFromCLSID (combase.@)
1343 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1345 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1346 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1347 return S_OK;
1350 /******************************************************************************
1351 * StringFromGUID2 (combase.@)
1353 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1355 if (!guid || cmax < CHARS_IN_GUID) return 0;
1356 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1357 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1358 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1359 return CHARS_IN_GUID;
1362 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1364 ULONG i;
1366 for (i = 0; i < count; i++)
1368 mqi[i].pItf = NULL;
1369 mqi[i].hr = hr;
1373 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1375 ULONG index = 0, fetched = 0;
1377 if (include_unk)
1379 mqi[0].hr = S_OK;
1380 mqi[0].pItf = unk;
1381 index = fetched = 1;
1384 for (; index < count; index++)
1386 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1387 if (mqi[index].hr == S_OK)
1388 fetched++;
1391 if (!include_unk)
1392 IUnknown_Release(unk);
1394 if (fetched == 0)
1395 return E_NOINTERFACE;
1397 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1400 /***********************************************************************
1401 * CoGetInstanceFromFile (combase.@)
1403 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1404 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1405 MULTI_QI *results)
1407 IPersistFile *pf = NULL;
1408 IUnknown *obj = NULL;
1409 CLSID clsid;
1410 HRESULT hr;
1412 if (!count || !results)
1413 return E_INVALIDARG;
1415 if (server_info)
1416 FIXME("() non-NULL server_info not supported\n");
1418 init_multi_qi(count, results, E_NOINTERFACE);
1420 if (!rclsid)
1422 hr = GetClassFile(filename, &clsid);
1423 if (FAILED(hr))
1425 ERR("Failed to get CLSID from a file.\n");
1426 return hr;
1429 rclsid = &clsid;
1432 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1433 if (hr != S_OK)
1435 init_multi_qi(count, results, hr);
1436 return hr;
1439 /* Init from file */
1440 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1441 if (FAILED(hr))
1443 init_multi_qi(count, results, hr);
1444 IUnknown_Release(obj);
1445 return hr;
1448 hr = IPersistFile_Load(pf, filename, grfmode);
1449 IPersistFile_Release(pf);
1450 if (SUCCEEDED(hr))
1451 return return_multi_qi(obj, count, results, FALSE);
1452 else
1454 init_multi_qi(count, results, hr);
1455 IUnknown_Release(obj);
1456 return hr;
1460 /***********************************************************************
1461 * CoGetInstanceFromIStorage (combase.@)
1463 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1464 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1466 IPersistStorage *ps = NULL;
1467 IUnknown *obj = NULL;
1468 STATSTG stat;
1469 HRESULT hr;
1471 if (!count || !results || !storage)
1472 return E_INVALIDARG;
1474 if (server_info)
1475 FIXME("() non-NULL server_info not supported\n");
1477 init_multi_qi(count, results, E_NOINTERFACE);
1479 if (!rclsid)
1481 memset(&stat.clsid, 0, sizeof(stat.clsid));
1482 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1483 if (FAILED(hr))
1485 ERR("Failed to get CLSID from a storage.\n");
1486 return hr;
1489 rclsid = &stat.clsid;
1492 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1493 if (hr != S_OK)
1494 return hr;
1496 /* Init from IStorage */
1497 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1498 if (FAILED(hr))
1499 ERR("failed to get IPersistStorage\n");
1501 if (ps)
1503 IPersistStorage_Load(ps, storage);
1504 IPersistStorage_Release(ps);
1507 return return_multi_qi(obj, count, results, FALSE);
1510 /***********************************************************************
1511 * CoCreateInstance (combase.@)
1513 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1514 REFIID riid, void **obj)
1516 MULTI_QI multi_qi = { .pIID = riid };
1517 HRESULT hr;
1519 TRACE("%s, %p, %#x, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1521 if (!obj)
1522 return E_POINTER;
1524 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1525 *obj = multi_qi.pItf;
1526 return hr;
1529 /***********************************************************************
1530 * CoCreateInstanceFromApp (combase.@)
1532 HRESULT WINAPI CoCreateInstanceFromApp(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1533 void *server_info, ULONG count, MULTI_QI *results)
1535 TRACE("%s, %p, %#x, %p, %u, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info,
1536 count, results);
1538 return CoCreateInstanceEx(rclsid, outer, cls_context | CLSCTX_APPCONTAINER, server_info,
1539 count, results);
1542 static HRESULT com_get_class_object(REFCLSID rclsid, DWORD clscontext,
1543 COSERVERINFO *server_info, REFIID riid, void **obj)
1545 struct class_reg_data clsreg = { 0 };
1546 HRESULT hr = E_UNEXPECTED;
1547 IUnknown *registered_obj;
1548 struct apartment *apt;
1550 if (!obj)
1551 return E_INVALIDARG;
1553 *obj = NULL;
1555 if (!(apt = apartment_get_current_or_mta()))
1557 ERR("apartment not initialised\n");
1558 return CO_E_NOTINITIALIZED;
1561 if (server_info)
1562 FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
1564 if (clscontext & CLSCTX_INPROC_SERVER)
1566 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
1567 IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
1568 (!(clscontext & CLSCTX_APPCONTAINER) && IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) ||
1569 IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
1571 apartment_release(apt);
1572 return Ole32DllGetClassObject(rclsid, riid, obj);
1576 if (clscontext & CLSCTX_INPROC)
1578 ACTCTX_SECTION_KEYED_DATA data;
1580 data.cbSize = sizeof(data);
1581 /* search activation context first */
1582 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1583 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
1585 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
1587 clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
1588 clsreg.u.actctx.hactctx = data.hActCtx;
1589 clsreg.u.actctx.threading_model = comclass->model;
1590 clsreg.origin = CLASS_REG_ACTCTX;
1592 hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid, clscontext, obj);
1593 ReleaseActCtx(data.hActCtx);
1594 apartment_release(apt);
1595 return hr;
1600 * First, try and see if we can't match the class ID with one of the
1601 * registered classes.
1603 if (!(clscontext & CLSCTX_APPCONTAINER) && (registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
1605 hr = IUnknown_QueryInterface(registered_obj, riid, obj);
1606 IUnknown_Release(registered_obj);
1607 apartment_release(apt);
1608 return hr;
1611 /* First try in-process server */
1612 if (clscontext & CLSCTX_INPROC_SERVER)
1614 HKEY hkey;
1616 hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
1617 if (FAILED(hr))
1619 if (hr == REGDB_E_CLASSNOTREG)
1620 ERR("class %s not registered\n", debugstr_guid(rclsid));
1621 else if (hr == REGDB_E_KEYMISSING)
1623 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
1624 hr = REGDB_E_CLASSNOTREG;
1628 if (SUCCEEDED(hr))
1630 clsreg.u.hkey = hkey;
1631 clsreg.origin = CLASS_REG_REGISTRY;
1633 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1634 RegCloseKey(hkey);
1637 /* return if we got a class, otherwise fall through to one of the
1638 * other types */
1639 if (SUCCEEDED(hr))
1641 apartment_release(apt);
1642 return hr;
1646 /* Next try in-process handler */
1647 if (clscontext & CLSCTX_INPROC_HANDLER)
1649 HKEY hkey;
1651 hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
1652 if (FAILED(hr))
1654 if (hr == REGDB_E_CLASSNOTREG)
1655 ERR("class %s not registered\n", debugstr_guid(rclsid));
1656 else if (hr == REGDB_E_KEYMISSING)
1658 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
1659 hr = REGDB_E_CLASSNOTREG;
1663 if (SUCCEEDED(hr))
1665 clsreg.u.hkey = hkey;
1666 clsreg.origin = CLASS_REG_REGISTRY;
1668 hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, clscontext, obj);
1669 RegCloseKey(hkey);
1672 /* return if we got a class, otherwise fall through to one of the
1673 * other types */
1674 if (SUCCEEDED(hr))
1676 apartment_release(apt);
1677 return hr;
1680 apartment_release(apt);
1682 /* Next try out of process */
1683 if (clscontext & CLSCTX_LOCAL_SERVER)
1685 hr = rpc_get_local_class_object(rclsid, riid, obj);
1686 if (SUCCEEDED(hr))
1687 return hr;
1690 /* Finally try remote: this requires networked DCOM (a lot of work) */
1691 if (clscontext & CLSCTX_REMOTE_SERVER)
1693 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1694 hr = REGDB_E_CLASSNOTREG;
1697 if (FAILED(hr))
1698 ERR("no class object %s could be created for context %#x\n", debugstr_guid(rclsid), clscontext);
1700 return hr;
1703 /***********************************************************************
1704 * CoCreateInstanceEx (combase.@)
1706 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1707 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1709 IClassFactory *factory;
1710 IUnknown *unk = NULL;
1711 CLSID clsid;
1712 HRESULT hr;
1714 TRACE("%s, %p, %#x, %p, %u, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1716 if (!count || !results)
1717 return E_INVALIDARG;
1719 if (server_info)
1720 FIXME("Server info is not supported.\n");
1722 init_multi_qi(count, results, E_NOINTERFACE);
1724 clsid = *rclsid;
1725 if (!(cls_context & CLSCTX_APPCONTAINER))
1726 CoGetTreatAsClass(rclsid, &clsid);
1728 if (FAILED(hr = com_get_class_object(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory)))
1729 return hr;
1731 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1732 IClassFactory_Release(factory);
1733 if (FAILED(hr))
1735 if (hr == CLASS_E_NOAGGREGATION && outer)
1736 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1737 else
1738 FIXME("no instance created for interface %s of class %s, hr %#x.\n",
1739 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1740 return hr;
1743 return return_multi_qi(unk, count, results, TRUE);
1746 /***********************************************************************
1747 * CoGetClassObject (combase.@)
1749 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
1750 COSERVERINFO *server_info, REFIID riid, void **obj)
1752 TRACE("%s, %#x, %s\n", debugstr_guid(rclsid), clscontext, debugstr_guid(riid));
1754 return com_get_class_object(rclsid, clscontext, server_info, riid, obj);
1757 /***********************************************************************
1758 * CoFreeUnusedLibraries (combase.@)
1760 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1762 CoFreeUnusedLibrariesEx(INFINITE, 0);
1765 /***********************************************************************
1766 * CoGetCallContext (combase.@)
1768 HRESULT WINAPI CoGetCallContext(REFIID riid, void **obj)
1770 struct tlsdata *tlsdata;
1771 HRESULT hr;
1773 TRACE("%s, %p\n", debugstr_guid(riid), obj);
1775 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1776 return hr;
1778 if (!tlsdata->call_state)
1779 return RPC_E_CALL_COMPLETE;
1781 return IUnknown_QueryInterface(tlsdata->call_state, riid, obj);
1784 /***********************************************************************
1785 * CoSwitchCallContext (combase.@)
1787 HRESULT WINAPI CoSwitchCallContext(IUnknown *context, IUnknown **old_context)
1789 struct tlsdata *tlsdata;
1790 HRESULT hr;
1792 TRACE("%p, %p\n", context, old_context);
1794 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1795 return hr;
1797 /* Reference counts are not touched. */
1798 *old_context = tlsdata->call_state;
1799 tlsdata->call_state = context;
1801 return S_OK;
1804 /******************************************************************************
1805 * CoRegisterInitializeSpy (combase.@)
1807 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1809 struct tlsdata *tlsdata;
1810 struct init_spy *entry;
1811 unsigned int id;
1812 HRESULT hr;
1814 TRACE("%p, %p\n", spy, cookie);
1816 if (!spy || !cookie)
1817 return E_INVALIDARG;
1819 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1820 return hr;
1822 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1823 if (FAILED(hr))
1824 return hr;
1826 entry = heap_alloc(sizeof(*entry));
1827 if (!entry)
1829 IInitializeSpy_Release(spy);
1830 return E_OUTOFMEMORY;
1833 entry->spy = spy;
1835 id = 0;
1836 while (get_spy_entry(tlsdata, id) != NULL)
1838 id++;
1841 entry->id = id;
1842 list_add_head(&tlsdata->spies, &entry->entry);
1844 cookie->u.HighPart = GetCurrentThreadId();
1845 cookie->u.LowPart = entry->id;
1847 return S_OK;
1850 /******************************************************************************
1851 * CoRevokeInitializeSpy (combase.@)
1853 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1855 struct tlsdata *tlsdata;
1856 struct init_spy *spy;
1857 HRESULT hr;
1859 TRACE("%s\n", wine_dbgstr_longlong(cookie.QuadPart));
1861 if (cookie.u.HighPart != GetCurrentThreadId())
1862 return E_INVALIDARG;
1864 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1865 return hr;
1867 if (!(spy = get_spy_entry(tlsdata, cookie.u.LowPart))) return E_INVALIDARG;
1869 IInitializeSpy_Release(spy->spy);
1870 spy->spy = NULL;
1871 if (!tlsdata->spies_lock)
1873 list_remove(&spy->entry);
1874 heap_free(spy);
1876 return S_OK;
1879 static BOOL com_peek_message(struct apartment *apt, MSG *msg)
1881 /* First try to retrieve messages for incoming COM calls to the apartment window */
1882 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE | PM_NOYIELD)) ||
1883 /* Next retrieve other messages necessary for the app to remain responsive */
1884 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE | PM_NOYIELD) ||
1885 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT | PM_QS_SENDMESSAGE | PM_REMOVE | PM_NOYIELD);
1888 /***********************************************************************
1889 * CoWaitForMultipleHandles (combase.@)
1891 HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles,
1892 DWORD *index)
1894 BOOL check_apc = !!(flags & COWAIT_ALERTABLE), post_quit = FALSE, message_loop;
1895 DWORD start_time, wait_flags = 0;
1896 struct tlsdata *tlsdata;
1897 struct apartment *apt;
1898 UINT exit_code;
1899 HRESULT hr;
1901 TRACE("%#x, %#x, %u, %p, %p\n", flags, timeout, handle_count, handles, index);
1903 if (!index)
1904 return E_INVALIDARG;
1906 *index = 0;
1908 if (!handles)
1909 return E_INVALIDARG;
1911 if (!handle_count)
1912 return RPC_E_NO_SYNC;
1914 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1915 return hr;
1917 apt = com_get_current_apt();
1918 message_loop = apt && !apt->multi_threaded;
1920 if (flags & COWAIT_WAITALL)
1921 wait_flags |= MWMO_WAITALL;
1922 if (flags & COWAIT_ALERTABLE)
1923 wait_flags |= MWMO_ALERTABLE;
1925 start_time = GetTickCount();
1927 while (TRUE)
1929 DWORD now = GetTickCount(), res;
1931 if (now - start_time > timeout)
1933 hr = RPC_S_CALLPENDING;
1934 break;
1937 if (message_loop)
1939 TRACE("waiting for rpc completion or window message\n");
1941 res = WAIT_TIMEOUT;
1943 if (check_apc)
1945 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE);
1946 check_apc = FALSE;
1949 if (res == WAIT_TIMEOUT)
1950 res = MsgWaitForMultipleObjectsEx(handle_count, handles,
1951 timeout == INFINITE ? INFINITE : start_time + timeout - now,
1952 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
1954 if (res == WAIT_OBJECT_0 + handle_count) /* messages available */
1956 int msg_count = 0;
1957 MSG msg;
1959 /* call message filter */
1961 if (apt->filter)
1963 PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
1964 DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype);
1966 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
1968 switch (be_handled)
1970 case PENDINGMSG_CANCELCALL:
1971 WARN("call canceled\n");
1972 hr = RPC_E_CALL_CANCELED;
1973 break;
1974 case PENDINGMSG_WAITNOPROCESS:
1975 case PENDINGMSG_WAITDEFPROCESS:
1976 default:
1977 /* FIXME: MSDN is very vague about the difference
1978 * between WAITNOPROCESS and WAITDEFPROCESS - there
1979 * appears to be none, so it is possibly a left-over
1980 * from the 16-bit world. */
1981 break;
1985 if (!apt->win)
1987 /* If window is NULL on apartment, peek at messages so that it will not trigger
1988 * MsgWaitForMultipleObjects next time. */
1989 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
1992 /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
1993 * so after processing 100 messages we go back to checking the wait handles */
1994 while (msg_count++ < 100 && com_peek_message(apt, &msg))
1996 if (msg.message == WM_QUIT)
1998 TRACE("Received WM_QUIT message\n");
1999 post_quit = TRUE;
2000 exit_code = msg.wParam;
2002 else
2004 TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message);
2005 TranslateMessage(&msg);
2006 DispatchMessageW(&msg);
2009 continue;
2012 else
2014 TRACE("Waiting for rpc completion\n");
2016 res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL),
2017 (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE));
2020 switch (res)
2022 case WAIT_TIMEOUT:
2023 hr = RPC_S_CALLPENDING;
2024 break;
2025 case WAIT_FAILED:
2026 hr = HRESULT_FROM_WIN32(GetLastError());
2027 break;
2028 default:
2029 *index = res;
2030 break;
2032 break;
2034 if (post_quit) PostQuitMessage(exit_code);
2036 TRACE("-- 0x%08x\n", hr);
2038 return hr;
2041 /******************************************************************************
2042 * CoRegisterMessageFilter (combase.@)
2044 HRESULT WINAPI CoRegisterMessageFilter(IMessageFilter *filter, IMessageFilter **ret_filter)
2046 IMessageFilter *old_filter;
2047 struct apartment *apt;
2049 TRACE("%p, %p\n", filter, ret_filter);
2051 apt = com_get_current_apt();
2053 /* Can't set a message filter in a multi-threaded apartment */
2054 if (!apt || apt->multi_threaded)
2056 WARN("Can't set message filter in MTA or uninitialized apt\n");
2057 return CO_E_NOT_SUPPORTED;
2060 if (filter)
2061 IMessageFilter_AddRef(filter);
2063 EnterCriticalSection(&apt->cs);
2065 old_filter = apt->filter;
2066 apt->filter = filter;
2068 LeaveCriticalSection(&apt->cs);
2070 if (ret_filter)
2071 *ret_filter = old_filter;
2072 else if (old_filter)
2073 IMessageFilter_Release(old_filter);
2075 return S_OK;
2078 static void com_revoke_all_ps_clsids(void)
2080 struct registered_ps *cur, *cur2;
2082 EnterCriticalSection(&cs_registered_ps);
2084 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_proxystubs, struct registered_ps, entry)
2086 list_remove(&cur->entry);
2087 heap_free(cur);
2090 LeaveCriticalSection(&cs_registered_ps);
2093 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2095 WCHAR value[CHARS_IN_GUID];
2096 HKEY hkey;
2097 DWORD len;
2099 access |= KEY_READ;
2101 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2102 return REGDB_E_IIDNOTREG;
2104 len = sizeof(value);
2105 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2106 return REGDB_E_IIDNOTREG;
2107 RegCloseKey(hkey);
2109 if (CLSIDFromString(value, pclsid) != NOERROR)
2110 return REGDB_E_IIDNOTREG;
2112 return S_OK;
2115 /*****************************************************************************
2116 * CoGetPSClsid (combase.@)
2118 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2120 static const WCHAR interfaceW[] = L"Interface\\";
2121 static const WCHAR psW[] = L"\\ProxyStubClsid32";
2122 WCHAR path[ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(psW)];
2123 ACTCTX_SECTION_KEYED_DATA data;
2124 struct registered_ps *cur;
2125 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2126 BOOL is_wow64;
2127 HRESULT hr;
2129 TRACE("%s, %p\n", debugstr_guid(riid), pclsid);
2131 if (!InternalIsProcessInitialized())
2133 ERR("apartment not initialised\n");
2134 return CO_E_NOTINITIALIZED;
2137 if (!pclsid)
2138 return E_INVALIDARG;
2140 EnterCriticalSection(&cs_registered_ps);
2142 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2144 if (IsEqualIID(&cur->iid, riid))
2146 *pclsid = cur->clsid;
2147 LeaveCriticalSection(&cs_registered_ps);
2148 return S_OK;
2152 LeaveCriticalSection(&cs_registered_ps);
2154 data.cbSize = sizeof(data);
2155 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2156 riid, &data))
2158 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data *)data.lpData;
2159 *pclsid = ifaceps->iid;
2160 return S_OK;
2163 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2164 lstrcpyW(path, interfaceW);
2165 StringFromGUID2(riid, path + ARRAY_SIZE(interfaceW) - 1, CHARS_IN_GUID);
2166 lstrcpyW(path + ARRAY_SIZE(interfaceW) - 1 + CHARS_IN_GUID - 1, psW);
2168 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2169 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2170 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2172 if (hr == S_OK)
2173 TRACE("() Returning CLSID %s\n", debugstr_guid(pclsid));
2174 else
2175 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2177 return hr;
2180 /*****************************************************************************
2181 * CoRegisterPSClsid (combase.@)
2183 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2185 struct registered_ps *cur;
2187 TRACE("%s, %s\n", debugstr_guid(riid), debugstr_guid(rclsid));
2189 if (!InternalIsProcessInitialized())
2191 ERR("apartment not initialised\n");
2192 return CO_E_NOTINITIALIZED;
2195 EnterCriticalSection(&cs_registered_ps);
2197 LIST_FOR_EACH_ENTRY(cur, &registered_proxystubs, struct registered_ps, entry)
2199 if (IsEqualIID(&cur->iid, riid))
2201 cur->clsid = *rclsid;
2202 LeaveCriticalSection(&cs_registered_ps);
2203 return S_OK;
2207 cur = heap_alloc(sizeof(*cur));
2208 if (!cur)
2210 LeaveCriticalSection(&cs_registered_ps);
2211 return E_OUTOFMEMORY;
2214 cur->iid = *riid;
2215 cur->clsid = *rclsid;
2216 list_add_head(&registered_proxystubs, &cur->entry);
2218 LeaveCriticalSection(&cs_registered_ps);
2220 return S_OK;
2223 struct thread_context
2225 IComThreadingInfo IComThreadingInfo_iface;
2226 IContextCallback IContextCallback_iface;
2227 IObjContext IObjContext_iface;
2228 LONG refcount;
2231 static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface)
2233 return CONTAINING_RECORD(iface, struct thread_context, IComThreadingInfo_iface);
2236 static inline struct thread_context *impl_from_IContextCallback(IContextCallback *iface)
2238 return CONTAINING_RECORD(iface, struct thread_context, IContextCallback_iface);
2241 static inline struct thread_context *impl_from_IObjContext(IObjContext *iface)
2243 return CONTAINING_RECORD(iface, struct thread_context, IObjContext_iface);
2246 static HRESULT WINAPI thread_context_info_QueryInterface(IComThreadingInfo *iface, REFIID riid, void **obj)
2248 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2250 *obj = NULL;
2252 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
2253 IsEqualIID(riid, &IID_IUnknown))
2255 *obj = &context->IComThreadingInfo_iface;
2257 else if (IsEqualIID(riid, &IID_IContextCallback))
2259 *obj = &context->IContextCallback_iface;
2261 else if (IsEqualIID(riid, &IID_IObjContext))
2263 *obj = &context->IObjContext_iface;
2266 if (*obj)
2268 IUnknown_AddRef((IUnknown *)*obj);
2269 return S_OK;
2272 FIXME("interface not implemented %s\n", debugstr_guid(riid));
2273 return E_NOINTERFACE;
2276 static ULONG WINAPI thread_context_info_AddRef(IComThreadingInfo *iface)
2278 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2279 return InterlockedIncrement(&context->refcount);
2282 static ULONG WINAPI thread_context_info_Release(IComThreadingInfo *iface)
2284 struct thread_context *context = impl_from_IComThreadingInfo(iface);
2286 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
2287 releasing context while refcount is at 0 destroys it. */
2288 if (!context->refcount)
2290 heap_free(context);
2291 return 0;
2294 return InterlockedDecrement(&context->refcount);
2297 static HRESULT WINAPI thread_context_info_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
2299 APTTYPEQUALIFIER qualifier;
2301 TRACE("%p\n", apttype);
2303 return CoGetApartmentType(apttype, &qualifier);
2306 static HRESULT WINAPI thread_context_info_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
2308 APTTYPEQUALIFIER qualifier;
2309 APTTYPE apttype;
2310 HRESULT hr;
2312 hr = CoGetApartmentType(&apttype, &qualifier);
2313 if (FAILED(hr))
2314 return hr;
2316 TRACE("%p\n", thdtype);
2318 switch (apttype)
2320 case APTTYPE_STA:
2321 case APTTYPE_MAINSTA:
2322 *thdtype = THDTYPE_PROCESSMESSAGES;
2323 break;
2324 default:
2325 *thdtype = THDTYPE_BLOCKMESSAGES;
2326 break;
2328 return S_OK;
2331 static HRESULT WINAPI thread_context_info_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
2333 TRACE("%p\n", logical_thread_id);
2335 return CoGetCurrentLogicalThreadId(logical_thread_id);
2338 static HRESULT WINAPI thread_context_info_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
2340 FIXME("%s stub\n", debugstr_guid(logical_thread_id));
2342 return E_NOTIMPL;
2345 static const IComThreadingInfoVtbl thread_context_info_vtbl =
2347 thread_context_info_QueryInterface,
2348 thread_context_info_AddRef,
2349 thread_context_info_Release,
2350 thread_context_info_GetCurrentApartmentType,
2351 thread_context_info_GetCurrentThreadType,
2352 thread_context_info_GetCurrentLogicalThreadId,
2353 thread_context_info_SetCurrentLogicalThreadId
2356 static HRESULT WINAPI thread_context_callback_QueryInterface(IContextCallback *iface, REFIID riid, void **obj)
2358 struct thread_context *context = impl_from_IContextCallback(iface);
2359 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2362 static ULONG WINAPI thread_context_callback_AddRef(IContextCallback *iface)
2364 struct thread_context *context = impl_from_IContextCallback(iface);
2365 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2368 static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface)
2370 struct thread_context *context = impl_from_IContextCallback(iface);
2371 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2374 static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface,
2375 PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk)
2377 FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk);
2379 return E_NOTIMPL;
2382 static const IContextCallbackVtbl thread_context_callback_vtbl =
2384 thread_context_callback_QueryInterface,
2385 thread_context_callback_AddRef,
2386 thread_context_callback_Release,
2387 thread_context_callback_ContextCallback
2390 static HRESULT WINAPI thread_object_context_QueryInterface(IObjContext *iface, REFIID riid, void **obj)
2392 struct thread_context *context = impl_from_IObjContext(iface);
2393 return IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, obj);
2396 static ULONG WINAPI thread_object_context_AddRef(IObjContext *iface)
2398 struct thread_context *context = impl_from_IObjContext(iface);
2399 return IComThreadingInfo_AddRef(&context->IComThreadingInfo_iface);
2402 static ULONG WINAPI thread_object_context_Release(IObjContext *iface)
2404 struct thread_context *context = impl_from_IObjContext(iface);
2405 return IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
2408 static HRESULT WINAPI thread_object_context_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
2410 FIXME("%p, %s, %x, %p\n", iface, debugstr_guid(propid), flags, punk);
2412 return E_NOTIMPL;
2415 static HRESULT WINAPI thread_object_context_RemoveProperty(IObjContext *iface, REFGUID propid)
2417 FIXME("%p, %s\n", iface, debugstr_guid(propid));
2419 return E_NOTIMPL;
2422 static HRESULT WINAPI thread_object_context_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
2424 FIXME("%p, %s, %p, %p\n", iface, debugstr_guid(propid), flags, punk);
2426 return E_NOTIMPL;
2429 static HRESULT WINAPI thread_object_context_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
2431 FIXME("%p, %p\n", iface, props);
2433 return E_NOTIMPL;
2436 static void WINAPI thread_object_context_Reserved1(IObjContext *iface)
2438 FIXME("%p\n", iface);
2441 static void WINAPI thread_object_context_Reserved2(IObjContext *iface)
2443 FIXME("%p\n", iface);
2446 static void WINAPI thread_object_context_Reserved3(IObjContext *iface)
2448 FIXME("%p\n", iface);
2451 static void WINAPI thread_object_context_Reserved4(IObjContext *iface)
2453 FIXME("%p\n", iface);
2456 static void WINAPI thread_object_context_Reserved5(IObjContext *iface)
2458 FIXME("%p\n", iface);
2461 static void WINAPI thread_object_context_Reserved6(IObjContext *iface)
2463 FIXME("%p\n", iface);
2466 static void WINAPI thread_object_context_Reserved7(IObjContext *iface)
2468 FIXME("%p\n", iface);
2471 static const IObjContextVtbl thread_object_context_vtbl =
2473 thread_object_context_QueryInterface,
2474 thread_object_context_AddRef,
2475 thread_object_context_Release,
2476 thread_object_context_SetProperty,
2477 thread_object_context_RemoveProperty,
2478 thread_object_context_GetProperty,
2479 thread_object_context_EnumContextProps,
2480 thread_object_context_Reserved1,
2481 thread_object_context_Reserved2,
2482 thread_object_context_Reserved3,
2483 thread_object_context_Reserved4,
2484 thread_object_context_Reserved5,
2485 thread_object_context_Reserved6,
2486 thread_object_context_Reserved7
2489 /***********************************************************************
2490 * CoGetContextToken (combase.@)
2492 HRESULT WINAPI CoGetContextToken(ULONG_PTR *token)
2494 struct tlsdata *tlsdata;
2495 HRESULT hr;
2497 TRACE("%p\n", token);
2499 if (!InternalIsProcessInitialized())
2501 ERR("apartment not initialised\n");
2502 return CO_E_NOTINITIALIZED;
2505 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2506 return hr;
2508 if (!token)
2509 return E_POINTER;
2511 if (!tlsdata->context_token)
2513 struct thread_context *context;
2515 context = heap_alloc_zero(sizeof(*context));
2516 if (!context)
2517 return E_OUTOFMEMORY;
2519 context->IComThreadingInfo_iface.lpVtbl = &thread_context_info_vtbl;
2520 context->IContextCallback_iface.lpVtbl = &thread_context_callback_vtbl;
2521 context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl;
2522 /* Context token does not take a reference, it's always zero until the
2523 interface is explicitly requested with CoGetObjectContext(). */
2524 context->refcount = 0;
2526 tlsdata->context_token = &context->IObjContext_iface;
2529 *token = (ULONG_PTR)tlsdata->context_token;
2530 TRACE("context_token %p\n", tlsdata->context_token);
2532 return S_OK;
2535 /***********************************************************************
2536 * CoGetCurrentLogicalThreadId (combase.@)
2538 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
2540 struct tlsdata *tlsdata;
2541 HRESULT hr;
2543 if (!id)
2544 return E_INVALIDARG;
2546 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2547 return hr;
2549 if (IsEqualGUID(&tlsdata->causality_id, &GUID_NULL))
2551 CoCreateGuid(&tlsdata->causality_id);
2552 tlsdata->flags |= OLETLS_UUIDINITIALIZED;
2555 *id = tlsdata->causality_id;
2557 return S_OK;
2560 /******************************************************************************
2561 * CoGetCurrentProcess (combase.@)
2563 DWORD WINAPI CoGetCurrentProcess(void)
2565 struct tlsdata *tlsdata;
2567 if (FAILED(com_get_tlsdata(&tlsdata)))
2568 return 0;
2570 if (!tlsdata->thread_seqid)
2571 rpcss_get_next_seqid(&tlsdata->thread_seqid);
2573 return tlsdata->thread_seqid;
2576 /***********************************************************************
2577 * CoFreeUnusedLibrariesEx (combase.@)
2579 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved)
2581 struct apartment *apt = com_get_current_apt();
2582 if (!apt)
2584 ERR("apartment not initialised\n");
2585 return;
2588 apartment_freeunusedlibraries(apt, unload_delay);
2592 * When locked, don't modify list (unless we add a new head), so that it's
2593 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
2595 static inline void lock_init_spies(struct tlsdata *tlsdata)
2597 tlsdata->spies_lock++;
2600 static void unlock_init_spies(struct tlsdata *tlsdata)
2602 struct init_spy *spy, *next;
2604 if (--tlsdata->spies_lock) return;
2606 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &tlsdata->spies, struct init_spy, entry)
2608 if (spy->spy) continue;
2609 list_remove(&spy->entry);
2610 heap_free(spy);
2614 /******************************************************************************
2615 * CoInitializeWOW (combase.@)
2617 HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2)
2619 FIXME("%#x, %#x\n", arg1, arg2);
2621 return S_OK;
2624 /******************************************************************************
2625 * CoInitializeEx (combase.@)
2627 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(void *reserved, DWORD model)
2629 struct tlsdata *tlsdata;
2630 struct init_spy *cursor;
2631 HRESULT hr;
2633 TRACE("%p, %#x\n", reserved, model);
2635 if (reserved)
2636 WARN("Unexpected reserved argument %p\n", reserved);
2638 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2639 return hr;
2641 if (InterlockedExchangeAdd(&com_lockcount, 1) == 0)
2642 TRACE("Initializing the COM libraries\n");
2644 lock_init_spies(tlsdata);
2645 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2647 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, model, tlsdata->inits);
2649 unlock_init_spies(tlsdata);
2651 hr = enter_apartment(tlsdata, model);
2653 lock_init_spies(tlsdata);
2654 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2656 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, model, tlsdata->inits);
2658 unlock_init_spies(tlsdata);
2660 return hr;
2663 /***********************************************************************
2664 * CoUninitialize (combase.@)
2666 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2668 struct tlsdata *tlsdata;
2669 struct init_spy *cursor, *next;
2670 LONG lockcount;
2672 TRACE("\n");
2674 if (FAILED(com_get_tlsdata(&tlsdata)))
2675 return;
2677 lock_init_spies(tlsdata);
2678 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2680 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, tlsdata->inits);
2682 unlock_init_spies(tlsdata);
2684 /* sanity check */
2685 if (!tlsdata->inits)
2687 ERR("Mismatched CoUninitialize\n");
2689 lock_init_spies(tlsdata);
2690 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &tlsdata->spies, struct init_spy, entry)
2692 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2694 unlock_init_spies(tlsdata);
2696 return;
2699 leave_apartment(tlsdata);
2702 * Decrease the reference count.
2703 * If we are back to 0 locks on the COM library, make sure we free
2704 * all the associated data structures.
2706 lockcount = InterlockedExchangeAdd(&com_lockcount, -1);
2707 if (lockcount == 1)
2709 TRACE("Releasing the COM libraries\n");
2711 com_revoke_all_ps_clsids();
2712 DestroyRunningObjectTable();
2714 else if (lockcount < 1)
2716 ERR("Unbalanced lock count %d\n", lockcount);
2717 InterlockedExchangeAdd(&com_lockcount, 1);
2720 lock_init_spies(tlsdata);
2721 LIST_FOR_EACH_ENTRY(cursor, &tlsdata->spies, struct init_spy, entry)
2723 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, tlsdata->inits);
2725 unlock_init_spies(tlsdata);
2728 /***********************************************************************
2729 * CoIncrementMTAUsage (combase.@)
2731 HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
2733 TRACE("%p\n", cookie);
2735 return apartment_increment_mta_usage(cookie);
2738 /***********************************************************************
2739 * CoDecrementMTAUsage (combase.@)
2741 HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
2743 TRACE("%p\n", cookie);
2745 apartment_decrement_mta_usage(cookie);
2746 return S_OK;
2749 /***********************************************************************
2750 * CoGetApartmentType (combase.@)
2752 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
2754 struct tlsdata *tlsdata;
2755 struct apartment *apt;
2756 HRESULT hr;
2758 TRACE("%p, %p\n", type, qualifier);
2760 if (!type || !qualifier)
2761 return E_INVALIDARG;
2763 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
2764 return hr;
2766 if (!tlsdata->apt)
2767 *type = APTTYPE_CURRENT;
2768 else if (tlsdata->apt->multi_threaded)
2769 *type = APTTYPE_MTA;
2770 else if (tlsdata->apt->main)
2771 *type = APTTYPE_MAINSTA;
2772 else
2773 *type = APTTYPE_STA;
2775 *qualifier = APTTYPEQUALIFIER_NONE;
2777 if (!tlsdata->apt && (apt = apartment_get_mta()))
2779 apartment_release(apt);
2780 *type = APTTYPE_MTA;
2781 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
2782 return S_OK;
2785 return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
2788 /******************************************************************************
2789 * CoRegisterClassObject (combase.@)
2790 * BUGS
2791 * MSDN claims that multiple interface registrations are legal, but we
2792 * can't do that with our current implementation.
2794 HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
2795 DWORD flags, DWORD *cookie)
2797 static LONG next_cookie;
2799 struct registered_class *newclass;
2800 IUnknown *found_object;
2801 struct apartment *apt;
2802 HRESULT hr = S_OK;
2804 TRACE("%s, %p, %#x, %#x, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
2806 if (!cookie || !object)
2807 return E_INVALIDARG;
2809 if (!(apt = apartment_get_current_or_mta()))
2811 ERR("COM was not initialized\n");
2812 return CO_E_NOTINITIALIZED;
2815 *cookie = 0;
2817 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2818 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2819 if (flags & REGCLS_MULTIPLEUSE)
2820 clscontext |= CLSCTX_INPROC_SERVER;
2823 * First, check if the class is already registered.
2824 * If it is, this should cause an error.
2826 if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
2828 if (flags & REGCLS_MULTIPLEUSE)
2830 if (clscontext & CLSCTX_LOCAL_SERVER)
2831 hr = CoLockObjectExternal(found_object, TRUE, FALSE);
2832 IUnknown_Release(found_object);
2833 apartment_release(apt);
2834 return hr;
2837 IUnknown_Release(found_object);
2838 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2839 apartment_release(apt);
2840 return CO_E_OBJISREG;
2843 newclass = heap_alloc_zero(sizeof(*newclass));
2844 if (!newclass)
2846 apartment_release(apt);
2847 return E_OUTOFMEMORY;
2850 newclass->clsid = *rclsid;
2851 newclass->apartment_id = apt->oxid;
2852 newclass->clscontext = clscontext;
2853 newclass->flags = flags;
2855 if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
2856 newclass->cookie = InterlockedIncrement(&next_cookie);
2858 newclass->object = object;
2859 IUnknown_AddRef(newclass->object);
2861 EnterCriticalSection(&registered_classes_cs);
2862 list_add_tail(&registered_classes, &newclass->entry);
2863 LeaveCriticalSection(&registered_classes_cs);
2865 *cookie = newclass->cookie;
2867 if (clscontext & CLSCTX_LOCAL_SERVER)
2869 IStream *marshal_stream;
2871 hr = apartment_get_local_server_stream(apt, &marshal_stream);
2872 if(FAILED(hr))
2874 apartment_release(apt);
2875 return hr;
2878 hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
2879 IStream_Release(marshal_stream);
2882 apartment_release(apt);
2883 return S_OK;
2886 static void com_revoke_class_object(struct registered_class *entry)
2888 list_remove(&entry->entry);
2890 if (entry->clscontext & CLSCTX_LOCAL_SERVER)
2891 rpc_revoke_local_server(entry->rpcss_cookie);
2893 IUnknown_Release(entry->object);
2894 heap_free(entry);
2897 /* Cleans up rpcss registry */
2898 static void com_revoke_local_servers(void)
2900 struct registered_class *cur, *cur2;
2902 EnterCriticalSection(&registered_classes_cs);
2904 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
2906 if (cur->clscontext & CLSCTX_LOCAL_SERVER)
2907 com_revoke_class_object(cur);
2910 LeaveCriticalSection(&registered_classes_cs);
2913 void apartment_revoke_all_classes(const struct apartment *apt)
2915 struct registered_class *cur, *cur2;
2917 EnterCriticalSection(&registered_classes_cs);
2919 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
2921 if (cur->apartment_id == apt->oxid)
2922 com_revoke_class_object(cur);
2925 LeaveCriticalSection(&registered_classes_cs);
2928 /***********************************************************************
2929 * CoRevokeClassObject (combase.@)
2931 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
2933 HRESULT hr = E_INVALIDARG;
2934 struct registered_class *cur;
2935 struct apartment *apt;
2937 TRACE("%#x\n", cookie);
2939 if (!(apt = apartment_get_current_or_mta()))
2941 ERR("COM was not initialized\n");
2942 return CO_E_NOTINITIALIZED;
2945 EnterCriticalSection(&registered_classes_cs);
2947 LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
2949 if (cur->cookie != cookie)
2950 continue;
2952 if (cur->apartment_id == apt->oxid)
2954 com_revoke_class_object(cur);
2955 hr = S_OK;
2957 else
2959 ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
2960 hr = RPC_E_WRONG_THREAD;
2963 break;
2966 LeaveCriticalSection(&registered_classes_cs);
2967 apartment_release(apt);
2969 return hr;
2972 /***********************************************************************
2973 * CoAddRefServerProcess (combase.@)
2975 ULONG WINAPI CoAddRefServerProcess(void)
2977 ULONG refs;
2979 TRACE("\n");
2981 EnterCriticalSection(&registered_classes_cs);
2982 refs = ++com_server_process_refcount;
2983 LeaveCriticalSection(&registered_classes_cs);
2985 TRACE("refs before: %d\n", refs - 1);
2987 return refs;
2990 /***********************************************************************
2991 * CoReleaseServerProcess [OLE32.@]
2993 ULONG WINAPI CoReleaseServerProcess(void)
2995 ULONG refs;
2997 TRACE("\n");
2999 EnterCriticalSection(&registered_classes_cs);
3001 refs = --com_server_process_refcount;
3002 /* FIXME: suspend objects */
3004 LeaveCriticalSection(&registered_classes_cs);
3006 TRACE("refs after: %d\n", refs);
3008 return refs;
3011 /******************************************************************************
3012 * CoDisconnectObject (combase.@)
3014 HRESULT WINAPI CoDisconnectObject(IUnknown *object, DWORD reserved)
3016 struct stub_manager *manager;
3017 struct apartment *apt;
3018 IMarshal *marshal;
3019 HRESULT hr;
3021 TRACE("%p, %#x\n", object, reserved);
3023 if (!object)
3024 return E_INVALIDARG;
3026 hr = IUnknown_QueryInterface(object, &IID_IMarshal, (void **)&marshal);
3027 if (hr == S_OK)
3029 hr = IMarshal_DisconnectObject(marshal, reserved);
3030 IMarshal_Release(marshal);
3031 return hr;
3034 if (!(apt = apartment_get_current_or_mta()))
3036 ERR("apartment not initialised\n");
3037 return CO_E_NOTINITIALIZED;
3040 manager = get_stub_manager_from_object(apt, object, FALSE);
3041 if (manager)
3043 stub_manager_disconnect(manager);
3044 /* Release stub manager twice, to remove the apartment reference. */
3045 stub_manager_int_release(manager);
3046 stub_manager_int_release(manager);
3049 /* Note: native is pretty broken here because it just silently
3050 * fails, without returning an appropriate error code if the object was
3051 * not found, making apps think that the object was disconnected, when
3052 * it actually wasn't */
3054 apartment_release(apt);
3055 return S_OK;
3058 /******************************************************************************
3059 * CoLockObjectExternal (combase.@)
3061 HRESULT WINAPI CoLockObjectExternal(IUnknown *object, BOOL lock, BOOL last_unlock_releases)
3063 struct stub_manager *stubmgr;
3064 struct apartment *apt;
3066 TRACE("%p, %d, %d\n", object, lock, last_unlock_releases);
3068 if (!(apt = apartment_get_current_or_mta()))
3070 ERR("apartment not initialised\n");
3071 return CO_E_NOTINITIALIZED;
3074 stubmgr = get_stub_manager_from_object(apt, object, lock);
3075 if (!stubmgr)
3077 WARN("stub object not found %p\n", object);
3078 /* Note: native is pretty broken here because it just silently
3079 * fails, without returning an appropriate error code, making apps
3080 * think that the object was disconnected, when it actually wasn't */
3081 apartment_release(apt);
3082 return S_OK;
3085 if (lock)
3086 stub_manager_ext_addref(stubmgr, 1, FALSE);
3087 else
3088 stub_manager_ext_release(stubmgr, 1, FALSE, last_unlock_releases);
3090 stub_manager_int_release(stubmgr);
3091 apartment_release(apt);
3092 return S_OK;
3095 /***********************************************************************
3096 * CoRegisterChannelHook (combase.@)
3098 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channel_hook)
3100 TRACE("%s, %p\n", debugstr_guid(guidExtension), channel_hook);
3102 return rpc_register_channel_hook(guidExtension, channel_hook);
3105 /***********************************************************************
3106 * CoDisableCallCancellation (combase.@)
3108 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
3110 struct tlsdata *tlsdata;
3111 HRESULT hr;
3113 TRACE("%p\n", reserved);
3115 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3116 return hr;
3118 if (!tlsdata->cancelcount)
3119 return CO_E_CANCEL_DISABLED;
3121 tlsdata->cancelcount--;
3123 return S_OK;
3126 /***********************************************************************
3127 * CoEnableCallCancellation (combase.@)
3129 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
3131 struct tlsdata *tlsdata;
3132 HRESULT hr;
3134 TRACE("%p\n", reserved);
3136 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
3137 return hr;
3139 tlsdata->cancelcount++;
3141 return S_OK;
3144 /***********************************************************************
3145 * CoGetCallerTID (combase.@)
3147 HRESULT WINAPI CoGetCallerTID(DWORD *tid)
3149 FIXME("stub!\n");
3150 return E_NOTIMPL;
3153 /***********************************************************************
3154 * CoIsHandlerConnected (combase.@)
3156 BOOL WINAPI CoIsHandlerConnected(IUnknown *object)
3158 FIXME("%p\n", object);
3160 return TRUE;
3163 /***********************************************************************
3164 * CoSuspendClassObjects (combase.@)
3166 HRESULT WINAPI CoSuspendClassObjects(void)
3168 FIXME("\n");
3170 return S_OK;
3173 /***********************************************************************
3174 * CoResumeClassObjects (combase.@)
3176 HRESULT WINAPI CoResumeClassObjects(void)
3178 FIXME("stub\n");
3180 return S_OK;
3183 /***********************************************************************
3184 * CoRegisterSurrogate (combase.@)
3186 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
3188 FIXME("%p stub\n", surrogate);
3190 return E_NOTIMPL;
3193 /***********************************************************************
3194 * CoRegisterSurrogateEx (combase.@)
3196 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
3198 FIXME("%s, %p stub\n", debugstr_guid(guid), reserved);
3200 return E_NOTIMPL;
3203 /***********************************************************************
3204 * DllMain (combase.@)
3206 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
3208 TRACE("%p 0x%x %p\n", hinstDLL, reason, reserved);
3210 switch (reason)
3212 case DLL_PROCESS_ATTACH:
3213 hProxyDll = hinstDLL;
3214 break;
3215 case DLL_PROCESS_DETACH:
3216 com_revoke_local_servers();
3217 if (reserved) break;
3218 apartment_global_cleanup();
3219 DeleteCriticalSection(&registered_classes_cs);
3220 rpc_unregister_channel_hooks();
3221 break;
3222 case DLL_THREAD_DETACH:
3223 com_cleanup_tlsdata();
3224 break;
3227 return TRUE;