combase: Move CoFreeUnusedLibraries().
[wine.git] / dlls / combase / combase.c
blob5752d90d5cc548fca11e3eea897ffb274719ba94
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 "oleauto.h"
28 #include "winternl.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ole);
35 #define CHARS_IN_GUID 39
37 struct comclassredirect_data
39 ULONG size;
40 ULONG flags;
41 DWORD model;
42 GUID clsid;
43 GUID alias;
44 GUID clsid2;
45 GUID tlbid;
46 ULONG name_len;
47 ULONG name_offset;
48 ULONG progid_len;
49 ULONG progid_offset;
50 ULONG clrdata_len;
51 ULONG clrdata_offset;
52 DWORD miscstatus;
53 DWORD miscstatuscontent;
54 DWORD miscstatusthumbnail;
55 DWORD miscstatusicon;
56 DWORD miscstatusdocprint;
59 struct progidredirect_data
61 ULONG size;
62 DWORD reserved;
63 ULONG clsid_offset;
66 static NTSTATUS create_key(HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr)
68 NTSTATUS status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
70 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
72 HANDLE subkey, root = attr->RootDirectory;
73 WCHAR *buffer = attr->ObjectName->Buffer;
74 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
75 UNICODE_STRING str;
77 while (i < len && buffer[i] != '\\') i++;
78 if (i == len) return status;
80 attrs = attr->Attributes;
81 attr->ObjectName = &str;
83 while (i < len)
85 str.Buffer = buffer + pos;
86 str.Length = (i - pos) * sizeof(WCHAR);
87 status = NtCreateKey(&subkey, access, attr, 0, NULL, 0, NULL);
88 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
89 if (status) return status;
90 attr->RootDirectory = subkey;
91 while (i < len && buffer[i] == '\\') i++;
92 pos = i;
93 while (i < len && buffer[i] != '\\') i++;
95 str.Buffer = buffer + pos;
96 str.Length = (i - pos) * sizeof(WCHAR);
97 attr->Attributes = attrs;
98 status = NtCreateKey((HANDLE *)retkey, access, attr, 0, NULL, 0, NULL);
99 if (attr->RootDirectory != root) NtClose(attr->RootDirectory);
101 return status;
104 static HKEY classes_root_hkey;
106 static HKEY create_classes_root_hkey(DWORD access)
108 HKEY hkey, ret = 0;
109 OBJECT_ATTRIBUTES attr;
110 UNICODE_STRING name;
112 attr.Length = sizeof(attr);
113 attr.RootDirectory = 0;
114 attr.ObjectName = &name;
115 attr.Attributes = 0;
116 attr.SecurityDescriptor = NULL;
117 attr.SecurityQualityOfService = NULL;
118 RtlInitUnicodeString(&name, L"\\Registry\\Machine\\Software\\Classes");
120 if (create_key( &hkey, access, &attr )) return 0;
121 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
123 if (!(access & KEY_WOW64_64KEY))
125 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
126 ret = hkey;
127 else
128 NtClose( hkey ); /* somebody beat us to it */
130 else
131 ret = hkey;
132 return ret;
135 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access);
137 static LSTATUS create_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
139 OBJECT_ATTRIBUTES attr;
140 UNICODE_STRING nameW;
142 if (!(hkey = get_classes_root_hkey(hkey, access)))
143 return ERROR_INVALID_HANDLE;
145 attr.Length = sizeof(attr);
146 attr.RootDirectory = hkey;
147 attr.ObjectName = &nameW;
148 attr.Attributes = 0;
149 attr.SecurityDescriptor = NULL;
150 attr.SecurityQualityOfService = NULL;
151 RtlInitUnicodeString( &nameW, name );
153 return RtlNtStatusToDosError(create_key(retkey, access, &attr));
156 static HKEY get_classes_root_hkey(HKEY hkey, REGSAM access)
158 HKEY ret = hkey;
159 const BOOL is_win64 = sizeof(void*) > sizeof(int);
160 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
162 if (hkey == HKEY_CLASSES_ROOT &&
163 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
164 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
165 if (force_wow32 && ret && ret == classes_root_hkey)
167 access &= ~KEY_WOW64_32KEY;
168 if (create_classes_key(classes_root_hkey, L"Wow6432Node", access, &hkey))
169 return 0;
170 ret = hkey;
173 return ret;
176 static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
178 OBJECT_ATTRIBUTES attr;
179 UNICODE_STRING nameW;
181 if (!(hkey = get_classes_root_hkey(hkey, access)))
182 return ERROR_INVALID_HANDLE;
184 attr.Length = sizeof(attr);
185 attr.RootDirectory = hkey;
186 attr.ObjectName = &nameW;
187 attr.Attributes = 0;
188 attr.SecurityDescriptor = NULL;
189 attr.SecurityQualityOfService = NULL;
190 RtlInitUnicodeString( &nameW, name );
192 return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
195 static HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
197 static const WCHAR clsidW[] = L"CLSID\\";
198 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
199 LONG res;
200 HKEY key;
202 lstrcpyW(path, clsidW);
203 StringFromGUID2(clsid, path + lstrlenW(clsidW), CHARS_IN_GUID);
204 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
205 if (res == ERROR_FILE_NOT_FOUND)
206 return REGDB_E_CLASSNOTREG;
207 else if (res != ERROR_SUCCESS)
208 return REGDB_E_READREGDB;
210 if (!keyname)
212 *subkey = key;
213 return S_OK;
216 res = open_classes_key(key, keyname, access, subkey);
217 RegCloseKey(key);
218 if (res == ERROR_FILE_NOT_FOUND)
219 return REGDB_E_KEYMISSING;
220 else if (res != ERROR_SUCCESS)
221 return REGDB_E_READREGDB;
223 return S_OK;
226 /***********************************************************************
227 * FreePropVariantArray (combase.@)
229 HRESULT WINAPI FreePropVariantArray(ULONG count, PROPVARIANT *rgvars)
231 ULONG i;
233 TRACE("%u, %p.\n", count, rgvars);
235 if (!rgvars)
236 return E_INVALIDARG;
238 for (i = 0; i < count; ++i)
239 PropVariantClear(&rgvars[i]);
241 return S_OK;
244 static HRESULT propvar_validatetype(VARTYPE vt)
246 switch (vt)
248 case VT_EMPTY:
249 case VT_NULL:
250 case VT_I1:
251 case VT_I2:
252 case VT_I4:
253 case VT_I8:
254 case VT_R4:
255 case VT_R8:
256 case VT_CY:
257 case VT_DATE:
258 case VT_BSTR:
259 case VT_ERROR:
260 case VT_BOOL:
261 case VT_DECIMAL:
262 case VT_UI1:
263 case VT_UI2:
264 case VT_UI4:
265 case VT_UI8:
266 case VT_INT:
267 case VT_UINT:
268 case VT_LPSTR:
269 case VT_LPWSTR:
270 case VT_FILETIME:
271 case VT_BLOB:
272 case VT_DISPATCH:
273 case VT_UNKNOWN:
274 case VT_STREAM:
275 case VT_STORAGE:
276 case VT_STREAMED_OBJECT:
277 case VT_STORED_OBJECT:
278 case VT_BLOB_OBJECT:
279 case VT_CF:
280 case VT_CLSID:
281 case VT_I1|VT_VECTOR:
282 case VT_I2|VT_VECTOR:
283 case VT_I4|VT_VECTOR:
284 case VT_I8|VT_VECTOR:
285 case VT_R4|VT_VECTOR:
286 case VT_R8|VT_VECTOR:
287 case VT_CY|VT_VECTOR:
288 case VT_DATE|VT_VECTOR:
289 case VT_BSTR|VT_VECTOR:
290 case VT_ERROR|VT_VECTOR:
291 case VT_BOOL|VT_VECTOR:
292 case VT_VARIANT|VT_VECTOR:
293 case VT_UI1|VT_VECTOR:
294 case VT_UI2|VT_VECTOR:
295 case VT_UI4|VT_VECTOR:
296 case VT_UI8|VT_VECTOR:
297 case VT_LPSTR|VT_VECTOR:
298 case VT_LPWSTR|VT_VECTOR:
299 case VT_FILETIME|VT_VECTOR:
300 case VT_CF|VT_VECTOR:
301 case VT_CLSID|VT_VECTOR:
302 case VT_ARRAY|VT_I1:
303 case VT_ARRAY|VT_UI1:
304 case VT_ARRAY|VT_I2:
305 case VT_ARRAY|VT_UI2:
306 case VT_ARRAY|VT_I4:
307 case VT_ARRAY|VT_UI4:
308 case VT_ARRAY|VT_INT:
309 case VT_ARRAY|VT_UINT:
310 case VT_ARRAY|VT_R4:
311 case VT_ARRAY|VT_R8:
312 case VT_ARRAY|VT_CY:
313 case VT_ARRAY|VT_DATE:
314 case VT_ARRAY|VT_BSTR:
315 case VT_ARRAY|VT_BOOL:
316 case VT_ARRAY|VT_DECIMAL:
317 case VT_ARRAY|VT_DISPATCH:
318 case VT_ARRAY|VT_UNKNOWN:
319 case VT_ARRAY|VT_ERROR:
320 case VT_ARRAY|VT_VARIANT:
321 return S_OK;
323 WARN("Bad type %d\n", vt);
324 return STG_E_INVALIDPARAMETER;
327 static void propvar_free_cf_array(ULONG count, CLIPDATA *data)
329 ULONG i;
330 for (i = 0; i < count; ++i)
331 CoTaskMemFree(data[i].pClipData);
334 /***********************************************************************
335 * PropVariantClear (combase.@)
337 HRESULT WINAPI PropVariantClear(PROPVARIANT *pvar)
339 HRESULT hr;
341 TRACE("%p.\n", pvar);
343 if (!pvar)
344 return S_OK;
346 hr = propvar_validatetype(pvar->vt);
347 if (FAILED(hr))
349 memset(pvar, 0, sizeof(*pvar));
350 return hr;
353 switch (pvar->vt)
355 case VT_EMPTY:
356 case VT_NULL:
357 case VT_I1:
358 case VT_I2:
359 case VT_I4:
360 case VT_I8:
361 case VT_R4:
362 case VT_R8:
363 case VT_CY:
364 case VT_DATE:
365 case VT_ERROR:
366 case VT_BOOL:
367 case VT_DECIMAL:
368 case VT_UI1:
369 case VT_UI2:
370 case VT_UI4:
371 case VT_UI8:
372 case VT_INT:
373 case VT_UINT:
374 case VT_FILETIME:
375 break;
376 case VT_DISPATCH:
377 case VT_UNKNOWN:
378 case VT_STREAM:
379 case VT_STREAMED_OBJECT:
380 case VT_STORAGE:
381 case VT_STORED_OBJECT:
382 if (pvar->u.pStream)
383 IStream_Release(pvar->u.pStream);
384 break;
385 case VT_CLSID:
386 case VT_LPSTR:
387 case VT_LPWSTR:
388 /* pick an arbitrary typed pointer - we don't care about the type
389 * as we are just freeing it */
390 CoTaskMemFree(pvar->u.puuid);
391 break;
392 case VT_BLOB:
393 case VT_BLOB_OBJECT:
394 CoTaskMemFree(pvar->u.blob.pBlobData);
395 break;
396 case VT_BSTR:
397 SysFreeString(pvar->u.bstrVal);
398 break;
399 case VT_CF:
400 if (pvar->u.pclipdata)
402 propvar_free_cf_array(1, pvar->u.pclipdata);
403 CoTaskMemFree(pvar->u.pclipdata);
405 break;
406 default:
407 if (pvar->vt & VT_VECTOR)
409 ULONG i;
411 switch (pvar->vt & ~VT_VECTOR)
413 case VT_VARIANT:
414 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
415 break;
416 case VT_CF:
417 propvar_free_cf_array(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
418 break;
419 case VT_BSTR:
420 for (i = 0; i < pvar->u.cabstr.cElems; i++)
421 SysFreeString(pvar->u.cabstr.pElems[i]);
422 break;
423 case VT_LPSTR:
424 for (i = 0; i < pvar->u.calpstr.cElems; i++)
425 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
426 break;
427 case VT_LPWSTR:
428 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
429 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
430 break;
432 if (pvar->vt & ~VT_VECTOR)
434 /* pick an arbitrary VT_VECTOR structure - they all have the same
435 * memory layout */
436 CoTaskMemFree(pvar->u.capropvar.pElems);
439 else if (pvar->vt & VT_ARRAY)
440 hr = SafeArrayDestroy(pvar->u.parray);
441 else
443 WARN("Invalid/unsupported type %d\n", pvar->vt);
444 hr = STG_E_INVALIDPARAMETER;
448 memset(pvar, 0, sizeof(*pvar));
449 return hr;
452 /***********************************************************************
453 * PropVariantCopy (combase.@)
455 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, const PROPVARIANT *pvarSrc)
457 ULONG len;
458 HRESULT hr;
460 TRACE("%p, %p vt %04x.\n", pvarDest, pvarSrc, pvarSrc->vt);
462 hr = propvar_validatetype(pvarSrc->vt);
463 if (FAILED(hr))
464 return DISP_E_BADVARTYPE;
466 /* this will deal with most cases */
467 *pvarDest = *pvarSrc;
469 switch (pvarSrc->vt)
471 case VT_EMPTY:
472 case VT_NULL:
473 case VT_I1:
474 case VT_UI1:
475 case VT_I2:
476 case VT_UI2:
477 case VT_BOOL:
478 case VT_DECIMAL:
479 case VT_I4:
480 case VT_UI4:
481 case VT_R4:
482 case VT_ERROR:
483 case VT_I8:
484 case VT_UI8:
485 case VT_INT:
486 case VT_UINT:
487 case VT_R8:
488 case VT_CY:
489 case VT_DATE:
490 case VT_FILETIME:
491 break;
492 case VT_DISPATCH:
493 case VT_UNKNOWN:
494 case VT_STREAM:
495 case VT_STREAMED_OBJECT:
496 case VT_STORAGE:
497 case VT_STORED_OBJECT:
498 if (pvarDest->u.pStream)
499 IStream_AddRef(pvarDest->u.pStream);
500 break;
501 case VT_CLSID:
502 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
503 *pvarDest->u.puuid = *pvarSrc->u.puuid;
504 break;
505 case VT_LPSTR:
506 if (pvarSrc->u.pszVal)
508 len = strlen(pvarSrc->u.pszVal);
509 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
510 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
512 break;
513 case VT_LPWSTR:
514 if (pvarSrc->u.pwszVal)
516 len = lstrlenW(pvarSrc->u.pwszVal);
517 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
518 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
520 break;
521 case VT_BLOB:
522 case VT_BLOB_OBJECT:
523 if (pvarSrc->u.blob.pBlobData)
525 len = pvarSrc->u.blob.cbSize;
526 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
527 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
529 break;
530 case VT_BSTR:
531 pvarDest->u.bstrVal = SysAllocString(pvarSrc->u.bstrVal);
532 break;
533 case VT_CF:
534 if (pvarSrc->u.pclipdata)
536 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
537 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
538 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
539 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
540 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
541 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
543 break;
544 default:
545 if (pvarSrc->vt & VT_VECTOR)
547 int elemSize;
548 ULONG i;
550 switch (pvarSrc->vt & ~VT_VECTOR)
552 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
553 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
554 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
555 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
556 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
557 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
558 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
559 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
560 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
561 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
562 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
563 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
564 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
565 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
566 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
567 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
568 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
569 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
570 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
571 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
572 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
574 default:
575 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
576 return E_INVALIDARG;
578 len = pvarSrc->u.capropvar.cElems;
579 pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
580 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
582 for (i = 0; i < len; i++)
583 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
585 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
587 FIXME("Copy clipformats\n");
589 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
591 for (i = 0; i < len; i++)
592 pvarDest->u.cabstr.pElems[i] = SysAllocString(pvarSrc->u.cabstr.pElems[i]);
594 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
596 size_t strLen;
597 for (i = 0; i < len; i++)
599 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
600 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
601 memcpy(pvarDest->u.calpstr.pElems[i],
602 pvarSrc->u.calpstr.pElems[i], strLen);
605 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
607 size_t strLen;
608 for (i = 0; i < len; i++)
610 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
611 sizeof(WCHAR);
612 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
613 memcpy(pvarDest->u.calpstr.pElems[i],
614 pvarSrc->u.calpstr.pElems[i], strLen);
617 else
618 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
620 else if (pvarSrc->vt & VT_ARRAY)
622 pvarDest->u.uhVal.QuadPart = 0;
623 return SafeArrayCopy(pvarSrc->u.parray, &pvarDest->u.parray);
625 else
626 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
629 return S_OK;
632 /***********************************************************************
633 * CoFileTimeNow (combase.@)
635 HRESULT WINAPI CoFileTimeNow(FILETIME *filetime)
637 GetSystemTimeAsFileTime(filetime);
638 return S_OK;
641 /******************************************************************************
642 * CoCreateGuid (combase.@)
644 HRESULT WINAPI CoCreateGuid(GUID *guid)
646 RPC_STATUS status;
648 if (!guid) return E_INVALIDARG;
650 status = UuidCreate(guid);
651 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
652 return HRESULT_FROM_WIN32(status);
655 /******************************************************************************
656 * CoQueryProxyBlanket (combase.@)
658 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *proxy, DWORD *authn_service,
659 DWORD *authz_service, OLECHAR **servername, DWORD *authn_level,
660 DWORD *imp_level, void **auth_info, DWORD *capabilities)
662 IClientSecurity *client_security;
663 HRESULT hr;
665 TRACE("%p, %p, %p, %p, %p, %p, %p, %p.\n", proxy, authn_service, authz_service, servername, authn_level, imp_level,
666 auth_info, capabilities);
668 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
669 if (SUCCEEDED(hr))
671 hr = IClientSecurity_QueryBlanket(client_security, proxy, authn_service, authz_service, servername,
672 authn_level, imp_level, auth_info, capabilities);
673 IClientSecurity_Release(client_security);
676 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
677 return hr;
680 /******************************************************************************
681 * CoSetProxyBlanket (combase.@)
683 HRESULT WINAPI CoSetProxyBlanket(IUnknown *proxy, DWORD authn_service, DWORD authz_service,
684 OLECHAR *servername, DWORD authn_level, DWORD imp_level, void *auth_info, DWORD capabilities)
686 IClientSecurity *client_security;
687 HRESULT hr;
689 TRACE("%p, %u, %u, %p, %u, %u, %p, %#x.\n", proxy, authn_service, authz_service, servername,
690 authn_level, imp_level, auth_info, capabilities);
692 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
693 if (SUCCEEDED(hr))
695 hr = IClientSecurity_SetBlanket(client_security, proxy, authn_service, authz_service, servername, authn_level,
696 imp_level, auth_info, capabilities);
697 IClientSecurity_Release(client_security);
700 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
701 return hr;
704 /***********************************************************************
705 * CoCopyProxy (combase.@)
707 HRESULT WINAPI CoCopyProxy(IUnknown *proxy, IUnknown **proxy_copy)
709 IClientSecurity *client_security;
710 HRESULT hr;
712 TRACE("%p, %p.\n", proxy, proxy_copy);
714 hr = IUnknown_QueryInterface(proxy, &IID_IClientSecurity, (void **)&client_security);
715 if (SUCCEEDED(hr))
717 hr = IClientSecurity_CopyProxy(client_security, proxy, proxy_copy);
718 IClientSecurity_Release(client_security);
721 if (FAILED(hr)) ERR("-- failed with %#x.\n", hr);
722 return hr;
725 /***********************************************************************
726 * CoQueryClientBlanket (combase.@)
728 HRESULT WINAPI CoQueryClientBlanket(DWORD *authn_service, DWORD *authz_service, OLECHAR **servername,
729 DWORD *authn_level, DWORD *imp_level, RPC_AUTHZ_HANDLE *privs, DWORD *capabilities)
731 IServerSecurity *server_security;
732 HRESULT hr;
734 TRACE("%p, %p, %p, %p, %p, %p, %p.\n", authn_service, authz_service, servername, authn_level, imp_level,
735 privs, capabilities);
737 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
738 if (SUCCEEDED(hr))
740 hr = IServerSecurity_QueryBlanket(server_security, authn_service, authz_service, servername, authn_level,
741 imp_level, privs, capabilities);
742 IServerSecurity_Release(server_security);
745 return hr;
748 /***********************************************************************
749 * CoImpersonateClient (combase.@)
751 HRESULT WINAPI CoImpersonateClient(void)
753 IServerSecurity *server_security;
754 HRESULT hr;
756 TRACE("\n");
758 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
759 if (SUCCEEDED(hr))
761 hr = IServerSecurity_ImpersonateClient(server_security);
762 IServerSecurity_Release(server_security);
765 return hr;
768 /***********************************************************************
769 * CoRevertToSelf (combase.@)
771 HRESULT WINAPI CoRevertToSelf(void)
773 IServerSecurity *server_security;
774 HRESULT hr;
776 TRACE("\n");
778 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&server_security);
779 if (SUCCEEDED(hr))
781 hr = IServerSecurity_RevertToSelf(server_security);
782 IServerSecurity_Release(server_security);
785 return hr;
788 /***********************************************************************
789 * CoGetObjectContext (combase.@)
791 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
793 IObjContext *context;
794 HRESULT hr;
796 TRACE("%s, %p.\n", debugstr_guid(riid), ppv);
798 *ppv = NULL;
799 hr = CoGetContextToken((ULONG_PTR *)&context);
800 if (FAILED(hr))
801 return hr;
803 return IObjContext_QueryInterface(context, riid, ppv);
806 /***********************************************************************
807 * CoGetDefaultContext (combase.@)
809 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, void **obj)
811 FIXME("%d, %s, %p stub\n", type, debugstr_guid(riid), obj);
813 return E_NOINTERFACE;
816 /***********************************************************************
817 * CoGetCallState (combase.@)
819 HRESULT WINAPI CoGetCallState(int arg1, ULONG *arg2)
821 FIXME("%d, %p.\n", arg1, arg2);
823 return E_NOTIMPL;
826 /***********************************************************************
827 * CoGetActivationState (combase.@)
829 HRESULT WINAPI CoGetActivationState(GUID guid, DWORD arg2, DWORD *arg3)
831 FIXME("%s, %x, %p.\n", debugstr_guid(&guid), arg2, arg3);
833 return E_NOTIMPL;
836 /******************************************************************************
837 * CoGetTreatAsClass (combase.@)
839 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, CLSID *clsidNew)
841 WCHAR buffW[CHARS_IN_GUID];
842 LONG len = sizeof(buffW);
843 HRESULT hr = S_OK;
844 HKEY hkey = NULL;
846 TRACE("%s, %p.\n", debugstr_guid(clsidOld), clsidNew);
848 if (!clsidOld || !clsidNew)
849 return E_INVALIDARG;
851 *clsidNew = *clsidOld;
853 hr = open_key_for_clsid(clsidOld, L"TreatAs", KEY_READ, &hkey);
854 if (FAILED(hr))
856 hr = S_FALSE;
857 goto done;
860 if (RegQueryValueW(hkey, NULL, buffW, &len))
862 hr = S_FALSE;
863 goto done;
866 hr = CLSIDFromString(buffW, clsidNew);
867 if (FAILED(hr))
868 ERR("Failed to get CLSID from string %s, hr %#x.\n", debugstr_w(buffW), hr);
869 done:
870 if (hkey) RegCloseKey(hkey);
871 return hr;
874 /******************************************************************************
875 * ProgIDFromCLSID (combase.@)
877 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
879 ACTCTX_SECTION_KEYED_DATA data;
880 LONG progidlen = 0;
881 HKEY hkey;
882 HRESULT hr;
884 if (!progid)
885 return E_INVALIDARG;
887 *progid = NULL;
889 data.cbSize = sizeof(data);
890 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
891 clsid, &data))
893 struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
894 if (comclass->progid_len)
896 WCHAR *ptrW;
898 *progid = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
899 if (!*progid) return E_OUTOFMEMORY;
901 ptrW = (WCHAR *)((BYTE *)comclass + comclass->progid_offset);
902 memcpy(*progid, ptrW, comclass->progid_len + sizeof(WCHAR));
903 return S_OK;
905 else
906 return REGDB_E_CLASSNOTREG;
909 hr = open_key_for_clsid(clsid, L"ProgID", KEY_READ, &hkey);
910 if (FAILED(hr))
911 return hr;
913 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
914 hr = REGDB_E_CLASSNOTREG;
916 if (hr == S_OK)
918 *progid = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
919 if (*progid)
921 if (RegQueryValueW(hkey, NULL, *progid, &progidlen))
923 hr = REGDB_E_CLASSNOTREG;
924 CoTaskMemFree(*progid);
925 *progid = NULL;
928 else
929 hr = E_OUTOFMEMORY;
932 RegCloseKey(hkey);
933 return hr;
936 static inline BOOL is_valid_hex(WCHAR c)
938 if (!(((c >= '0') && (c <= '9')) ||
939 ((c >= 'a') && (c <= 'f')) ||
940 ((c >= 'A') && (c <= 'F'))))
941 return FALSE;
942 return TRUE;
945 static const BYTE guid_conv_table[256] =
947 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
948 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
949 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
950 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
951 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
953 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
956 static BOOL guid_from_string(LPCWSTR s, GUID *id)
958 int i;
960 if (!s || s[0] != '{')
962 memset(id, 0, sizeof(*id));
963 if (!s) return TRUE;
964 return FALSE;
967 TRACE("%s -> %p\n", debugstr_w(s), id);
969 /* In form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
971 id->Data1 = 0;
972 for (i = 1; i < 9; ++i)
974 if (!is_valid_hex(s[i])) return FALSE;
975 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
977 if (s[9] != '-') return FALSE;
979 id->Data2 = 0;
980 for (i = 10; i < 14; ++i)
982 if (!is_valid_hex(s[i])) return FALSE;
983 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
985 if (s[14] != '-') return FALSE;
987 id->Data3 = 0;
988 for (i = 15; i < 19; ++i)
990 if (!is_valid_hex(s[i])) return FALSE;
991 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
993 if (s[19] != '-') return FALSE;
995 for (i = 20; i < 37; i += 2)
997 if (i == 24)
999 if (s[i] != '-') return FALSE;
1000 i++;
1002 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i + 1])) return FALSE;
1003 id->Data4[(i - 20) / 2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i + 1]];
1006 if (s[37] == '}' && s[38] == '\0')
1007 return TRUE;
1009 return FALSE;
1012 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
1014 WCHAR buf2[CHARS_IN_GUID];
1015 LONG buf2len = sizeof(buf2);
1016 HKEY xhkey;
1017 WCHAR *buf;
1019 memset(clsid, 0, sizeof(*clsid));
1020 buf = heap_alloc((lstrlenW(progid) + 8) * sizeof(WCHAR));
1021 if (!buf) return E_OUTOFMEMORY;
1023 lstrcpyW(buf, progid);
1024 lstrcatW(buf, L"\\CLSID");
1025 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
1027 heap_free(buf);
1028 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1029 return CO_E_CLASSSTRING;
1031 heap_free(buf);
1033 if (RegQueryValueW(xhkey, NULL, buf2, &buf2len))
1035 RegCloseKey(xhkey);
1036 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1037 return CO_E_CLASSSTRING;
1039 RegCloseKey(xhkey);
1040 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
1043 /******************************************************************************
1044 * CLSIDFromProgID (combase.@)
1046 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
1048 ACTCTX_SECTION_KEYED_DATA data;
1050 if (!progid || !clsid)
1051 return E_INVALIDARG;
1053 data.cbSize = sizeof(data);
1054 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
1055 progid, &data))
1057 struct progidredirect_data *progiddata = (struct progidredirect_data *)data.lpData;
1058 CLSID *alias = (CLSID *)((BYTE *)data.lpSectionBase + progiddata->clsid_offset);
1059 *clsid = *alias;
1060 return S_OK;
1063 return clsid_from_string_reg(progid, clsid);
1066 /******************************************************************************
1067 * CLSIDFromProgIDEx (combase.@)
1069 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, CLSID *clsid)
1071 FIXME("%s, %p: semi-stub\n", debugstr_w(progid), clsid);
1073 return CLSIDFromProgID(progid, clsid);
1076 /******************************************************************************
1077 * CLSIDFromString (combase.@)
1079 HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid)
1081 CLSID tmp_id;
1082 HRESULT hr;
1084 if (!clsid)
1085 return E_INVALIDARG;
1087 if (guid_from_string(str, clsid))
1088 return S_OK;
1090 /* It appears a ProgID is also valid */
1091 hr = clsid_from_string_reg(str, &tmp_id);
1092 if (SUCCEEDED(hr))
1093 *clsid = tmp_id;
1095 return hr;
1098 /******************************************************************************
1099 * IIDFromString (combase.@)
1101 HRESULT WINAPI IIDFromString(LPCOLESTR str, IID *iid)
1103 TRACE("%s, %p\n", debugstr_w(str), iid);
1105 if (!str)
1107 memset(iid, 0, sizeof(*iid));
1108 return S_OK;
1111 /* length mismatch is a special case */
1112 if (lstrlenW(str) + 1 != CHARS_IN_GUID)
1113 return E_INVALIDARG;
1115 if (str[0] != '{')
1116 return CO_E_IIDSTRING;
1118 return guid_from_string(str, iid) ? S_OK : CO_E_IIDSTRING;
1121 /******************************************************************************
1122 * StringFromCLSID (combase.@)
1124 HRESULT WINAPI StringFromCLSID(REFCLSID clsid, LPOLESTR *str)
1126 if (!(*str = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
1127 StringFromGUID2(clsid, *str, CHARS_IN_GUID);
1128 return S_OK;
1131 /******************************************************************************
1132 * StringFromGUID2 (combase.@)
1134 INT WINAPI StringFromGUID2(REFGUID guid, LPOLESTR str, INT cmax)
1136 if (!guid || cmax < CHARS_IN_GUID) return 0;
1137 swprintf(str, CHARS_IN_GUID, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid->Data1,
1138 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1139 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1140 return CHARS_IN_GUID;
1143 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
1145 ULONG i;
1147 for (i = 0; i < count; i++)
1149 mqi[i].pItf = NULL;
1150 mqi[i].hr = hr;
1154 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
1156 ULONG index = 0, fetched = 0;
1158 if (include_unk)
1160 mqi[0].hr = S_OK;
1161 mqi[0].pItf = unk;
1162 index = fetched = 1;
1165 for (; index < count; index++)
1167 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void **)&mqi[index].pItf);
1168 if (mqi[index].hr == S_OK)
1169 fetched++;
1172 if (!include_unk)
1173 IUnknown_Release(unk);
1175 if (fetched == 0)
1176 return E_NOINTERFACE;
1178 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
1181 /***********************************************************************
1182 * CoGetInstanceFromFile (combase.@)
1184 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(COSERVERINFO *server_info, CLSID *rclsid,
1185 IUnknown *outer, DWORD cls_context, DWORD grfmode, OLECHAR *filename, DWORD count,
1186 MULTI_QI *results)
1188 IPersistFile *pf = NULL;
1189 IUnknown *obj = NULL;
1190 CLSID clsid;
1191 HRESULT hr;
1193 if (!count || !results)
1194 return E_INVALIDARG;
1196 if (server_info)
1197 FIXME("() non-NULL server_info not supported\n");
1199 init_multi_qi(count, results, E_NOINTERFACE);
1201 if (!rclsid)
1203 hr = GetClassFile(filename, &clsid);
1204 if (FAILED(hr))
1206 ERR("Failed to get CLSID from a file.\n");
1207 return hr;
1210 rclsid = &clsid;
1213 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1214 if (hr != S_OK)
1216 init_multi_qi(count, results, hr);
1217 return hr;
1220 /* Init from file */
1221 hr = IUnknown_QueryInterface(obj, &IID_IPersistFile, (void **)&pf);
1222 if (FAILED(hr))
1224 init_multi_qi(count, results, hr);
1225 IUnknown_Release(obj);
1226 return hr;
1229 hr = IPersistFile_Load(pf, filename, grfmode);
1230 IPersistFile_Release(pf);
1231 if (SUCCEEDED(hr))
1232 return return_multi_qi(obj, count, results, FALSE);
1233 else
1235 init_multi_qi(count, results, hr);
1236 IUnknown_Release(obj);
1237 return hr;
1241 /***********************************************************************
1242 * CoGetInstanceFromIStorage (combase.@)
1244 HRESULT WINAPI CoGetInstanceFromIStorage(COSERVERINFO *server_info, CLSID *rclsid,
1245 IUnknown *outer, DWORD cls_context, IStorage *storage, DWORD count, MULTI_QI *results)
1247 IPersistStorage *ps = NULL;
1248 IUnknown *obj = NULL;
1249 STATSTG stat;
1250 HRESULT hr;
1252 if (!count || !results || !storage)
1253 return E_INVALIDARG;
1255 if (server_info)
1256 FIXME("() non-NULL server_info not supported\n");
1258 init_multi_qi(count, results, E_NOINTERFACE);
1260 if (!rclsid)
1262 memset(&stat.clsid, 0, sizeof(stat.clsid));
1263 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
1264 if (FAILED(hr))
1266 ERR("Failed to get CLSID from a storage.\n");
1267 return hr;
1270 rclsid = &stat.clsid;
1273 hr = CoCreateInstance(rclsid, outer, cls_context, &IID_IUnknown, (void **)&obj);
1274 if (hr != S_OK)
1275 return hr;
1277 /* Init from IStorage */
1278 hr = IUnknown_QueryInterface(obj, &IID_IPersistStorage, (void **)&ps);
1279 if (FAILED(hr))
1280 ERR("failed to get IPersistStorage\n");
1282 if (ps)
1284 IPersistStorage_Load(ps, storage);
1285 IPersistStorage_Release(ps);
1288 return return_multi_qi(obj, count, results, FALSE);
1291 /***********************************************************************
1292 * CoCreateInstance (combase.@)
1294 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1295 REFIID riid, void **obj)
1297 MULTI_QI multi_qi = { .pIID = riid };
1298 HRESULT hr;
1300 TRACE("%s, %p, %#x, %s, %p.\n", debugstr_guid(rclsid), outer, cls_context, debugstr_guid(riid), obj);
1302 if (!obj)
1303 return E_POINTER;
1305 hr = CoCreateInstanceEx(rclsid, outer, cls_context, NULL, 1, &multi_qi);
1306 *obj = multi_qi.pItf;
1307 return hr;
1310 /***********************************************************************
1311 * CoCreateInstanceEx (combase.@)
1313 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *outer, DWORD cls_context,
1314 COSERVERINFO *server_info, ULONG count, MULTI_QI *results)
1316 IClassFactory *factory;
1317 IUnknown *unk = NULL;
1318 CLSID clsid;
1319 HRESULT hr;
1321 TRACE("%s, %p, %#x, %p, %u, %p\n", debugstr_guid(rclsid), outer, cls_context, server_info, count, results);
1323 if (!count || !results)
1324 return E_INVALIDARG;
1326 if (server_info)
1327 FIXME("Server info is not supported.\n");
1329 init_multi_qi(count, results, E_NOINTERFACE);
1331 hr = CoGetTreatAsClass(rclsid, &clsid);
1332 if (FAILED(hr))
1333 clsid = *rclsid;
1335 hr = CoGetClassObject(&clsid, cls_context, NULL, &IID_IClassFactory, (void **)&factory);
1336 if (FAILED(hr))
1337 return hr;
1339 hr = IClassFactory_CreateInstance(factory, outer, results[0].pIID, (void **)&unk);
1340 IClassFactory_Release(factory);
1341 if (FAILED(hr))
1343 if (hr == CLASS_E_NOAGGREGATION && outer)
1344 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
1345 else
1346 FIXME("no instance created for interface %s of class %s, hr %#x.\n",
1347 debugstr_guid(results[0].pIID), debugstr_guid(&clsid), hr);
1348 return hr;
1351 return return_multi_qi(unk, count, results, TRUE);
1354 /***********************************************************************
1355 * CoFreeUnusedLibraries (combase.@)
1357 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
1359 CoFreeUnusedLibrariesEx(INFINITE, 0);