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