ReactOS  0.4.14-dev-614-gbfd8a84
compobj.c
Go to the documentation of this file.
1 /*
2  * COMPOBJ library
3  *
4  * Copyright 1995 Martin von Loewis
5  * Copyright 1998 Justin Bradford
6  * Copyright 1999 Francis Beaudet
7  * Copyright 1999 Sylvain St-Germain
8  * Copyright 2002 Marcus Meissner
9  * Copyright 2004 Mike Hearn
10  * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  *
26  * Note
27  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28  * Therefore do not test against COINIT_MULTITHREADED
29  *
30  * TODO list: (items bunched together depend on each other)
31  *
32  * - Implement the service control manager (in rpcss) to keep track
33  * of registered class objects: ISCM::ServerRegisterClsid et al
34  * - Implement the OXID resolver so we don't need magic endpoint names for
35  * clients and servers to meet up
36  *
37  */
38 
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <assert.h>
43 
44 #define COBJMACROS
45 #define NONAMELESSUNION
46 
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "winuser.h"
54 #define USE_COM_CONTEXT_DEF
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
58 #include "ctxtcall.h"
59 #include "dde.h"
60 #include "servprov.h"
61 
62 #ifndef __REACTOS__
63 #include "initguid.h"
64 #endif
65 #include "compobj_private.h"
66 #include "moniker.h"
67 
68 #include "wine/debug.h"
69 
71 
72 /****************************************************************************
73  * This section defines variables internal to the COM module.
74  */
75 
76 static APARTMENT *MTA; /* protected by csApartment */
77 static APARTMENT *MainApartment; /* the first STA apartment */
78 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
79 
82 {
83  0, 0, &csApartment,
85  0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
86 };
87 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
88 
90 {
96 };
97 
99 {
105 };
106 
108 {
112  BYTE res1[2];
129 };
130 
132 {
141 };
142 
144 {
148 };
149 
151 {
152  union
153  {
154  struct
155  {
157  void *section;
159  } actctx;
161  } u;
163 };
164 
166 {
167  struct list entry;
170 };
171 
173 
176 {
179  0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
180 };
181 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
182 
183 /*
184  * This is a marshallable object exposing registered local servers.
185  * IServiceProvider is used only because it happens meet requirements
186  * and already has proxy/stub code. If more functionality is needed,
187  * a custom interface may be used instead.
188  */
190 {
195 };
196 
197 /*
198  * This lock count counts the number of times CoInitialize is called. It is
199  * decreased every time CoUninitialize is called. When it hits 0, the COM
200  * libraries are freed
201  */
202 static LONG s_COMLockCount = 0;
203 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
205 
206 /*
207  * This linked list contains the list of registered class objects. These
208  * are mostly used to register the factories for out-of-proc servers of OLE
209  * objects.
210  *
211  * TODO: Make this data structure aware of inter-process communication. This
212  * means that parts of this will be exported to rpcss.
213  */
214 typedef struct tagRegisteredClass
215 {
216  struct list entry;
225 
227 
230 {
231  0, 0, &csRegisteredClassList,
233  0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
234 };
235 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
236 
238 {
239  switch (aspect)
240  {
241  case DVASPECT_CONTENT:
242  return MiscStatusContent;
243  case DVASPECT_THUMBNAIL:
244  return MiscStatusThumbnail;
245  case DVASPECT_ICON:
246  return MiscStatusIcon;
247  case DVASPECT_DOCPRINT:
248  return MiscStatusDocPrint;
249  default:
250  return MiscStatus;
251  };
252 }
253 
255 {
256  ACTCTX_SECTION_KEYED_DATA data;
257 
258  data.cbSize = sizeof(data);
259  if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
260  clsid, &data))
261  {
262  struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
263  enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
264 
265  if (!(comclass->miscmask & misc))
266  {
267  if (!(comclass->miscmask & MiscStatus))
268  {
269  *status = 0;
270  return TRUE;
271  }
272  misc = MiscStatus;
273  }
274 
275  switch (misc)
276  {
277  case MiscStatus:
278  *status = comclass->miscstatus;
279  break;
280  case MiscStatusIcon:
281  *status = comclass->miscstatusicon;
282  break;
283  case MiscStatusContent:
284  *status = comclass->miscstatuscontent;
285  break;
286  case MiscStatusThumbnail:
287  *status = comclass->miscstatusthumbnail;
288  break;
289  case MiscStatusDocPrint:
290  *status = comclass->miscstatusdocprint;
291  break;
292  default:
293  ;
294  };
295 
296  return TRUE;
297  }
298  else
299  return FALSE;
300 }
301 
302 /* wrapper for NtCreateKey that creates the key recursively if necessary */
304 {
305  NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
306 
308  {
309  HANDLE subkey, root = attr->RootDirectory;
310  WCHAR *buffer = attr->ObjectName->Buffer;
311  DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
313 
314  while (i < len && buffer[i] != '\\') i++;
315  if (i == len) return status;
316 
317  attrs = attr->Attributes;
318  attr->ObjectName = &str;
319 
320  while (i < len)
321  {
322  str.Buffer = buffer + pos;
323  str.Length = (i - pos) * sizeof(WCHAR);
324  status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
325  if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
326  if (status) return status;
327  attr->RootDirectory = subkey;
328  while (i < len && buffer[i] == '\\') i++;
329  pos = i;
330  while (i < len && buffer[i] != '\\') i++;
331  }
332  str.Buffer = buffer + pos;
333  str.Length = (i - pos) * sizeof(WCHAR);
334  attr->Attributes = attrs;
335  status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
336  if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
337  }
338  return status;
339 }
340 
341 #ifdef __REACTOS__
342 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
343 #else
344 static const WCHAR classes_rootW[] =
345  {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346  '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
347 #endif
348 
350 
351 /* create the special HKEY_CLASSES_ROOT key */
353 {
354  HKEY hkey, ret = 0;
357 
358  attr.Length = sizeof(attr);
359  attr.RootDirectory = 0;
360  attr.ObjectName = &name;
361  attr.Attributes = 0;
362  attr.SecurityDescriptor = NULL;
363  attr.SecurityQualityOfService = NULL;
365  if (create_key( &hkey, access, &attr )) return 0;
366  TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
367 
368  if (!(access & KEY_WOW64_64KEY))
369  {
370  if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
371  ret = hkey;
372  else
373  NtClose( hkey ); /* somebody beat us to it */
374  }
375  else
376  ret = hkey;
377  return ret;
378 }
379 
380 /* map the hkey from special root to normal key if necessary */
382 {
383  HKEY ret = hkey;
384  const BOOL is_win64 = sizeof(void*) > sizeof(int);
385  const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
386 
387  if (hkey == HKEY_CLASSES_ROOT &&
390  if (force_wow32 && ret && ret == classes_root_hkey)
391  {
392  static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
394  if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
395  return 0;
396  ret = hkey;
397  }
398 
399  return ret;
400 }
401 
403 {
406 
407  if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
408 
409  attr.Length = sizeof(attr);
410  attr.RootDirectory = hkey;
411  attr.ObjectName = &nameW;
412  attr.Attributes = 0;
413  attr.SecurityDescriptor = NULL;
414  attr.SecurityQualityOfService = NULL;
416 
417  return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
418 }
419 
421 {
424 
425  if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
426 
427  attr.Length = sizeof(attr);
428  attr.RootDirectory = hkey;
429  attr.ObjectName = &nameW;
430  attr.Attributes = 0;
431  attr.SecurityDescriptor = NULL;
432  attr.SecurityQualityOfService = NULL;
434 
435  return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
436 }
437 
438 /*****************************************************************************
439  * This section contains OpenDllList definitions
440  *
441  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
442  * other functions that do LoadLibrary _without_ giving back a HMODULE.
443  * Without this list these handles would never be freed.
444  *
445  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
446  * next unload-call but not before 600 sec.
447  */
448 
451 
452 typedef struct tagOpenDll
453 {
459  struct list entry;
460 } OpenDll;
461 
463 
466 {
467  0, 0, &csOpenDllList,
469  0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
470 };
471 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
472 
474 {
475  struct list entry;
479 };
480 
481 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0};
482 
484 
485 /*****************************************************************************
486  * This section contains OpenDllList implementation
487  */
488 
489 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
490 {
491  OpenDll *ptr;
492  OpenDll *ret = NULL;
495  {
496  if (!wcsicmp(library_name, ptr->library_name) &&
497  (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
498  {
499  ret = ptr;
500  break;
501  }
502  }
504  return ret;
505 }
506 
507 /* caller must ensure that library_name is not already in the open dll list */
509 {
510  OpenDll *entry;
511  int len;
512  HRESULT hr = S_OK;
516 
517  TRACE("%s\n", debugstr_w(library_name));
518 
519  *ret = COMPOBJ_DllList_Get(library_name);
520  if (*ret) return S_OK;
521 
522  /* do this outside the csOpenDllList to avoid creating a lock dependency on
523  * the loader lock */
525  if (!hLibrary)
526  {
527  ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
528  /* failure: DLL could not be loaded */
529  return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
530  }
531 
532  DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
533  /* Note: failing to find DllCanUnloadNow is not a failure */
534  DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
535  if (!DllGetClassObject)
536  {
537  /* failure: the dll did not export DllGetClassObject */
538  ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
540  return CO_E_DLLNOTFOUND;
541  }
542 
544 
545  *ret = COMPOBJ_DllList_Get(library_name);
546  if (*ret)
547  {
548  /* another caller to this function already added the dll while we
549  * weren't in the critical section */
551  }
552  else
553  {
554  len = lstrlenW(library_name);
555  entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
556  if (entry)
557  entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
558  if (entry && entry->library_name)
559  {
560  memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
561  entry->library = hLibrary;
562  entry->refs = 1;
563  entry->DllCanUnloadNow = DllCanUnloadNow;
564  entry->DllGetClassObject = DllGetClassObject;
565  list_add_tail(&openDllList, &entry->entry);
566  *ret = entry;
567  }
568  else
569  {
571  hr = E_OUTOFMEMORY;
573  }
574  }
575 
577 
578  return hr;
579 }
580 
581 /* pass FALSE for free_entry to release a reference without destroying the
582  * entry if it reaches zero or TRUE otherwise */
584 {
585  if (!InterlockedDecrement(&entry->refs) && free_entry)
586  {
588  list_remove(&entry->entry);
590 
591  TRACE("freeing %p\n", entry->library);
592  FreeLibrary(entry->library);
593 
594  HeapFree(GetProcessHeap(), 0, entry->library_name);
596  }
597 }
598 
599 /* frees memory associated with active dll list */
600 static void COMPOBJ_DllList_Free(void)
601 {
602  OpenDll *entry, *cursor2;
605  {
606  list_remove(&entry->entry);
607 
608  HeapFree(GetProcessHeap(), 0, entry->library_name);
610  }
613 }
614 
615 /******************************************************************************
616  * Manage apartments.
617  */
618 
619 static DWORD apartment_addref(struct apartment *apt)
620 {
621  DWORD refs = InterlockedIncrement(&apt->refs);
622  TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
623  return refs;
624 }
625 
626 /* allocates memory and fills in the necessary fields for a new apartment
627  * object. must be called inside apartment cs */
629 {
630  APARTMENT *apt;
631 
632  TRACE("creating new apartment, model=%d\n", model);
633 
634  apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
635  apt->tid = GetCurrentThreadId();
636 
637  list_init(&apt->proxies);
638  list_init(&apt->stubmgrs);
639  list_init(&apt->loaded_dlls);
640  apt->ipidc = 0;
641  apt->refs = 1;
642  apt->remunk_exported = FALSE;
643  apt->oidc = 1;
645  DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
646 
647  apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
648 
649  if (apt->multi_threaded)
650  {
651  /* FIXME: should be randomly generated by in an RPC call to rpcss */
652  apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
653  }
654  else
655  {
656  /* FIXME: should be randomly generated by in an RPC call to rpcss */
657  apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
658  }
659 
660  TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
661 
662  list_add_head(&apts, &apt->entry);
663 
664  return apt;
665 }
666 
667 /* gets and existing apartment if one exists or otherwise creates an apartment
668  * structure which stores OLE apartment-local information and stores a pointer
669  * to it in the thread-local storage */
671 {
672  APARTMENT *apt = COM_CurrentApt();
673 
674  if (!apt)
675  {
676  if (model & COINIT_APARTMENTTHREADED)
677  {
679 
680  apt = apartment_construct(model);
681  if (!MainApartment)
682  {
683  MainApartment = apt;
684  apt->main = TRUE;
685  TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
686  }
687 
689 
690  if (apt->main)
692  }
693  else
694  {
696 
697  /* The multi-threaded apartment (MTA) contains zero or more threads interacting
698  * with free threaded (ie thread safe) COM objects. There is only ever one MTA
699  * in a process */
700  if (MTA)
701  {
702  TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
704  }
705  else
706  MTA = apartment_construct(model);
707 
708  apt = MTA;
709 
711  }
712  COM_CurrentInfo()->apt = apt;
713  }
714 
715  return apt;
716 }
717 
718 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
719 {
720  return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
721 }
722 
723 /* gets the multi-threaded apartment if it exists. The caller must
724  * release the reference from the apartment as soon as the apartment pointer
725  * is no longer required. */
727 {
728  APARTMENT *apt;
729 
731 
732  if ((apt = MTA))
733  apartment_addref(apt);
734 
736 
737  return apt;
738 }
739 
740 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
741  * must free the returned apartment in either case. */
743 {
744  APARTMENT *apt = COM_CurrentApt();
745  if (apt)
746  {
747  apartment_addref(apt);
748  return apt;
749  }
750  return apartment_find_mta();
751 }
752 
754 {
755  list_remove(&curClass->entry);
756 
757  if (curClass->runContext & CLSCTX_LOCAL_SERVER)
759 
760  IUnknown_Release(curClass->classObject);
761  HeapFree(GetProcessHeap(), 0, curClass);
762 }
763 
764 static void COM_RevokeAllClasses(const struct apartment *apt)
765 {
766  RegisteredClass *curClass, *cursor;
767 
769 
771  {
772  if (curClass->apartment_id == apt->oxid)
774  }
775 
777 }
778 
779 static void revoke_registered_psclsids(void)
780 {
781  struct registered_psclsid *psclsid, *psclsid2;
782 
784 
786  {
787  list_remove(&psclsid->entry);
788  HeapFree(GetProcessHeap(), 0, psclsid);
789  }
790 
792 }
793 
794 /******************************************************************************
795  * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
796  */
797 
798 typedef struct ManualResetEvent {
803 } MREImpl;
804 
806 {
807  return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
808 }
809 
811 {
813 
814  TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
815 
816  if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
817  *ppv = &This->ISynchronize_iface;
818  }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
819  *ppv = &This->ISynchronizeHandle_iface;
820  }else {
821  ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
822  *ppv = NULL;
823  return E_NOINTERFACE;
824  }
825 
826  IUnknown_AddRef((IUnknown*)*ppv);
827  return S_OK;
828 }
829 
831 {
834  TRACE("%p - ref %d\n", This, ref);
835 
836  return ref;
837 }
838 
840 {
843  TRACE("%p - ref %d\n", This, ref);
844 
845  if(!ref)
846  {
847  CloseHandle(This->event);
849  }
850 
851  return ref;
852 }
853 
855 {
857  UINT index;
858  TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
859  return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
860 }
861 
863 {
865  TRACE("%p\n", This);
866  SetEvent(This->event);
867  return S_OK;
868 }
869 
871 {
873  TRACE("%p\n", This);
874  ResetEvent(This->event);
875  return S_OK;
876 }
877 
878 static ISynchronizeVtbl vt_ISynchronize = {
885 };
886 
888 {
889  return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
890 }
891 
893 {
895  return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
896 }
897 
899 {
901  return ISynchronize_AddRef(&This->ISynchronize_iface);
902 }
903 
905 {
907  return ISynchronize_Release(&This->ISynchronize_iface);
908 }
909 
911 {
913 
914  *ph = This->event;
915  return S_OK;
916 }
917 
918 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
923 };
924 
925 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
926 {
928  HRESULT hr;
929 
930  if(punkouter)
931  FIXME("Aggregation not implemented.\n");
932 
933  This->ref = 1;
934  This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
935  This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
936  This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
937 
938  hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
939  ISynchronize_Release(&This->ISynchronize_iface);
940  return hr;
941 }
942 
944 {
945  return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
946 }
947 
949 {
951 
952  TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
953 
954  if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
955  *ppv = &This->IServiceProvider_iface;
956  }else {
957  *ppv = NULL;
958  return E_NOINTERFACE;
959  }
960 
961  IUnknown_AddRef((IUnknown*)*ppv);
962  return S_OK;
963 }
964 
966 {
969 
970  TRACE("(%p) ref=%d\n", This, ref);
971 
972  return ref;
973 }
974 
976 {
979 
980  TRACE("(%p) ref=%d\n", This, ref);
981 
982  if(!ref) {
983  assert(!This->apt);
985  }
986 
987  return ref;
988 }
989 
991 {
993  APARTMENT *apt = COM_CurrentApt();
994  RegisteredClass *iter;
995  HRESULT hres = E_FAIL;
996 
997  TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
998 
999  if(!This->apt)
1000  return E_UNEXPECTED;
1001 
1003 
1005  if(iter->apartment_id == apt->oxid
1006  && (iter->runContext & CLSCTX_LOCAL_SERVER)
1007  && IsEqualGUID(&iter->classIdentifier, guid)) {
1008  hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1009  break;
1010  }
1011  }
1012 
1014 
1015  return hres;
1016 }
1017 
1018 static const IServiceProviderVtbl LocalServerVtbl = {
1023 };
1024 
1026 {
1027  HRESULT hres = S_OK;
1028 
1029  EnterCriticalSection(&apt->cs);
1030 
1031  if(!apt->local_server) {
1032  LocalServer *obj;
1033 
1034  obj = heap_alloc(sizeof(*obj));
1035  if(obj) {
1036  obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1037  obj->ref = 1;
1038  obj->apt = apt;
1039 
1040  hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1041  if(SUCCEEDED(hres)) {
1042  hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1043  MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1044  if(FAILED(hres))
1045  IStream_Release(obj->marshal_stream);
1046  }
1047 
1048  if(SUCCEEDED(hres))
1049  apt->local_server = obj;
1050  else
1051  heap_free(obj);
1052  }else {
1053  hres = E_OUTOFMEMORY;
1054  }
1055  }
1056 
1057  if(SUCCEEDED(hres))
1058  hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1059 
1060  LeaveCriticalSection(&apt->cs);
1061 
1062  if(FAILED(hres))
1063  ERR("Failed: %08x\n", hres);
1064  return hres;
1065 }
1066 
1067 /***********************************************************************
1068  * CoRevokeClassObject [OLE32.@]
1069  *
1070  * Removes a class object from the class registry.
1071  *
1072  * PARAMS
1073  * dwRegister [I] Cookie returned from CoRegisterClassObject().
1074  *
1075  * RETURNS
1076  * Success: S_OK.
1077  * Failure: HRESULT code.
1078  *
1079  * NOTES
1080  * Must be called from the same apartment that called CoRegisterClassObject(),
1081  * otherwise it will fail with RPC_E_WRONG_THREAD.
1082  *
1083  * SEE ALSO
1084  * CoRegisterClassObject
1085  */
1087  DWORD dwRegister)
1088 {
1090  RegisteredClass *curClass;
1091  APARTMENT *apt;
1092 
1093  TRACE("(%08x)\n",dwRegister);
1094 
1095  if (!(apt = apartment_get_current_or_mta()))
1096  {
1097  ERR("COM was not initialized\n");
1098  return CO_E_NOTINITIALIZED;
1099  }
1100 
1102 
1104  {
1105  /*
1106  * Check if we have a match on the cookie.
1107  */
1108  if (curClass->dwCookie == dwRegister)
1109  {
1110  if (curClass->apartment_id == apt->oxid)
1111  {
1113  hr = S_OK;
1114  }
1115  else
1116  {
1117  ERR("called from wrong apartment, should be called from %s\n",
1118  wine_dbgstr_longlong(curClass->apartment_id));
1120  }
1121  break;
1122  }
1123  }
1124 
1126  apartment_release(apt);
1127  return hr;
1128 }
1129 
1130 /* frees unused libraries loaded by apartment_getclassobject by calling the
1131  * DLL's DllCanUnloadNow entry point */
1133 {
1134  struct apartment_loaded_dll *entry, *next;
1135  EnterCriticalSection(&apt->cs);
1137  {
1138  if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1139  {
1140  DWORD real_delay = delay;
1141 
1142  if (real_delay == INFINITE)
1143  {
1144  /* DLLs that return multi-threaded objects aren't unloaded
1145  * straight away to cope for programs that have races between
1146  * last object destruction and threads in the DLLs that haven't
1147  * finished, despite DllCanUnloadNow returning S_OK */
1148  if (entry->multi_threaded)
1149  real_delay = 10 * 60 * 1000; /* 10 minutes */
1150  else
1151  real_delay = 0;
1152  }
1153 
1154  if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1155  {
1156  list_remove(&entry->entry);
1158  HeapFree(GetProcessHeap(), 0, entry);
1159  }
1160  else
1161  {
1162  entry->unload_time = GetTickCount() + real_delay;
1163  if (!entry->unload_time) entry->unload_time = 1;
1164  }
1165  }
1166  else if (entry->unload_time)
1167  entry->unload_time = 0;
1168  }
1169  LeaveCriticalSection(&apt->cs);
1170 }
1171 
1173 {
1174  DWORD ret;
1175 
1177 
1178  ret = InterlockedDecrement(&apt->refs);
1179  TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1180 
1181  if (apt->being_destroyed)
1182  {
1184  return ret;
1185  }
1186 
1187  /* destruction stuff that needs to happen under csApartment CS */
1188  if (ret == 0)
1189  {
1190  apt->being_destroyed = TRUE;
1191  if (apt == MTA) MTA = NULL;
1192  else if (apt == MainApartment) MainApartment = NULL;
1193  list_remove(&apt->entry);
1194  }
1195 
1197 
1198  if (ret == 0)
1199  {
1200  struct list *cursor, *cursor2;
1201 
1202  TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1203 
1204  if(apt->local_server) {
1207 
1208  memset(&zero, 0, sizeof(zero));
1209  IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1210  CoReleaseMarshalData(local_server->marshal_stream);
1211  IStream_Release(local_server->marshal_stream);
1212  local_server->marshal_stream = NULL;
1213 
1214  apt->local_server = NULL;
1215  local_server->apt = NULL;
1216  IServiceProvider_Release(&local_server->IServiceProvider_iface);
1217  }
1218 
1219  /* Release the references to the registered class objects */
1220  COM_RevokeAllClasses(apt);
1221 
1222  /* no locking is needed for this apartment, because no other thread
1223  * can access it at this point */
1224 
1226 
1227  if (apt->win) DestroyWindow(apt->win);
1228  if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1229 
1230  LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1231  {
1232  struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1233  /* release the implicit reference given by the fact that the
1234  * stub has external references (it must do since it is in the
1235  * stub manager list in the apartment and all non-apartment users
1236  * must have a ref on the apartment and so it cannot be destroyed).
1237  */
1238  stub_manager_int_release(stubmgr);
1239  }
1240 
1241  /* if this assert fires, then another thread took a reference to a
1242  * stub manager without taking a reference to the containing
1243  * apartment, which it must do. */
1245 
1246  if (apt->filter) IMessageFilter_Release(apt->filter);
1247 
1248  /* free as many unused libraries as possible... */
1250 
1251  /* ... and free the memory for the apartment loaded dll entry and
1252  * release the dll list reference without freeing the library for the
1253  * rest */
1254  while ((cursor = list_head(&apt->loaded_dlls)))
1255  {
1260  }
1261 
1263  DeleteCriticalSection(&apt->cs);
1264 
1265  HeapFree(GetProcessHeap(), 0, apt);
1266  }
1267 
1268  return ret;
1269 }
1270 
1271 /* The given OXID must be local to this process:
1272  *
1273  * The ref parameter is here mostly to ensure people remember that
1274  * they get one, you should normally take a ref for thread safety.
1275  */
1277 {
1278  APARTMENT *result = NULL;
1279  struct list *cursor;
1280 
1283  {
1284  struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1285  if (apt->oxid == oxid)
1286  {
1287  result = apt;
1288  if (ref) apartment_addref(result);
1289  break;
1290  }
1291  }
1293 
1294  return result;
1295 }
1296 
1297 /* gets the apartment which has a given creator thread ID. The caller must
1298  * release the reference from the apartment as soon as the apartment pointer
1299  * is no longer required. */
1301 {
1302  APARTMENT *result = NULL;
1303  struct list *cursor;
1304 
1307  {
1308  struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1309  if (apt->tid == tid)
1310  {
1311  result = apt;
1313  break;
1314  }
1315  }
1317 
1318  return result;
1319 }
1320 
1321 /* gets the main apartment if it exists. The caller must
1322  * release the reference from the apartment as soon as the apartment pointer
1323  * is no longer required. */
1325 {
1326  APARTMENT *result;
1327 
1329 
1332 
1334 
1335  return result;
1336 }
1337 
1338 /* gets the specified class object by loading the appropriate DLL, if
1339  * necessary and calls the DllGetClassObject function for the DLL */
1341  BOOL apartment_threaded,
1342  REFCLSID rclsid, REFIID riid, void **ppv)
1343 {
1344  static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1345  HRESULT hr = S_OK;
1346  BOOL found = FALSE;
1348 
1349  if (!wcsicmp(dllpath, wszOle32))
1350  {
1351  /* we don't need to control the lifetime of this dll, so use the local
1352  * implementation of DllGetClassObject directly */
1353  TRACE("calling ole32!DllGetClassObject\n");
1354  hr = DllGetClassObject(rclsid, riid, ppv);
1355 
1356  if (hr != S_OK)
1357  ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1358 
1359  return hr;
1360  }
1361 
1362  EnterCriticalSection(&apt->cs);
1363 
1366  {
1367  TRACE("found %s already loaded\n", debugstr_w(dllpath));
1368  found = TRUE;
1369  break;
1370  }
1371 
1372  if (!found)
1373  {
1375  if (!apartment_loaded_dll)
1376  hr = E_OUTOFMEMORY;
1377  if (SUCCEEDED(hr))
1378  {
1382  if (FAILED(hr))
1384  }
1385  if (SUCCEEDED(hr))
1386  {
1387  TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1389  }
1390  }
1391 
1392  LeaveCriticalSection(&apt->cs);
1393 
1394  if (SUCCEEDED(hr))
1395  {
1396  /* one component being multi-threaded overrides any number of
1397  * apartment-threaded components */
1398  if (!apartment_threaded)
1400 
1401  TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1402  /* OK: get the ClassObject */
1404 
1405  if (hr != S_OK)
1406  ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1407  }
1408 
1409  return hr;
1410 }
1411 
1412 /* Returns expanded dll path from the registry or activation context. */
1413 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1414 {
1415  DWORD ret;
1416 
1417  if (regdata->hkey)
1418  {
1419  DWORD keytype;
1420  WCHAR src[MAX_PATH];
1421  DWORD dwLength = dstlen * sizeof(WCHAR);
1422 
1423  if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1424  if (keytype == REG_EXPAND_SZ) {
1426  } else {
1427  const WCHAR *quote_start;
1428  quote_start = wcschr(src, '\"');
1429  if (quote_start) {
1430  const WCHAR *quote_end = wcschr(quote_start + 1, '\"');
1431  if (quote_end) {
1432  memmove(src, quote_start + 1,
1433  (quote_end - quote_start - 1) * sizeof(WCHAR));
1434  src[quote_end - quote_start - 1] = '\0';
1435  }
1436  }
1437  lstrcpynW(dst, src, dstlen);
1438  }
1439  }
1440  return !ret;
1441  }
1442  else
1443  {
1444  static const WCHAR dllW[] = {'.','d','l','l',0};
1445  ULONG_PTR cookie;
1446  WCHAR *nameW;
1447 
1448  *dst = 0;
1449  nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1450  ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1453  return *dst != 0;
1454  }
1455 }
1456 
1458 {
1460  CLSID clsid; /* clsid of object to marshal */
1461  IID iid; /* interface to marshal */
1462  HANDLE event; /* event signalling when ready for multi-threaded case */
1463  HRESULT hr; /* result for multi-threaded case */
1464  IStream *stream; /* stream that the object will be marshaled into */
1465  BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1466 };
1467 
1469  const struct host_object_params *params)
1470 {
1471  IUnknown *object;
1472  HRESULT hr;
1473  static const LARGE_INTEGER llZero;
1474  WCHAR dllpath[MAX_PATH+1];
1475 
1476  TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1477 
1479  {
1480  /* failure: CLSID is not found in registry */
1481  WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1482  return REGDB_E_CLASSNOTREG;
1483  }
1484 
1485  hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1486  &params->clsid, &params->iid, (void **)&object);
1487  if (FAILED(hr))
1488  return hr;
1489 
1490  hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1491  if (FAILED(hr))
1492  IUnknown_Release(object);
1493  IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1494 
1495  return hr;
1496 }
1497 
1499 {
1500  switch (msg)
1501  {
1502  case DM_EXECUTERPC:
1504  return 0;
1505  case DM_HOSTOBJECT:
1506  return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1507  default:
1508  return DefWindowProcW(hWnd, msg, wParam, lParam);
1509  }
1510 }
1511 
1513 {
1517 };
1518 
1519 /* thread for hosting an object to allow an object to appear to be created in
1520  * an apartment with an incompatible threading model */
1522 {
1523  struct host_thread_params *params = p;
1524  MSG msg;
1525  HRESULT hr;
1526  struct apartment *apt;
1527 
1528  TRACE("\n");
1529 
1530  hr = CoInitializeEx(NULL, params->threading_model);
1531  if (FAILED(hr)) return hr;
1532 
1533  apt = COM_CurrentApt();
1534  if (params->threading_model == COINIT_APARTMENTTHREADED)
1535  {
1537  params->apartment_hwnd = apartment_getwindow(apt);
1538  }
1539  else
1540  params->apartment_hwnd = NULL;
1541 
1542  /* force the message queue to be created before signaling parent thread */
1544 
1545  SetEvent(params->ready_event);
1546  params = NULL; /* can't touch params after here as it may be invalid */
1547 
1548  while (GetMessageW(&msg, NULL, 0, 0))
1549  {
1550  if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1551  {
1552  struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1553  obj_params->hr = apartment_hostobject(apt, obj_params);
1554  SetEvent(obj_params->event);
1555  }
1556  else
1557  {
1560  }
1561  }
1562 
1563  TRACE("exiting\n");
1564 
1565  CoUninitialize();
1566 
1567  return S_OK;
1568 }
1569 
1570 /* finds or creates a host apartment, creates the object inside it and returns
1571  * a proxy to it so that the object can be used in the apartment of the
1572  * caller of this function */
1574  struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1575  const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1576 {
1577  struct host_object_params params;
1578  HWND apartment_hwnd = NULL;
1579  DWORD apartment_tid = 0;
1580  HRESULT hr;
1581 
1582  if (!multi_threaded && main_apartment)
1583  {
1584  APARTMENT *host_apt = apartment_findmain();
1585  if (host_apt)
1586  {
1587  apartment_hwnd = apartment_getwindow(host_apt);
1588  apartment_release(host_apt);
1589  }
1590  }
1591 
1592  if (!apartment_hwnd)
1593  {
1594  EnterCriticalSection(&apt->cs);
1595 
1596  if (!apt->host_apt_tid)
1597  {
1598  struct host_thread_params thread_params;
1599  HANDLE handles[2];
1600  DWORD wait_value;
1601 
1602  thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1603  handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1604  thread_params.apartment_hwnd = NULL;
1605  handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1606  if (!handles[1])
1607  {
1608  CloseHandle(handles[0]);
1609  LeaveCriticalSection(&apt->cs);
1610  return E_OUTOFMEMORY;
1611  }
1612  wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1613  CloseHandle(handles[0]);
1614  CloseHandle(handles[1]);
1615  if (wait_value == WAIT_OBJECT_0)
1616  apt->host_apt_hwnd = thread_params.apartment_hwnd;
1617  else
1618  {
1619  LeaveCriticalSection(&apt->cs);
1620  return E_OUTOFMEMORY;
1621  }
1622  }
1623 
1624  if (multi_threaded || !main_apartment)
1625  {
1627  apartment_tid = apt->host_apt_tid;
1628  }
1629 
1630  LeaveCriticalSection(&apt->cs);
1631  }
1632 
1633  /* another thread may have become the main apartment in the time it took
1634  * us to create the thread for the host apartment */
1635  if (!apartment_hwnd && !multi_threaded && main_apartment)
1636  {
1637  APARTMENT *host_apt = apartment_findmain();
1638  if (host_apt)
1639  {
1640  apartment_hwnd = apartment_getwindow(host_apt);
1641  apartment_release(host_apt);
1642  }
1643  }
1644 
1645  params.regdata = *regdata;
1646  params.clsid = *rclsid;
1647  params.iid = *riid;
1648  hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1649  if (FAILED(hr))
1650  return hr;
1651  params.apartment_threaded = !multi_threaded;
1652  if (multi_threaded)
1653  {
1654  params.hr = S_OK;
1655  params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1656  if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1657  hr = E_OUTOFMEMORY;
1658  else
1659  {
1661  hr = params.hr;
1662  }
1663  CloseHandle(params.event);
1664  }
1665  else
1666  {
1667  if (!apartment_hwnd)
1668  {
1669  ERR("host apartment didn't create window\n");
1670  hr = E_OUTOFMEMORY;
1671  }
1672  else
1674  }
1675  if (SUCCEEDED(hr))
1676  hr = CoUnmarshalInterface(params.stream, riid, ppv);
1677  IStream_Release(params.stream);
1678  return hr;
1679 }
1680 
1681 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1682 {
1683  WNDCLASSW wclass;
1684 
1685  /* Dispatching to the correct thread in an apartment is done through
1686  * window messages rather than RPC transports. When an interface is
1687  * marshalled into another apartment in the same process, a window of the
1688  * following class is created. The *caller* of CoMarshalInterface (i.e., the
1689  * application) is responsible for pumping the message loop in that thread.
1690  * The WM_USER messages which point to the RPCs are then dispatched to
1691  * apartment_wndproc by the user's code from the apartment in which the
1692  * interface was unmarshalled.
1693  */
1694  memset(&wclass, 0, sizeof(wclass));
1695  wclass.lpfnWndProc = apartment_wndproc;
1696  wclass.hInstance = hProxyDll;
1697  wclass.lpszClassName = wszAptWinClass;
1698  apt_win_class = RegisterClassW(&wclass);
1699  return TRUE;
1700 }
1701 
1702 /* create a window for the apartment or return the current one if one has
1703  * already been created */
1705 {
1706  static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1707 
1708  if (apt->multi_threaded)
1709  return S_OK;
1710 
1711  if (!apt->win)
1712  {
1713  HWND hwnd;
1714 
1715  InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1716 
1717  hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1718  HWND_MESSAGE, 0, hProxyDll, NULL);
1719  if (!hwnd)
1720  {
1721  ERR("CreateWindow failed with error %d\n", GetLastError());
1722  return HRESULT_FROM_WIN32(GetLastError());
1723  }
1725  /* someone beat us to it */
1727  }
1728 
1729  return S_OK;
1730 }
1731 
1732 /* retrieves the window for the main- or apartment-threaded apartment */
1734 {
1735  assert(!apt->multi_threaded);
1736  return apt->win;
1737 }
1738 
1739 static void COM_TlsDestroy(void)
1740 {
1741  struct oletls *info = NtCurrentTeb()->ReservedForOle;
1742  if (info)
1743  {
1744  struct init_spy *cursor, *cursor2;
1745 
1746  if (info->apt) apartment_release(info->apt);
1747  if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1748  if (info->state) IUnknown_Release(info->state);
1749 
1750  LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
1751  {
1752  list_remove(&cursor->entry);
1753  if (cursor->spy) IInitializeSpy_Release(cursor->spy);
1754  heap_free(cursor);
1755  }
1756 
1757  if (info->context_token) IObjContext_Release(info->context_token);
1758 
1759  HeapFree(GetProcessHeap(), 0, info);
1760  NtCurrentTeb()->ReservedForOle = NULL;
1761  }
1762 }
1763 
1764 /******************************************************************************
1765  * CoBuildVersion [OLE32.@]
1766  *
1767  * Gets the build version of the DLL.
1768  *
1769  * PARAMS
1770  *
1771  * RETURNS
1772  * Current build version, hiword is majornumber, loword is minornumber
1773  */
1775 {
1776  TRACE("Returning version %d, build %d.\n", rmm, rup);
1777  return (rmm<<16)+rup;
1778 }
1779 
1780 static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
1781 {
1782  struct init_spy *spy;
1783 
1784  LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
1785  {
1786  if (id == spy->id && spy->spy)
1787  return spy;
1788  }
1789 
1790  return NULL;
1791 }
1792 
1793 /*
1794  * When locked, don't modify list (unless we add a new head), so that it's
1795  * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1796  */
1797 static inline void lock_init_spies(struct oletls *info)
1798 {
1799  info->spies_lock++;
1800 }
1801 
1802 static void unlock_init_spies(struct oletls *info)
1803 {
1804  struct init_spy *spy, *next;
1805 
1806  if (--info->spies_lock) return;
1807 
1808  LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry)
1809  {
1810  if (spy->spy) continue;
1811  list_remove(&spy->entry);
1812  heap_free(spy);
1813  }
1814 }
1815 
1816 /******************************************************************************
1817  * CoRegisterInitializeSpy [OLE32.@]
1818  *
1819  * Add a Spy that watches CoInitializeEx calls
1820  *
1821  * PARAMS
1822  * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1823  * cookie [II] cookie receiver
1824  *
1825  * RETURNS
1826  * Success: S_OK if not already initialized, S_FALSE otherwise.
1827  * Failure: HRESULT code.
1828  *
1829  * SEE ALSO
1830  * CoInitializeEx
1831  */
1833 {
1834  struct oletls *info = COM_CurrentInfo();
1835  struct init_spy *entry;
1836  unsigned int id;
1837  HRESULT hr;
1838 
1839  TRACE("(%p, %p)\n", spy, cookie);
1840 
1841  if (!spy || !cookie || !info)
1842  {
1843  if (!info)
1844  WARN("Could not allocate tls\n");
1845  return E_INVALIDARG;
1846  }
1847 
1848  hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1849  if (FAILED(hr))
1850  return hr;
1851 
1852  entry = heap_alloc(sizeof(*entry));
1853  if (!entry)
1854  {
1855  IInitializeSpy_Release(spy);
1856  return E_OUTOFMEMORY;
1857  }
1858 
1859  entry->spy = spy;
1860 
1861  id = 0;
1862  while (get_spy_entry(info, id) != NULL)
1863  {
1864  id++;
1865  }
1866 
1867  entry->id = id;
1868  list_add_head(&info->spies, &entry->entry);
1869 
1870  cookie->s.HighPart = GetCurrentThreadId();
1871  cookie->s.LowPart = entry->id;
1872 
1873  return S_OK;
1874 }
1875 
1876 /******************************************************************************
1877  * CoRevokeInitializeSpy [OLE32.@]
1878  *
1879  * Remove a spy that previously watched CoInitializeEx calls
1880  *
1881  * PARAMS
1882  * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1883  *
1884  * RETURNS
1885  * Success: S_OK if a spy is removed
1886  * Failure: E_INVALIDARG
1887  *
1888  * SEE ALSO
1889  * CoInitializeEx
1890  */
1892 {
1893  struct oletls *info = COM_CurrentInfo();
1894  struct init_spy *spy;
1895 
1896  TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1897 
1898  if (!info || cookie.s.HighPart != GetCurrentThreadId())
1899  return E_INVALIDARG;
1900 
1901  if (!(spy = get_spy_entry(info, cookie.s.LowPart))) return E_INVALIDARG;
1902 
1903  IInitializeSpy_Release(spy->spy);
1904  spy->spy = NULL;
1905  if (!info->spies_lock)
1906  {
1907  list_remove(&spy->entry);
1908  heap_free(spy);
1909  }
1910  return S_OK;
1911 }
1912 
1914 {
1915  HRESULT hr = S_OK;
1916 
1917  if (!info->apt)
1918  {
1919  if (!apartment_get_or_create( model ))
1920  return E_OUTOFMEMORY;
1921  }
1922  else if (!apartment_is_model( info->apt, model ))
1923  {
1924  WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1925  info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1926  model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1927  return RPC_E_CHANGED_MODE;
1928  }
1929  else
1930  hr = S_FALSE;
1931 
1932  info->inits++;
1933 
1934  return hr;
1935 }
1936 
1937 void leave_apartment( struct oletls *info )
1938 {
1939  if (!--info->inits)
1940  {
1941  if (info->ole_inits)
1942  WARN( "Uninitializing apartment while Ole is still initialized\n" );
1943  apartment_release( info->apt );
1944  info->apt = NULL;
1945  }
1946 }
1947 
1948 /******************************************************************************
1949  * CoInitialize [OLE32.@]
1950  *
1951  * Initializes the COM libraries by calling CoInitializeEx with
1952  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1953  *
1954  * PARAMS
1955  * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1956  *
1957  * RETURNS
1958  * Success: S_OK if not already initialized, S_FALSE otherwise.
1959  * Failure: HRESULT code.
1960  *
1961  * SEE ALSO
1962  * CoInitializeEx
1963  */
1965 {
1966  /*
1967  * Just delegate to the newer method.
1968  */
1969  return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1970 }
1971 
1972 /******************************************************************************
1973  * CoInitializeEx [OLE32.@]
1974  *
1975  * Initializes the COM libraries.
1976  *
1977  * PARAMS
1978  * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1979  * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1980  *
1981  * RETURNS
1982  * S_OK if successful,
1983  * S_FALSE if this function was called already.
1984  * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1985  * threading model.
1986  *
1987  * NOTES
1988  *
1989  * The behavior used to set the IMalloc used for memory management is
1990  * obsolete.
1991  * The dwCoInit parameter must specify one of the following apartment
1992  * threading models:
1993  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1994  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1995  * The parameter may also specify zero or more of the following flags:
1996  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1997  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1998  *
1999  * SEE ALSO
2000  * CoUninitialize
2001  */
2003 {
2004  struct oletls *info = COM_CurrentInfo();
2005  struct init_spy *cursor;
2006  HRESULT hr;
2007 
2008  TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
2009 
2010  if (lpReserved!=NULL)
2011  {
2012  ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
2013  }
2014 
2015  /*
2016  * Check the lock count. If this is the first time going through the initialize
2017  * process, we have to initialize the libraries.
2018  *
2019  * And crank-up that lock count.
2020  */
2022  {
2023  /*
2024  * Initialize the various COM libraries and data structures.
2025  */
2026  TRACE("() - Initializing the COM libraries\n");
2027 
2028  /* we may need to defer this until after apartment initialisation */
2030  }
2031 
2033  LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2034  {
2035  if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
2036  }
2038 
2040 
2042  LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2043  {
2044  if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
2045  }
2047 
2048  return hr;
2049 }
2050 
2051 /***********************************************************************
2052  * CoUninitialize [OLE32.@]
2053  *
2054  * This method will decrement the refcount on the current apartment, freeing
2055  * the resources associated with it if it is the last thread in the apartment.
2056  * If the last apartment is freed, the function will additionally release
2057  * any COM resources associated with the process.
2058  *
2059  * PARAMS
2060  *
2061  * RETURNS
2062  * Nothing.
2063  *
2064  * SEE ALSO
2065  * CoInitializeEx
2066  */
2068 {
2069  struct oletls * info = COM_CurrentInfo();
2070  struct init_spy *cursor, *next;
2071  LONG lCOMRefCnt;
2072 
2073  TRACE("()\n");
2074 
2075  /* will only happen on OOM */
2076  if (!info) return;
2077 
2080  {
2081  if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2082  }
2084 
2085  /* sanity check */
2086  if (!info->inits)
2087  {
2088  ERR("Mismatched CoUninitialize\n");
2089 
2092  {
2093  if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2094  }
2096 
2097  return;
2098  }
2099 
2100  leave_apartment( info );
2101 
2102  /*
2103  * Decrease the reference count.
2104  * If we are back to 0 locks on the COM library, make sure we free
2105  * all the associated data structures.
2106  */
2107  lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2108  if (lCOMRefCnt==1)
2109  {
2110  TRACE("() - Releasing the COM libraries\n");
2111 
2114  }
2115  else if (lCOMRefCnt<1) {
2116  ERR( "CoUninitialize() - not CoInitialized.\n" );
2117  InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2118  }
2119 
2121  LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2122  {
2123  if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2124  }
2126 }
2127 
2128 /******************************************************************************
2129  * CoDisconnectObject [OLE32.@]
2130  *
2131  * Disconnects all connections to this object from remote processes. Dispatches
2132  * pending RPCs while blocking new RPCs from occurring, and then calls
2133  * IMarshal::DisconnectObject on the given object.
2134  *
2135  * Typically called when the object server is forced to shut down, for instance by
2136  * the user.
2137  *
2138  * PARAMS
2139  * lpUnk [I] The object whose stub should be disconnected.
2140  * reserved [I] Reserved. Should be set to 0.
2141  *
2142  * RETURNS
2143  * Success: S_OK.
2144  * Failure: HRESULT code.
2145  *
2146  * SEE ALSO
2147  * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2148  */
2150 {
2151  struct stub_manager *manager;
2152  HRESULT hr;
2153  IMarshal *marshal;
2154  APARTMENT *apt;
2155 
2156  TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2157 
2158  if (!lpUnk) return E_INVALIDARG;
2159 
2160  hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2161  if (hr == S_OK)
2162  {
2163  hr = IMarshal_DisconnectObject(marshal, reserved);
2164  IMarshal_Release(marshal);
2165  return hr;
2166  }
2167 
2168  if (!(apt = apartment_get_current_or_mta()))
2169  {
2170  ERR("apartment not initialised\n");
2171  return CO_E_NOTINITIALIZED;
2172  }
2173 
2174  manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2175  if (manager) {
2176  stub_manager_disconnect(manager);
2177  /* Release stub manager twice, to remove the apartment reference. */
2178  stub_manager_int_release(manager);
2179  stub_manager_int_release(manager);
2180  }
2181 
2182  /* Note: native is pretty broken here because it just silently
2183  * fails, without returning an appropriate error code if the object was
2184  * not found, making apps think that the object was disconnected, when
2185  * it actually wasn't */
2186 
2188  return S_OK;
2189 }
2190 
2191 /******************************************************************************
2192  * CoCreateGuid [OLE32.@]
2193  *
2194  * Simply forwards to UuidCreate in RPCRT4.
2195  *
2196  * PARAMS
2197  * pguid [O] Points to the GUID to initialize.
2198  *
2199  * RETURNS
2200  * Success: S_OK.
2201  * Failure: HRESULT code.
2202  *
2203  * SEE ALSO
2204  * UuidCreate
2205  */
2207 {
2208  DWORD status;
2209 
2210  if(!pguid) return E_INVALIDARG;
2211 
2212  status = UuidCreate(pguid);
2213  if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2214  return HRESULT_FROM_WIN32( status );
2215 }
2216 
2217 static inline BOOL is_valid_hex(WCHAR c)
2218 {
2219  if (!(((c >= '0') && (c <= '9')) ||
2220  ((c >= 'a') && (c <= 'f')) ||
2221  ((c >= 'A') && (c <= 'F'))))
2222  return FALSE;
2223  return TRUE;
2224 }
2225 
2226 static const BYTE guid_conv_table[256] =
2227 {
2228  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2229  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2230  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2231  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2232  0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2233  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2234  0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2235 };
2236 
2237 /* conversion helper for CLSIDFromString/IIDFromString */
2239 {
2240  int i;
2241 
2242  if (!s || s[0]!='{') {
2243  memset( id, 0, sizeof (CLSID) );
2244  if(!s) return TRUE;
2245  return FALSE;
2246  }
2247 
2248  TRACE("%s -> %p\n", debugstr_w(s), id);
2249 
2250  /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2251 
2252  id->Data1 = 0;
2253  for (i = 1; i < 9; i++) {
2254  if (!is_valid_hex(s[i])) return FALSE;
2255  id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2256  }
2257  if (s[9]!='-') return FALSE;
2258 
2259  id->Data2 = 0;
2260  for (i = 10; i < 14; i++) {
2261  if (!is_valid_hex(s[i])) return FALSE;
2262  id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2263  }
2264  if (s[14]!='-') return FALSE;
2265 
2266  id->Data3 = 0;
2267  for (i = 15; i < 19; i++) {
2268  if (!is_valid_hex(s[i])) return FALSE;
2269  id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2270  }
2271  if (s[19]!='-') return FALSE;
2272 
2273  for (i = 20; i < 37; i+=2) {
2274  if (i == 24) {
2275  if (s[i]!='-') return FALSE;
2276  i++;
2277  }
2278  if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2279  id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2280  }
2281 
2282  if (s[37] == '}' && s[38] == '\0')
2283  return TRUE;
2284 
2285  return FALSE;
2286 }
2287 
2288 /*****************************************************************************/
2289 
2291 {
2292  static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2293  WCHAR buf2[CHARS_IN_GUID];
2294  LONG buf2len = sizeof(buf2);
2295  HKEY xhkey;
2296  WCHAR *buf;
2297 
2298  memset(clsid, 0, sizeof(*clsid));
2299  buf = HeapAlloc( GetProcessHeap(),0,(lstrlenW(progid)+8) * sizeof(WCHAR) );
2300  if (!buf) return E_OUTOFMEMORY;
2301  lstrcpyW( buf, progid );
2302  lstrcatW( buf, clsidW );
2304  {
2306  WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2307  return CO_E_CLASSSTRING;
2308  }
2310 
2311  if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2312  {
2313  RegCloseKey(xhkey);
2314  WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2315  return CO_E_CLASSSTRING;
2316  }
2317  RegCloseKey(xhkey);
2318  return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2319 }
2320 
2321 /******************************************************************************
2322  * CLSIDFromString [OLE32.@]
2323  *
2324  * Converts a unique identifier from its string representation into
2325  * the GUID struct.
2326  *
2327  * PARAMS
2328  * idstr [I] The string representation of the GUID.
2329  * id [O] GUID converted from the string.
2330  *
2331  * RETURNS
2332  * S_OK on success
2333  * CO_E_CLASSSTRING if idstr is not a valid CLSID
2334  *
2335  * SEE ALSO
2336  * StringFromCLSID
2337  */
2338 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2339 {
2341  CLSID tmp_id;
2342 
2343  if (!id)
2344  return E_INVALIDARG;
2345 
2346  if (guid_from_string(idstr, id))
2347  return S_OK;
2348 
2349  /* It appears a ProgID is also valid */
2350  ret = clsid_from_string_reg(idstr, &tmp_id);
2351  if(SUCCEEDED(ret))
2352  *id = tmp_id;
2353 
2354  return ret;
2355 }
2356 
2357 /******************************************************************************
2358  * IIDFromString [OLE32.@]
2359  *
2360  * Converts an interface identifier from its string representation to
2361  * the IID struct.
2362  *
2363  * PARAMS
2364  * idstr [I] The string representation of the GUID.
2365  * id [O] IID converted from the string.
2366  *
2367  * RETURNS
2368  * S_OK on success
2369  * CO_E_IIDSTRING if idstr is not a valid IID
2370  *
2371  * SEE ALSO
2372  * StringFromIID
2373  */
2375 {
2376  TRACE("%s -> %p\n", debugstr_w(s), iid);
2377 
2378  if (!s)
2379  {
2380  memset(iid, 0, sizeof(*iid));
2381  return S_OK;
2382  }
2383 
2384  /* length mismatch is a special case */
2385  if (lstrlenW(s) + 1 != CHARS_IN_GUID)
2386  return E_INVALIDARG;
2387 
2388  if (s[0] != '{')
2389  return CO_E_IIDSTRING;
2390 
2391  return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2392 }
2393 
2394 /******************************************************************************
2395  * StringFromCLSID [OLE32.@]
2396  * StringFromIID [OLE32.@]
2397  *
2398  * Converts a GUID into the respective string representation.
2399  * The target string is allocated using the OLE IMalloc.
2400  *
2401  * PARAMS
2402  * id [I] the GUID to be converted.
2403  * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2404  *
2405  * RETURNS
2406  * S_OK
2407  * E_FAIL
2408  *
2409  * SEE ALSO
2410  * StringFromGUID2, CLSIDFromString
2411  */
2413 {
2414  if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2415  StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2416  return S_OK;
2417 }
2418 
2419 /******************************************************************************
2420  * StringFromGUID2 [OLE32.@]
2421  *
2422  * Modified version of StringFromCLSID that allows you to specify max
2423  * buffer size.
2424  *
2425  * PARAMS
2426  * id [I] GUID to convert to string.
2427  * str [O] Buffer where the result will be stored.
2428  * cmax [I] Size of the buffer in characters.
2429  *
2430  * RETURNS
2431  * Success: The length of the resulting string in characters.
2432  * Failure: 0.
2433  */
2435 {
2436  static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2437  '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2438  '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2439  '%','0','2','X','%','0','2','X','}',0 };
2440  if (!id || cmax < CHARS_IN_GUID) return 0;
2441  swprintf( str, formatW, id->Data1, id->Data2, id->Data3,
2442  id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2443  id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2444  return CHARS_IN_GUID;
2445 }
2446 
2447 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2449 {
2450  static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2451  WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2452  LONG res;
2453  HKEY key;
2454 
2455  lstrcpyW(path, wszCLSIDSlash);
2456  StringFromGUID2(clsid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
2458  if (res == ERROR_FILE_NOT_FOUND)
2459  return REGDB_E_CLASSNOTREG;
2460  else if (res != ERROR_SUCCESS)
2461  return REGDB_E_READREGDB;
2462 
2463  if (!keyname)
2464  {
2465  *subkey = key;
2466  return S_OK;
2467  }
2468 
2469  res = open_classes_key(key, keyname, access, subkey);
2470  RegCloseKey(key);
2471  if (res == ERROR_FILE_NOT_FOUND)
2472  return REGDB_E_KEYMISSING;
2473  else if (res != ERROR_SUCCESS)
2474  return REGDB_E_READREGDB;
2475 
2476  return S_OK;
2477 }
2478 
2479 /* open HKCR\\AppId\\{string form of appid clsid} key */
2481 {
2482  static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2483  static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2484  DWORD res;
2486  WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2487  DWORD size;
2488  HKEY hkey;
2489  DWORD type;
2490  HRESULT hr;
2491 
2492  /* read the AppID value under the class's key */
2494  if (FAILED(hr))
2495  return hr;
2496 
2497  size = sizeof(buf);
2498  res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2499  RegCloseKey(hkey);
2500  if (res == ERROR_FILE_NOT_FOUND)
2501  return REGDB_E_KEYMISSING;
2502  else if (res != ERROR_SUCCESS || type!=REG_SZ)
2503  return REGDB_E_READREGDB;
2504 
2505  lstrcpyW(keyname, szAppIdKey);
2506  lstrcatW(keyname, buf);
2507  res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2508  if (res == ERROR_FILE_NOT_FOUND)
2509  return REGDB_E_KEYMISSING;
2510  else if (res != ERROR_SUCCESS)
2511  return REGDB_E_READREGDB;
2512 
2513  return S_OK;
2514 }
2515 
2516 /******************************************************************************
2517  * ProgIDFromCLSID [OLE32.@]
2518  *
2519  * Converts a class id into the respective program ID.
2520  *
2521  * PARAMS
2522  * clsid [I] Class ID, as found in registry.
2523  * ppszProgID [O] Associated ProgID.
2524  *
2525  * RETURNS
2526  * S_OK
2527  * E_OUTOFMEMORY
2528  * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2529  */
2531 {
2532  static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2533  ACTCTX_SECTION_KEYED_DATA data;
2534  HKEY hkey;
2535  HRESULT ret;
2536  LONG progidlen = 0;
2537 
2538  if (!ppszProgID)
2539  return E_INVALIDARG;
2540 
2541  *ppszProgID = NULL;
2542 
2543  data.cbSize = sizeof(data);
2544  if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2545  clsid, &data))
2546  {
2547  struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2548  if (comclass->progid_len)
2549  {
2550  WCHAR *ptrW;
2551 
2552  *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2553  if (!*ppszProgID) return E_OUTOFMEMORY;
2554 
2555  ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2556  memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2557  return S_OK;
2558  }
2559  else
2560  return REGDB_E_CLASSNOTREG;
2561  }
2562 
2563  ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2564  if (FAILED(ret))
2565  return ret;
2566 
2567  if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2569 
2570  if (ret == S_OK)
2571  {
2572  *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2573  if (*ppszProgID)
2574  {
2575  if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2577  CoTaskMemFree(*ppszProgID);
2578  *ppszProgID = NULL;
2579  }
2580  }
2581  else
2582  ret = E_OUTOFMEMORY;
2583  }
2584 
2585  RegCloseKey(hkey);
2586  return ret;
2587 }
2588 
2589 /******************************************************************************
2590  * CLSIDFromProgID [OLE32.@]
2591  *
2592  * Converts a program id into the respective GUID.
2593  *
2594  * PARAMS
2595  * progid [I] Unicode program ID, as found in registry.
2596  * clsid [O] Associated CLSID.
2597  *
2598  * RETURNS
2599  * Success: S_OK
2600  * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2601  */
2603 {
2604  ACTCTX_SECTION_KEYED_DATA data;
2605 
2606  if (!progid || !clsid)
2607  return E_INVALIDARG;
2608 
2609  data.cbSize = sizeof(data);
2610  if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2611  progid, &data))
2612  {
2613  struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2614  CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2615  *clsid = *alias;
2616  return S_OK;
2617  }
2618 
2620 }
2621 
2622 /******************************************************************************
2623  * CLSIDFromProgIDEx [OLE32.@]
2624  */
2626 {
2627  FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2628 
2629  return CLSIDFromProgID(progid, clsid);
2630 }
2631 
2633 {
2634  HKEY hkey;
2636  DWORD len;
2637 
2638  access |= KEY_READ;
2639 
2641  return REGDB_E_IIDNOTREG;
2642 
2643  len = sizeof(value);
2644  if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2645  return REGDB_E_IIDNOTREG;
2646  RegCloseKey(hkey);
2647 
2648  if (CLSIDFromString(value, pclsid) != NOERROR)
2649  return REGDB_E_IIDNOTREG;
2650 
2651  return S_OK;
2652 }
2653 
2654 /*****************************************************************************
2655  * CoGetPSClsid [OLE32.@]
2656  *
2657  * Retrieves the CLSID of the proxy/stub factory that implements
2658  * IPSFactoryBuffer for the specified interface.
2659  *
2660  * PARAMS
2661  * riid [I] Interface whose proxy/stub CLSID is to be returned.
2662  * pclsid [O] Where to store returned proxy/stub CLSID.
2663  *
2664  * RETURNS
2665  * S_OK
2666  * E_OUTOFMEMORY
2667  * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2668  *
2669  * NOTES
2670  *
2671  * The standard marshaller activates the object with the CLSID
2672  * returned and uses the CreateProxy and CreateStub methods on its
2673  * IPSFactoryBuffer interface to construct the proxies and stubs for a
2674  * given object.
2675  *
2676  * CoGetPSClsid determines this CLSID by searching the
2677  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2678  * in the registry and any interface id registered by
2679  * CoRegisterPSClsid within the current process.
2680  *
2681  * BUGS
2682  *
2683  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2684  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2685  * considered a bug in native unless an application depends on this (unlikely).
2686  *
2687  * SEE ALSO
2688  * CoRegisterPSClsid.
2689  */
2691 {
2692  static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2693  static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2694  WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2695  APARTMENT *apt;
2697  ACTCTX_SECTION_KEYED_DATA data;
2698  HRESULT hr;
2699  REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2700  BOOL is_wow64;
2701 
2702  TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2703 
2704  if (!(apt = apartment_get_current_or_mta()))
2705  {
2706  ERR("apartment not initialised\n");
2707  return CO_E_NOTINITIALIZED;
2708  }
2709  apartment_release(apt);
2710 
2711  if (!pclsid)
2712  return E_INVALIDARG;
2713 
2715 
2718  {
2719  *pclsid = registered_psclsid->clsid;
2721  return S_OK;
2722  }
2723 
2725 
2726  data.cbSize = sizeof(data);
2727  if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2728  riid, &data))
2729  {
2730  struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2731  *pclsid = ifaceps->iid;
2732  return S_OK;
2733  }
2734 
2735  /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2736  lstrcpyW(path, wszInterface);
2737  StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2738  lstrcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2739 
2740  hr = get_ps_clsid_from_registry(path, 0, pclsid);
2741  if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2743  hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2744 
2745  if (hr == S_OK)
2746  TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2747  else
2748  WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2749 
2750  return hr;
2751 }
2752 
2753 /*****************************************************************************
2754  * CoRegisterPSClsid [OLE32.@]
2755  *
2756  * Register a proxy/stub CLSID for the given interface in the current process
2757  * only.
2758  *
2759  * PARAMS
2760  * riid [I] Interface whose proxy/stub CLSID is to be registered.
2761  * rclsid [I] CLSID of the proxy/stub.
2762  *
2763  * RETURNS
2764  * Success: S_OK
2765  * Failure: E_OUTOFMEMORY
2766  *
2767  * NOTES
2768  *
2769  * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2770  * will be returned from other apartments in the same process.
2771  *
2772  * This function does not add anything to the registry and the effects are
2773  * limited to the lifetime of the current process.
2774  *
2775  * SEE ALSO
2776  * CoGetPSClsid.
2777  */
2779 {
2780  APARTMENT *apt;
2782 
2783  TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2784 
2785  if (!(apt = apartment_get_current_or_mta()))
2786  {
2787  ERR("apartment not initialised\n");
2788  return CO_E_NOTINITIALIZED;
2789  }
2790  apartment_release(apt);
2791 
2793 
2796  {
2797  registered_psclsid->clsid = *rclsid;
2799  return S_OK;
2800  }
2801 
2803  if (!registered_psclsid)
2804  {
2806  return E_OUTOFMEMORY;
2807  }
2808 
2810  registered_psclsid->clsid = *rclsid;
2812 
2814 
2815  return S_OK;
2816 }
2817 
2818 
2819 /***
2820  * COM_GetRegisteredClassObject
2821  *
2822  * This internal method is used to scan the registered class list to
2823  * find a class object.
2824  *
2825  * Params:
2826  * rclsid Class ID of the class to find.
2827  * dwClsContext Class context to match.
2828  * ppv [out] returns a pointer to the class object. Complying
2829  * to normal COM usage, this method will increase the
2830  * reference count on this object.
2831  */
2832 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2833  DWORD dwClsContext, LPUNKNOWN* ppUnk)
2834 {
2835  HRESULT hr = S_FALSE;
2836  RegisteredClass *curClass;
2837 
2839 
2841  {
2842  /*
2843  * Check if we have a match on the class ID and context.
2844  */
2845  if ((apt->oxid == curClass->apartment_id) &&
2846  (dwClsContext & curClass->runContext) &&
2847  IsEqualGUID(&(curClass->classIdentifier), rclsid))
2848  {
2849  /*
2850  * We have a match, return the pointer to the class object.
2851  */
2852  *ppUnk = curClass->classObject;
2853 
2854  IUnknown_AddRef(curClass->classObject);
2855 
2856  hr = S_OK;
2857  break;
2858  }
2859  }
2860 
2862 
2863  return hr;
2864 }
2865 
2866 /******************************************************************************
2867  * CoRegisterClassObject [OLE32.@]
2868  *
2869  * Registers the class object for a given class ID. Servers housed in EXE
2870  * files use this method instead of exporting DllGetClassObject to allow
2871  * other code to connect to their objects.
2872  *
2873  * PARAMS
2874  * rclsid [I] CLSID of the object to register.
2875  * pUnk [I] IUnknown of the object.
2876  * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2877  * flags [I] REGCLS flags indicating how connections are made.
2878  * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2879  *
2880  * RETURNS
2881  * S_OK on success,
2882  * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2883  * CO_E_OBJISREG if the object is already registered. We should not return this.
2884  *
2885  * SEE ALSO
2886  * CoRevokeClassObject, CoGetClassObject
2887  *
2888  * NOTES
2889  * In-process objects are only registered for the current apartment.
2890  * CoGetClassObject() and CoCreateInstance() will not return objects registered
2891  * in other apartments.
2892  *
2893  * BUGS
2894  * MSDN claims that multiple interface registrations are legal, but we
2895  * can't do that with our current implementation.
2896  */
2898  REFCLSID rclsid,
2899  LPUNKNOWN pUnk,
2900  DWORD dwClsContext,
2901  DWORD flags,
2902  LPDWORD lpdwRegister)
2903 {
2904  static LONG next_cookie;
2905  RegisteredClass* newClass;
2906  LPUNKNOWN foundObject;
2907  HRESULT hr;
2908  APARTMENT *apt;
2909 
2910  TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2911  debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2912 
2913  if ( (lpdwRegister==0) || (pUnk==0) )
2914  return E_INVALIDARG;
2915 
2916  if (!(apt = apartment_get_current_or_mta()))
2917  {
2918  ERR("COM was not initialized\n");
2919  return CO_E_NOTINITIALIZED;
2920  }
2921 
2922  *lpdwRegister = 0;
2923 
2924  /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2925  * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2926  if (flags & REGCLS_MULTIPLEUSE)
2927  dwClsContext |= CLSCTX_INPROC_SERVER;
2928 
2929  /*
2930  * First, check if the class is already registered.
2931  * If it is, this should cause an error.
2932  */
2933  hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2934  if (hr == S_OK) {
2935  if (flags & REGCLS_MULTIPLEUSE) {
2936  if (dwClsContext & CLSCTX_LOCAL_SERVER)
2937  hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2938  IUnknown_Release(foundObject);
2939  apartment_release(apt);
2940  return hr;
2941  }
2942  IUnknown_Release(foundObject);
2943  ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2944  apartment_release(apt);
2945  return CO_E_OBJISREG;
2946  }
2947 
2948  newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2949  if ( newClass == NULL )
2950  {
2951  apartment_release(apt);
2952  return E_OUTOFMEMORY;
2953  }
2954 
2955  newClass->classIdentifier = *rclsid;
2956  newClass->apartment_id = apt->oxid;
2957  newClass->runContext = dwClsContext;
2958  newClass->connectFlags = flags;
2959  newClass->RpcRegistration = NULL;
2960 
2961  if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2962  newClass->dwCookie = InterlockedIncrement( &next_cookie );
2963 
2964  /*
2965  * Since we're making a copy of the object pointer, we have to increase its
2966  * reference count.
2967  */
2968  newClass->classObject = pUnk;
2969  IUnknown_AddRef(newClass->classObject);
2970 
2972  list_add_tail(&RegisteredClassList, &newClass->entry);
2974 
2975  *lpdwRegister = newClass->dwCookie;
2976 
2977  if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2978  IStream *marshal_stream;
2979 
2980  hr = get_local_server_stream(apt, &marshal_stream);
2981  if(FAILED(hr))
2982  {
2983  apartment_release(apt);
2984  return hr;
2985  }
2986 
2988  marshal_stream,
2990  &newClass->RpcRegistration);
2991  IStream_Release(marshal_stream);
2992  }
2993  apartment_release(apt);
2994  return S_OK;
2995 }
2996 
2998 {
2999  if (data->hkey)
3000  {
3001  static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
3002  static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
3003  static const WCHAR wszFree[] = {'F','r','e','e',0};
3004  static const WCHAR wszBoth[] = {'B','o','t','h',0};
3005  WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */];
3006  DWORD dwLength = sizeof(threading_model);
3007  DWORD keytype;
3008  DWORD ret;
3009 
3010  ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
3011  if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
3012  threading_model[0] = '\0';
3013 
3014  if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment;
3015  if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free;
3016  if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both;
3017 
3018  /* there's not specific handling for this case */
3019  if (threading_model[0]) return ThreadingModel_Neutral;
3020  return ThreadingModel_No;
3021  }
3022  else
3023  return data->u.actctx.data->model;
3024 }
3025 
3026 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
3027  REFCLSID rclsid, REFIID riid,
3028  BOOL hostifnecessary, void **ppv)
3029 {
3030  WCHAR dllpath[MAX_PATH+1];
3031  BOOL apartment_threaded;
3032 
3033  if (hostifnecessary)
3034  {
3035  enum comclass_threadingmodel model = get_threading_model(regdata);
3036 
3037  if (model == ThreadingModel_Apartment)
3038  {
3039  apartment_threaded = TRUE;
3040  if (apt->multi_threaded)
3041  return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
3042  }
3043  else if (model == ThreadingModel_Free)
3044  {
3045  apartment_threaded = FALSE;
3046  if (!apt->multi_threaded)
3047  return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
3048  }
3049  /* everything except "Apartment", "Free" and "Both" */
3050  else if (model != ThreadingModel_Both)
3051  {
3052  apartment_threaded = TRUE;
3053  /* everything else is main-threaded */
3054  if (model != ThreadingModel_No)
3055  FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
3056 
3057  if (apt->multi_threaded || !apt->main)
3058  return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
3059  }
3060  else
3061  apartment_threaded = FALSE;
3062  }
3063  else
3064  apartment_threaded = !apt->multi_threaded;
3065 
3066  if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
3067  {
3068  /* failure: CLSID is not found in registry */
3069  WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
3070  return REGDB_E_CLASSNOTREG;
3071  }
3072 
3073  return apartment_getclassobject(apt, dllpath, apartment_threaded,
3074  rclsid, riid, ppv);
3075 }
3076 
3077 /***********************************************************************
3078  * CoGetClassObject [OLE32.@]
3079  *
3080  * Creates an object of the specified class.
3081  *
3082  * PARAMS
3083  * rclsid [I] Class ID to create an instance of.
3084  * dwClsContext [I] Flags to restrict the location of the created instance.
3085  * pServerInfo [I] Optional. Details for connecting to a remote server.
3086  * iid [I] The ID of the interface of the instance to return.
3087  * ppv [O] On returns, contains a pointer to the specified interface of the object.
3088  *
3089  * RETURNS
3090  * Success: S_OK
3091  * Failure: HRESULT code.
3092  *
3093  * NOTES
3094  * The dwClsContext parameter can be one or more of the following:
3095  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3096  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3097  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3098  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3099  *
3100  * SEE ALSO
3101  * CoCreateInstance()
3102  */
3104  REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3105  REFIID iid, LPVOID *ppv)
3106 {
3107  struct class_reg_data clsreg;
3108  IUnknown *regClassObject;
3110  APARTMENT *apt;
3111 
3112  TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3113 
3114  if (!ppv)
3115  return E_INVALIDARG;
3116 
3117  *ppv = NULL;
3118 
3119  if (!(apt = apartment_get_current_or_mta()))
3120  {
3121  ERR("apartment not initialised\n");
3122  return CO_E_NOTINITIALIZED;
3123  }
3124 
3125  if (pServerInfo) {
3126  FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3127  debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3128  }
3129 
3130  if (CLSCTX_INPROC_SERVER & dwClsContext)
3131  {
3133  {
3134  apartment_release(apt);
3135  return FTMarshalCF_Create(iid, ppv);
3136  }
3137  if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3138  return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3139  }
3140 
3141  if (CLSCTX_INPROC & dwClsContext)
3142  {
3143  ACTCTX_SECTION_KEYED_DATA data;
3144 
3145  data.cbSize = sizeof(data);
3146  /* search activation context first */
3147  if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3148  ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3149  rclsid, &data))
3150  {
3151  struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3152 
3153  clsreg.u.actctx.hactctx = data.hActCtx;
3154  clsreg.u.actctx.data = data.lpData;
3155  clsreg.u.actctx.section = data.lpSectionBase;
3156  clsreg.hkey = FALSE;
3157 
3158  hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3159  ReleaseActCtx(data.hActCtx);
3160  apartment_release(apt);
3161  return hres;
3162  }
3163  }
3164 
3165  /*
3166  * First, try and see if we can't match the class ID with one of the
3167  * registered classes.
3168  */
3169  if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3170  &regClassObject))
3171  {
3172  /* Get the required interface from the retrieved pointer. */
3173  hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3174 
3175  /*
3176  * Since QI got another reference on the pointer, we want to release the
3177  * one we already have. If QI was unsuccessful, this will release the object. This
3178  * is good since we are not returning it in the "out" parameter.
3179  */
3180  IUnknown_Release(regClassObject);
3181  apartment_release(apt);
3182  return hres;
3183  }
3184 
3185  /* First try in-process server */
3186  if (CLSCTX_INPROC_SERVER & dwClsContext)
3187  {
3188  static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3189  HKEY hkey;
3190 
3191  hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3192  if (FAILED(hres))
3193  {
3194  if (hres == REGDB_E_CLASSNOTREG)
3195  ERR("class %s not registered\n", debugstr_guid(rclsid));
3196  else if (hres == REGDB_E_KEYMISSING)
3197  {
3198  WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3200  }
3201  }
3202 
3203  if (SUCCEEDED(hres))
3204  {
3205  clsreg.u.hkey = hkey;
3206  clsreg.hkey = TRUE;
3207 
3208  hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3209  RegCloseKey(hkey);
3210  }
3211 
3212  /* return if we got a class, otherwise fall through to one of the
3213  * other types */
3214  if (SUCCEEDED(hres))
3215  {
3216  apartment_release(apt);
3217  return hres;
3218  }
3219  }
3220 
3221  /* Next try in-process handler */
3222  if (CLSCTX_INPROC_HANDLER & dwClsContext)
3223  {
3224  static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3225  HKEY hkey;
3226 
3227  hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3228  if (FAILED(hres))
3229  {
3230  if (hres == REGDB_E_CLASSNOTREG)
3231  ERR("class %s not registered\n", debugstr_guid(rclsid));
3232  else if (hres == REGDB_E_KEYMISSING)
3233  {
3234  WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3236  }
3237  }
3238 
3239  if (SUCCEEDED(hres))
3240  {
3241  clsreg.u.hkey = hkey;
3242  clsreg.hkey = TRUE;
3243 
3244  hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3245  RegCloseKey(hkey);
3246  }
3247 
3248  /* return if we got a class, otherwise fall through to one of the
3249  * other types */
3250  if (SUCCEEDED(hres))
3251  {
3252  apartment_release(apt);
3253  return hres;
3254  }
3255  }
3256  apartment_release(apt);
3257 
3258  /* Next try out of process */
3259  if (CLSCTX_LOCAL_SERVER & dwClsContext)
3260  {
3261  hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3262  if (SUCCEEDED(hres))
3263  return hres;
3264  }
3265 
3266  /* Finally try remote: this requires networked DCOM (a lot of work) */
3267  if (CLSCTX_REMOTE_SERVER & dwClsContext)
3268  {
3269  FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3271  }
3272 
3273  if (FAILED(hres))
3274  ERR("no class object %s could be created for context 0x%x\n",
3275  debugstr_guid(rclsid), dwClsContext);
3276  return hres;
3277 }
3278 
3279 /***********************************************************************
3280  * CoResumeClassObjects (OLE32.@)
3281  *
3282  * Resumes all class objects registered with REGCLS_SUSPENDED.
3283  *
3284  * RETURNS
3285  * Success: S_OK.
3286  * Failure: HRESULT code.
3287  */
3289 {
3290  FIXME("stub\n");
3291  return S_OK;
3292 }
3293 
3294 /***********************************************************************
3295  * CoCreateInstance [OLE32.@]
3296  *
3297  * Creates an instance of the specified class.
3298  *
3299  * PARAMS
3300  * rclsid [I] Class ID to create an instance of.
3301  * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3302  * dwClsContext [I] Flags to restrict the location of the created instance.
3303  * iid [I] The ID of the interface of the instance to return.
3304  * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3305  *
3306  * RETURNS
3307  * Success: S_OK
3308  * Failure: HRESULT code.
3309  *
3310  * NOTES
3311  * The dwClsContext parameter can be one or more of the following:
3312  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3313  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3314  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3315  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3316  *
3317  * Aggregation is the concept of deferring the IUnknown of an object to another
3318  * object. This allows a separate object to behave as though it was part of
3319  * the object and to allow this the pUnkOuter parameter can be set. Note that
3320  * not all objects support having an outer of unknown.
3321  *
3322  * SEE ALSO
3323  * CoGetClassObject()
3324  */
3326  REFCLSID rclsid,
3327  LPUNKNOWN pUnkOuter,
3328  DWORD dwClsContext,
3329  REFIID iid,
3330  LPVOID *ppv)
3331 {
3332  MULTI_QI multi_qi = { iid };
3333  HRESULT hres;
3334 
3335  TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3336  pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3337 
3338  if (ppv==0)
3339  return E_POINTER;
3340 
3341  hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3342  *ppv = multi_qi.pItf;
3343  return hres;
3344 }
3345 
3346 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3347 {
3348  ULONG i;
3349 
3350  for (i = 0; i < count; i++)
3351  {
3352  mqi[i].pItf = NULL;
3353  mqi[i].hr = hr;
3354  }
3355 }
3356 
3357 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3358 {
3359  ULONG index = 0, fetched = 0;
3360 
3361  if (include_unk)
3362  {
3363  mqi[0].hr = S_OK;
3364  mqi[0].pItf = unk;
3365  index = fetched = 1;
3366  }
3367 
3368  for (; index < count; index++)
3369  {
3370  mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3371  if (mqi[index].hr == S_OK)
3372  fetched++;
3373  }
3374 
3375  if (!include_unk)
3376  IUnknown_Release(unk);
3377 
3378  if (fetched == 0)
3379  return E_NOINTERFACE;
3380 
3381  return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3382 }
3383 
3384 /***********************************************************************
3385  * CoCreateInstanceEx [OLE32.@]
3386  */
3388  REFCLSID rclsid,
3389  LPUNKNOWN pUnkOuter,
3390  DWORD dwClsContext,
3391  COSERVERINFO* pServerInfo,
3392  ULONG cmq,
3393  MULTI_QI* pResults)
3394 {
3395  IUnknown *unk = NULL;
3396  IClassFactory *cf;
3397  APARTMENT *apt;
3398  CLSID clsid;
3399  HRESULT hres;
3400 
3401  TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3402 
3403  if (!cmq || !pResults)
3404  return E_INVALIDARG;
3405 
3406  if (pServerInfo)
3407  FIXME("() non-NULL pServerInfo not supported!\n");
3408 
3409  init_multi_qi(cmq, pResults, E_NOINTERFACE);
3410 
3411  hres = CoGetTreatAsClass(rclsid, &clsid);
3412  if(FAILED(hres))
3413  clsid = *rclsid;
3414 
3415  if (!(apt = apartment_get_current_or_mta()))
3416  {
3417  ERR("apartment not initialised\n");
3418  return CO_E_NOTINITIALIZED;
3419  }
3420  apartment_release(apt);
3421 
3422  /*
3423  * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3424  */
3426  {
3428  TRACE("Retrieving GIT\n");
3429  return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3430  }
3431 
3433  hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3434  if (FAILED(hres))
3435  return hres;
3436  return return_multi_qi(unk, cmq, pResults, TRUE);
3437  }
3438 
3439  /*
3440  * Get a class factory to construct the object we want.
3441  */
3442  hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3443  if (FAILED(hres))
3444  return hres;
3445 
3446  /*
3447  * Create the object and don't forget to release the factory
3448  */
3449  hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3450  IClassFactory_Release(cf);
3451  if (FAILED(hres))
3452  {
3453  if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3454  FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3455  else
3456  FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3457  debugstr_guid(pResults[0].pIID),
3459  return hres;
3460  }
3461 
3462  return return_multi_qi(unk, cmq, pResults, TRUE);
3463 }
3464 
3465 /***********************************************************************
3466  * CoGetInstanceFromFile [OLE32.@]
3467  */
3470  CLSID *rclsid,
3471  IUnknown *outer,
3472  DWORD cls_context,
3473  DWORD grfmode,
3474  OLECHAR *filename,
3475  DWORD count,
3476  MULTI_QI *results
3477 )
3478 {
3479  IPersistFile *pf = NULL;
3480  IUnknown* unk = NULL;
3481  CLSID clsid;
3482  HRESULT hr;
3483 
3484  if (count == 0 || !results)
3485  return E_INVALIDARG;
3486 
3487  if (server_info)
3488  FIXME("() non-NULL server_info not supported\n");
3489 
3491 
3492  /* optionally get CLSID from a file */
3493  if (!rclsid)
3494  {
3496  if (FAILED(hr))
3497  {
3498  ERR("failed to get CLSID from a file\n");
3499  return hr;
3500  }
3501 
3502  rclsid = &clsid;
3503  }
3504 
3505  hr = CoCreateInstance(rclsid,
3506  outer,
3507  cls_context,
3508  &IID_IUnknown,
3509  (void**)&unk);
3510 
3511  if (hr != S_OK)
3512  {
3514  return hr;
3515  }
3516 
3517  /* init from file */
3518  hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3519  if (FAILED(hr))
3520  {
3522  IUnknown_Release(unk);
3523  return hr;
3524  }
3525 
3526  hr = IPersistFile_Load(pf, filename, grfmode);
3527  IPersistFile_Release(pf);
3528  if (SUCCEEDED(hr))
3529  return return_multi_qi(unk, count, results, FALSE);
3530  else
3531  {
3533  IUnknown_Release(unk);
3534  return hr;
3535  }
3536 }
3537 
3538 /***********************************************************************
3539  * CoGetInstanceFromIStorage [OLE32.@]
3540  */
3543  CLSID *rclsid,
3544  IUnknown *outer,
3545  DWORD cls_context,
3546  IStorage *storage,
3547  DWORD count,
3548  MULTI_QI *results
3549 )
3550 {
3551  IPersistStorage *ps = NULL;
3552  IUnknown* unk = NULL;
3553  STATSTG stat;
3554  HRESULT hr;
3555 
3556  if (count == 0 || !results || !storage)
3557  return E_INVALIDARG;
3558 
3559  if (server_info)
3560  FIXME("() non-NULL server_info not supported\n");
3561 
3563 
3564  /* optionally get CLSID from a file */
3565  if (!rclsid)
3566  {
3567  memset(&stat.clsid, 0, sizeof(stat.clsid));
3568  hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3569  if (FAILED(hr))
3570  {
3571  ERR("failed to get CLSID from a file\n");
3572  return hr;
3573  }
3574 
3575  rclsid = &stat.clsid;
3576  }
3577 
3578  hr = CoCreateInstance(rclsid,
3579  outer,
3580  cls_context,
3581  &IID_IUnknown,
3582  (void**)&unk);
3583 
3584  if (hr != S_OK)
3585  return hr;
3586 
3587  /* init from IStorage */
3588  hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3589  if (FAILED(hr))
3590  ERR("failed to get IPersistStorage\n");
3591 
3592  if (ps)
3593  {
3594  IPersistStorage_Load(ps, storage);
3595  IPersistStorage_Release(ps);
3596  }
3597 
3598  return return_multi_qi(unk, count, results, FALSE);
3599 }
3600 
3601 /***********************************************************************
3602  * CoLoadLibrary (OLE32.@)
3603  *
3604  * Loads a library.
3605  *
3606  * PARAMS
3607  * lpszLibName [I] Path to library.
3608  * bAutoFree [I] Whether the library should automatically be freed.
3609  *
3610  * RETURNS
3611  * Success: Handle to loaded library.
3612  * Failure: NULL.
3613  *
3614  * SEE ALSO
3615  * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3616  */
3617 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3618 {
3619  TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3620 
3621  return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3622 }
3623 
3624 /***********************************************************************
3625  * CoFreeLibrary [OLE32.@]
3626  *
3627  * Unloads a library from memory.
3628  *
3629  * PARAMS
3630  * hLibrary [I] Handle to library to unload.
3631  *
3632  * RETURNS
3633  * Nothing
3634  *
3635  * SEE ALSO
3636  * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3637  */
3639 {
3641 }
3642 
3643 
3644 /***********************************************************************
3645  * CoFreeAllLibraries [OLE32.@]
3646  *
3647  * Function for backwards compatibility only. Does nothing.
3648  *
3649  * RETURNS
3650  * Nothing.
3651  *
3652  * SEE ALSO
3653  * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3654  */
3656 {
3657  /* NOP */
3658 }
3659 
3660 /***********************************************************************
3661  * CoFreeUnusedLibrariesEx [OLE32.@]
3662  *
3663  * Frees any previously unused libraries whose delay has expired and marks
3664  * currently unused libraries for unloading. Unused are identified as those that
3665  * return S_OK from their DllCanUnloadNow function.
3666  *
3667  * PARAMS
3668  * dwUnloadDelay [I] Unload delay in milliseconds.
3669  * dwReserved [I] Reserved. Set to 0.
3670  *
3671  * RETURNS
3672  * Nothing.
3673  *
3674  * SEE ALSO
3675  * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3676  */
3678 {
3679  struct apartment *apt = COM_CurrentApt();
3680  if (!apt)
3681  {
3682  ERR("apartment not initialised\n");
3683  return;
3684  }
3685 
3686  apartment_freeunusedlibraries(apt, dwUnloadDelay);
3687 }
3688 
3689 /***********************************************************************
3690  * CoFreeUnusedLibraries [OLE32.@]
3691  *
3692  * Frees any unused libraries. Unused are identified as those that return
3693  * S_OK from their DllCanUnloadNow function.
3694  *
3695  * RETURNS
3696  * Nothing.
3697  *
3698  * SEE ALSO
3699  * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3700  */
3702 {
3704 }
3705 
3706 /***********************************************************************
3707  * CoFileTimeNow [OLE32.@]
3708  *
3709  * Retrieves the current time in FILETIME format.
3710  *
3711  * PARAMS
3712  * lpFileTime [O] The current time.
3713  *
3714  * RETURNS
3715  * S_OK.
3716  */
3718 {
3719  GetSystemTimeAsFileTime( lpFileTime );
3720  return S_OK;
3721 }
3722 
3723 /******************************************************************************
3724  * CoLockObjectExternal [OLE32.@]
3725  *
3726  * Increments or decrements the external reference count of a stub object.
3727  *
3728  * PARAMS
3729  * pUnk [I] Stub object.
3730  * fLock [I] If TRUE then increments the external ref-count,
3731  * otherwise decrements.
3732  * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3733  * calling CoDisconnectObject.
3734  *
3735  * RETURNS
3736  * Success: S_OK.
3737  * Failure: HRESULT code.
3738  *
3739  * NOTES
3740  * If fLock is TRUE and an object is passed in that doesn't have a stub
3741  * manager then a new stub manager is created for the object.
3742  */
3744  LPUNKNOWN pUnk,
3745  BOOL fLock,
3746  BOOL fLastUnlockReleases)
3747 {
3748  struct stub_manager *stubmgr;
3749  struct apartment *apt;
3750 
3751  TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3752  pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3753 
3754  if (!(apt = apartment_get_current_or_mta()))
3755  {
3756  ERR("apartment not initialised\n");
3757  return CO_E_NOTINITIALIZED;
3758  }
3759 
3760  stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3761  if (!stubmgr)
3762  {
3763  WARN("stub object not found %p\n", pUnk);
3764  /* Note: native is pretty broken here because it just silently
3765  * fails, without returning an appropriate error code, making apps
3766  * think that the object was disconnected, when it actually wasn't */
3767  apartment_release(apt);
3768  return S_OK;
3769  }
3770 
3771  if (fLock)
3772  stub_manager_ext_addref(stubmgr, 1, FALSE);
3773  else
3774  stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3775 
3776  stub_manager_int_release(stubmgr);
3777  apartment_release(apt);
3778  return S_OK;
3779 }
3780 
3781 /***********************************************************************
3782  * CoInitializeWOW (OLE32.@)
3783  *
3784  * WOW equivalent of CoInitialize?
3785  *
3786  * PARAMS
3787  * x [I] Unknown.
3788  * y [I] Unknown.
3789  *
3790  * RETURNS
3791  * Unknown.
3792  */
3794 {
3795  FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3796  return 0;
3797 }
3798 
3799 /***********************************************************************
3800  * CoGetState [OLE32.@]
3801  *
3802  * Retrieves the thread state object previously stored by CoSetState().
3803  *
3804  * PARAMS
3805  * ppv [I] Address where pointer to object will be stored.
3806  *
3807  * RETURNS
3808  * Success: S_OK.
3809  * Failure: E_OUTOFMEMORY.
3810  *
3811  * NOTES
3812  * Crashes on all invalid ppv addresses, including NULL.
3813  * If the function returns a non-NULL object then the caller must release its
3814  * reference on the object when the object is no longer required.
3815  *
3816  * SEE ALSO
3817  * CoSetState().
3818  */
3820 {
3821  struct oletls *info = COM_CurrentInfo();
3822  if (!info) return E_OUTOFMEMORY;
3823 
3824  *ppv = NULL;
3825 
3826  if (info->state)
3827  {
3828  IUnknown_AddRef(info->state);
3829  *ppv = info->state;
3830  TRACE("apt->state=%p\n", info->state);
3831  }
3832 
3833  return S_OK;
3834 }
3835 
3836 /***********************************************************************
3837  * CoSetState [OLE32.@]
3838  *
3839  * Sets the thread state object.
3840  *
3841  * PARAMS
3842  * pv [I] Pointer to state object to be stored.
3843  *
3844  * NOTES
3845  * The system keeps a reference on the object while the object stored.
3846  *
3847  * RETURNS
3848  * Success: S_OK.
3849  * Failure: E_OUTOFMEMORY.
3850  */
3852 {
3853  struct oletls *info = COM_CurrentInfo();
3854  if (!info) return E_OUTOFMEMORY;
3855 
3856  if (pv) IUnknown_AddRef(pv);
3857 
3858  if (info->state)
3859  {
3860  TRACE("-- release %p now\n", info->state);
3861  IUnknown_Release(info->state);
3862  }
3863 
3864  info->state = pv;
3865 
3866  return S_OK;
3867 }
3868 
3869 
3870 /******************************************************************************
3871  * CoTreatAsClass [OLE32.@]
3872  *
3873  * Sets the TreatAs value of a class.
3874  *
3875  * PARAMS
3876  * clsidOld [I] Class to set TreatAs value on.
3877  * clsidNew [I] The class the clsidOld should be treated as.
3878  *
3879  * RETURNS
3880  * Success: S_OK.
3881  * Failure: HRESULT code.
3882  *
3883  * SEE ALSO
3884  * CoGetTreatAsClass
3885  */
3887 {
3888  static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3889  static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3890  HKEY hkey = NULL;
3891  WCHAR szClsidNew[CHARS_IN_GUID];
3892  HRESULT res = S_OK;
3893  WCHAR auto_treat_as[CHARS_IN_GUID];
3894  LONG auto_treat_as_size = sizeof(auto_treat_as);
3895  CLSID id;
3896 
3897  res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3898  if (FAILED(res))
3899  goto done;
3900 
3901  if (IsEqualGUID( clsidOld, clsidNew ))
3902  {
3903  if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3904  CLSIDFromString(auto_treat_as, &id) == S_OK)
3905  {
3906  if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3907  {
3909  goto done;
3910  }
3911  }
3912  else
3913  {
3914  if(RegDeleteKeyW(hkey, wszTreatAs))
3916  goto done;
3917  }
3918  }
3919  else
3920  {
3921  if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3922  RegDeleteKeyW(hkey, wszTreatAs);
3923  }else{
3924  if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){
3925  WARN("StringFromGUID2 failed\n");
3926  res = E_FAIL;
3927  goto done;
3928  }
3929 
3930  if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3931  WARN("RegSetValue failed\n");
3933  goto done;
3934  }
3935  }
3936  }
3937 
3938 done:
3939  if (hkey) RegCloseKey(hkey);
3940  return res;
3941 }
3942 
3943 /******************************************************************************
3944  * CoGetTreatAsClass [OLE32.@]
3945  *
3946  * Gets the TreatAs value of a class.
3947  *
3948  * PARAMS
3949  * clsidOld [I] Class to get the TreatAs value of.
3950  * clsidNew [I] The class the clsidOld should be treated as.
3951  *
3952  * RETURNS
3953  * Success: S_OK.
3954  * Failure: HRESULT code.
3955  *
3956  * SEE ALSO
3957  * CoSetTreatAsClass
3958  */
3960 {
3961  static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3962  HKEY hkey = NULL;
3963  WCHAR szClsidNew[CHARS_IN_GUID];
3964  HRESULT res = S_OK;
3965  LONG len = sizeof(szClsidNew);
3966 
3967  TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3968 
3969  if (!clsidOld || !clsidNew)
3970  return E_INVALIDARG;
3971 
3972  *clsidNew = *clsidOld; /* copy over old value */
3973 
3974  res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3975  if (FAILED(res))
3976  {
3977  res = S_FALSE;
3978  goto done;
3979  }
3980  if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3981  {
3982  res = S_FALSE;
3983  goto done;
3984  }
3985  res = CLSIDFromString(szClsidNew,clsidNew);
3986  if (FAILED(res))
3987  ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3988 done:
3989  if (hkey) RegCloseKey(hkey);
3990  return res;
3991 }
3992 
3993 /******************************************************************************
3994  * CoGetCurrentProcess [OLE32.@]
3995  *
3996  * Gets the current process ID.
3997  *
3998  * RETURNS
3999  * The current process ID.
4000  *
4001  * NOTES
4002  * Is DWORD really the correct return type for this function?
4003  */
4005 {
4006  return GetCurrentProcessId();
4007 }
4008 
4009 /***********************************************************************
4010  * CoGetCurrentLogicalThreadId [OLE32.@]
4011  */
4013 {
4014  TRACE("(%p)\n", id);
4015 
4016  if (!id)
4017  return E_INVALIDARG;
4018 
4019  *id = COM_CurrentCausalityId();
4020  return S_OK;
4021 }
4022 
4023 /******************************************************************************
4024  * CoRegisterMessageFilter [OLE32.@]
4025  *
4026  * Registers a message filter.
4027  *
4028  * PARAMS
4029  * lpMessageFilter [I] Pointer to interface.
4030  * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
4031  *
4032  * RETURNS
4033  * Success: S_OK.
4034  * Failure: HRESULT code.
4035  *
4036  * NOTES
4037  * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4038  * lpMessageFilter removes the message filter.
4039  *
4040  * If lplpMessageFilter is not NULL the previous message filter will be
4041  * returned in the memory pointer to this parameter and the caller is
4042  * responsible for releasing the object.
4043  *
4044  * The current thread be in an apartment otherwise the function will crash.
4045  */
4047  LPMESSAGEFILTER lpMessageFilter,
4048  LPMESSAGEFILTER *lplpMessageFilter)
4049 {
4050  struct apartment *apt;
4051  IMessageFilter *lpOldMessageFilter;
4052 
4053  TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
4054 
4055  apt = COM_CurrentApt();
4056 
4057  /* can't set a message filter in a multi-threaded apartment */
4058  if (!apt || apt->multi_threaded)
4059  {
4060  WARN("can't set message filter in MTA or uninitialized apt\n");
4061  return CO_E_NOT_SUPPORTED;
4062  }
4063 
4064  if (lpMessageFilter)
4065  IMessageFilter_AddRef(lpMessageFilter);
4066 
4067  EnterCriticalSection(&apt->cs);
4068 
4069  lpOldMessageFilter = apt->filter;
4070  apt->filter = lpMessageFilter;
4071 
4072  LeaveCriticalSection(&apt->cs);
4073 
4074  if (lplpMessageFilter)
4075  *lplpMessageFilter = lpOldMessageFilter;
4076  else if (lpOldMessageFilter)
4077  IMessageFilter_Release(lpOldMessageFilter);
4078 
4079  return S_OK;
4080 }
4081 
4082 /***********************************************************************
4083  * CoIsOle1Class [OLE32.@]
4084  *
4085  * Determines whether the specified class an OLE v1 class.
4086  *
4087  * PARAMS
4088  * clsid [I] Class to test.
4089  *
4090  * RETURNS
4091  * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4092  */
4094 {
4095  FIXME("%s\n", debugstr_guid(clsid));
4096  return FALSE;
4097 }
4098 
4099 /***********************************************************************
4100  * IsEqualGUID [OLE32.@]
4101  *
4102  * Compares two Unique Identifiers.
4103  *
4104  * PARAMS
4105  * rguid1 [I] The first GUID to compare.
4106  * rguid2 [I] The other GUID to compare.
4107  *
4108  * RETURNS
4109  * TRUE if equal
4110  */
4111 #undef IsEqualGUID
4113  REFGUID rguid1,
4114  REFGUID rguid2)
4115 {
4116  return !memcmp(rguid1,rguid2,sizeof(GUID));
4117 }
4118 
4119 /***********************************************************************
4120  * CoInitializeSecurity [OLE32.@]
4121  */
4123  SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4124  void* pReserved1, DWORD dwAuthnLevel,
4125  DWORD dwImpLevel, void* pReserved2,
4126  DWORD dwCapabilities, void* pReserved3)
4127 {
4128  FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4129  asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4130  dwCapabilities, pReserved3);
4131  return S_OK;
4132 }
4133 
4134 /***********************************************************************
4135  * CoSuspendClassObjects [OLE32.@]
4136  *
4137  * Suspends all registered class objects to prevent further requests coming in
4138  * for those objects.
4139  *
4140  * RETURNS
4141  * Success: S_OK.
4142  * Failure: HRESULT code.
4143  */
4145 {
4146  FIXME("\n");
4147  return S_OK;
4148 }
4149 
4150 /***********************************************************************
4151  * CoAddRefServerProcess [OLE32.@]
4152  *
4153  * Helper function for incrementing the reference count of a local-server
4154  * process.
4155  *
4156  * RETURNS
4157  * New reference count.
4158  *
4159  * SEE ALSO
4160  * CoReleaseServerProcess().
4161  */
4163 {
4164  ULONG refs;
4165 
4166  TRACE("\n");
4167 
4171 
4172  TRACE("refs before: %d\n", refs - 1);
4173 
4174  return refs;
4175 }
4176 
4177 /***********************************************************************
4178  * CoReleaseServerProcess [OLE32.@]
4179  *
4180  * Helper function for decrementing the reference count of a local-server
4181  * process.
4182  *
4183  * RETURNS
4184  * New reference count.
4185  *
4186  * NOTES
4187  * When reference count reaches 0, this function suspends all registered
4188  * classes so no new connections are accepted.
4189  *
4190  * SEE ALSO
4191  * CoAddRefServerProcess(), CoSuspendClassObjects().
4192  */
4194 {
4195  ULONG refs;
4196 
4197  TRACE("\n");
4198 
4200 
4202  /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4203 
4205 
4206  TRACE("refs after: %d\n", refs);
4207 
4208  return refs;
4209 }
4210 
4211 /***********************************************************************
4212  * CoIsHandlerConnected [OLE32.@]
4213  *
4214  * Determines whether a proxy is connected to a remote stub.
4215  *
4216  * PARAMS
4217  * pUnk [I] Pointer to object that may or may not be connected.
4218  *
4219  * RETURNS
4220  * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4221  * FALSE otherwise.
4222  */
4224 {
4225  FIXME("%p\n", pUnk);
4226 
4227  return TRUE;
4228 }
4229 
4230 /***********************************************************************
4231  * CoAllowSetForegroundWindow [OLE32.@]
4232  *
4233  */
4235 {
4236  FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4237  return S_OK;
4238 }
4239 
4240 /***********************************************************************
4241  * CoQueryProxyBlanket [OLE32.@]
4242  *
4243  * Retrieves the security settings being used by a proxy.
4244  *
4245  * PARAMS
4246  * pProxy [I] Pointer to the proxy object.
4247  * pAuthnSvc [O] The type of authentication service.
4248  * pAuthzSvc [O] The type of authorization service.
4249  * ppServerPrincName [O] Optional. The server prinicple name.
4250  * pAuthnLevel [O] The authentication level.
4251  * pImpLevel [O] The impersonation level.
4252  * ppAuthInfo [O] Information specific to the authorization/authentication service.
4253  * pCapabilities [O] Flags affecting the security behaviour.
4254  *
4255  * RETURNS
4256  * Success: S_OK.
4257  * Failure: HRESULT code.
4258  *
4259  * SEE ALSO
4260  * CoCopyProxy, CoSetProxyBlanket.
4261  */
4263  DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4264  DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4265 {
4266  IClientSecurity *pCliSec;
4267  HRESULT hr;
4268 
4269  TRACE("%p\n", pProxy);
4270 
4271  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4272  if (SUCCEEDED(hr))
4273  {
4274  hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4275  pAuthzSvc, ppServerPrincName,
4276  pAuthnLevel, pImpLevel, ppAuthInfo,
4277  pCapabilities);
4278  IClientSecurity_Release(pCliSec);
4279  }
4280 
4281  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4282  return hr;
4283 }
4284 
4285 /***********************************************************************
4286  * CoSetProxyBlanket [OLE32.@]
4287  *
4288  * Sets the security settings for a proxy.
4289  *
4290  * PARAMS
4291  * pProxy [I] Pointer to the proxy object.
4292  * AuthnSvc [I] The type of authentication service.
4293  * AuthzSvc [I] The type of authorization service.
4294  * pServerPrincName [I] The server prinicple name.
4295  * AuthnLevel [I] The authentication level.
4296  * ImpLevel [I] The impersonation level.
4297  * pAuthInfo [I] Information specific to the authorization/authentication service.
4298  * Capabilities [I] Flags affecting the security behaviour.
4299  *
4300  * RETURNS
4301  * Success: S_OK.
4302  * Failure: HRESULT code.
4303  *
4304  * SEE ALSO
4305  * CoQueryProxyBlanket, CoCopyProxy.
4306  */
4308  DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4309  DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4310 {
4311  IClientSecurity *pCliSec;
4312  HRESULT hr;
4313 
4314  TRACE("%p\n", pProxy);
4315 
4316  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4317  if (SUCCEEDED(hr))
4318  {
4319  hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4320  AuthzSvc, pServerPrincName,
4321  AuthnLevel, ImpLevel, pAuthInfo,
4322  Capabilities);
4323  IClientSecurity_Release(pCliSec);
4324  }
4325 
4326  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4327  return hr;
4328 }
4329 
4330 /***********************************************************************
4331  * CoCopyProxy [OLE32.@]
4332  *
4333  * Copies a proxy.
4334  *
4335  * PARAMS
4336  * pProxy [I] Pointer to the proxy object.
4337  * ppCopy [O] Copy of the proxy.
4338  *
4339  * RETURNS
4340  * Success: S_OK.
4341  * Failure: HRESULT code.
4342  *
4343  * SEE ALSO
4344  * CoQueryProxyBlanket, CoSetProxyBlanket.
4345  */
4347 {
4348  IClientSecurity *pCliSec;
4349  HRESULT hr;
4350 
4351  TRACE("%p\n", pProxy);
4352 
4353  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4354  if (SUCCEEDED(hr))
4355  {
4356  hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4357  IClientSecurity_Release(pCliSec);
4358  }
4359 
4360  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4361  return hr;
4362 }
4363 
4364 
4365 /***********************************************************************
4366  * CoGetCallContext [OLE32.@]
4367  *
4368  * Gets the context of the currently executing server call in the current
4369  * thread.
4370  *
4371  * PARAMS
4372  * riid [I] Context interface to return.
4373  * ppv [O] Pointer to memory that will receive the context on return.
4374  *
4375  * RETURNS
4376  * Success: S_OK.
4377  * Failure: HRESULT code.
4378  */
4380 {
4381  struct oletls *info = COM_CurrentInfo();
4382 
4383  TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4384 
4385  if (!info)
4386  return E_OUTOFMEMORY;
4387 
4388  if (!info->call_state)
4389  return RPC_E_CALL_COMPLETE;
4390 
4391  return IUnknown_QueryInterface(info->call_state, riid, ppv);
4392 }
4393 
4394 /***********************************************************************
4395  * CoSwitchCallContext [OLE32.@]
4396  *
4397  * Switches the context of the currently executing server call in the current
4398  * thread.
4399  *
4400  * PARAMS
4401  * pObject [I] Pointer to new context object
4402  * ppOldObject [O] Pointer to memory that will receive old context object pointer
4403  *
4404  * RETURNS
4405  * Success: S_OK.
4406  * Failure: HRESULT code.
4407  */
4409 {
4410  struct oletls *info = COM_CurrentInfo();
4411 
4412  TRACE("(%p, %p)\n", pObject, ppOldObject);
4413 
4414  if (!info)
4415  return E_OUTOFMEMORY;
4416 
4417  *ppOldObject = info->call_state;
4418  info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4419 
4420  return S_OK;
4421 }
4422 
4423 /***********************************************************************
4424  * CoQueryClientBlanket [OLE32.@]
4425  *
4426  * Retrieves the authentication information about the client of the currently
4427  * executing server call in the current thread.
4428  *
4429  * PARAMS
4430  * pAuthnSvc [O] Optional. The type of authentication service.
4431  * pAuthzSvc [O] Optional. The type of authorization service.
4432  * pServerPrincName [O] Optional. The server prinicple name.
4433  * pAuthnLevel [O] Optional. The authentication level.
4434  * pImpLevel [O] Optional. The impersonation level.
4435  * pPrivs [O] Optional. Information about the privileges of the client.
4436  * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4437  *
4438  * RETURNS
4439  * Success: S_OK.
4440  * Failure: HRESULT code.
4441  *
4442  * SEE ALSO
4443  * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4444  */
4446  DWORD *pAuthnSvc,
4447  DWORD *pAuthzSvc,
4448  OLECHAR **pServerPrincName,
4449  DWORD *pAuthnLevel,
4450  DWORD *pImpLevel,
4451  RPC_AUTHZ_HANDLE *pPrivs,
4452  DWORD *pCapabilities)
4453 {
4454  IServerSecurity *pSrvSec;
4455  HRESULT hr;
4456 
4457  TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4458  pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4459  pPrivs, pCapabilities);
4460 
4461  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4462  if (SUCCEEDED(hr))
4463  {
4464  hr = IServerSecurity_QueryBlanket(
4465  pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4466  pImpLevel, pPrivs, pCapabilities);
4467  IServerSecurity_Release(pSrvSec);
4468  }
4469 
4470  return hr;
4471 }
4472 
4473 /***********************************************************************
4474  * CoImpersonateClient [OLE32.@]
4475  *
4476  * Impersonates the client of the currently executing server call in the
4477  * current thread.
4478  *
4479  * PARAMS
4480  * None.
4481  *
4482  * RETURNS
4483  * Success: S_OK.
4484  * Failure: HRESULT code.
4485  *
4486  * NOTES
4487  * If this function fails then the current thread will not be impersonating
4488  * the client and all actions will take place on behalf of the server.
4489  * Therefore, it is important to check the return value from this function.
4490  *
4491  * SEE ALSO
4492  * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4493  */
4495 {
4496  IServerSecurity *pSrvSec;
4497  HRESULT hr;
4498 
4499  TRACE("\n");
4500 
4501  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4502  if (SUCCEEDED(hr))
4503  {
4504  hr = IServerSecurity_ImpersonateClient(pSrvSec);
4505  IServerSecurity_Release(pSrvSec);
4506  }
4507 
4508  return hr;
4509 }
4510 
4511 /***********************************************************************
4512  * CoRevertToSelf [OLE32.@]
4513  *
4514  * Ends the impersonation of the client of the currently executing server
4515  * call in the current thread.
4516  *
4517  * PARAMS
4518  * None.
4519  *
4520  * RETURNS
4521  * Success: S_OK.
4522  * Failure: HRESULT code.
4523  *
4524  * SEE ALSO
4525  * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4526  */
4528 {
4529  IServerSecurity *pSrvSec;
4530  HRESULT hr;
4531 
4532  TRACE("\n");
4533 
4534  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4535  if (SUCCEEDED(hr))
4536  {
4537  hr = IServerSecurity_RevertToSelf(pSrvSec);
4538  IServerSecurity_Release(pSrvSec);
4539  }
4540 
4541  return hr;
4542 }
4543 
4545 {
4546  /* first try to retrieve messages for incoming COM calls to the apartment window */
4547  return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4548  /* next retrieve other messages necessary for the app to remain responsive */
4550  PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4551 }
4552 
4553 /***********************************************************************
4554  * CoWaitForMultipleHandles [OLE32.@]
4555  *
4556  * Waits for one or more handles to become signaled.
4557  *
4558  * PARAMS
4559  * dwFlags [I] Flags. See notes.
4560  * dwTimeout [I] Timeout in milliseconds.
4561  * cHandles [I] Number of handles pointed to by pHandles.
4562  * pHandles [I] Handles to wait for.
4563  * lpdwindex [O] Index of handle that was signaled.
4564  *
4565  * RETURNS
4566  * Success: S_OK.
4567  * Failure: RPC_S_CALLPENDING on timeout.
4568  *
4569  * NOTES
4570  *
4571  * The dwFlags parameter can be zero or more of the following:
4572  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4573  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4574  *
4575  * SEE ALSO
4576  * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4577  */
4579  ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4580 {
4581  HRESULT hr = S_OK;
4582  DWORD start_time = GetTickCount();
4584  BOOL message_loop = apt && !apt->multi_threaded;
4585  BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4586  BOOL post_quit = FALSE;
4587  UINT exit_code;
4588 
4589  TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4590  pHandles, lpdwindex);
4591 
4592  if (!lpdwindex)
4593  return E_INVALIDARG;
4594 
4595  *lpdwindex = 0;
4596 
4597  if (!pHandles)
4598  return E_INVALIDARG;
4599 
4600  if (!cHandles)
4601  return RPC_E_NO_SYNC;
4602 
4603  while (TRUE)
4604  {
4605  DWORD now = GetTickCount();
4606  DWORD res;
4607 
4608  if (now - start_time > dwTimeout)
4609  {
4611  break;
4612  }
4613 
4614  if (message_loop)
4615  {
4616  DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4618 
4619  TRACE("waiting for rpc completion or window message\n");
4620 
4621  res = WAIT_TIMEOUT;
4622 
4623  if (check_apc)
4624  {
4625  res = WaitForMultipleObjectsEx(cHandles, pHandles,
4626  (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4627  check_apc = FALSE;
4628  }
4629 
4630  if (res == WAIT_TIMEOUT)
4631  res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4632  (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4633  QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4634 
4635  if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4636  {
4637  MSG msg;
4638  int count = 0;
4639 
4640  /* call message filter */
4641 
4642  if (COM_CurrentApt()->filter)
4643  {
4644  PENDINGTYPE pendingtype =
4645  COM_CurrentInfo()->pending_call_count_server ?
4646  PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4647  DWORD be_handled = IMessageFilter_MessagePending(
4648  COM_CurrentApt()->filter, 0 /* FIXME */,
4649  now - start_time, pendingtype);
4650  TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4651  switch (be_handled)
4652  {
4653  case PENDINGMSG_CANCELCALL:
4654  WARN("call canceled\n");
4656  break;
4657  case PENDINGMSG_WAITNOPROCESS:
4658