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