ReactOS  r75214
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  if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
2978  return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
2979  }
2980 
2981  if (CLSCTX_INPROC & dwClsContext)
2982  {
2983  ACTCTX_SECTION_KEYED_DATA data;
2984 
2985  data.cbSize = sizeof(data);
2986  /* search activation context first */
2987  if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2988  ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2989  rclsid, &data))
2990  {
2991  struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2992 
2993  clsreg.u.actctx.hactctx = data.hActCtx;
2994  clsreg.u.actctx.data = data.lpData;
2995  clsreg.u.actctx.section = data.lpSectionBase;
2996  clsreg.hkey = FALSE;
2997 
2998  hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2999  ReleaseActCtx(data.hActCtx);
3000  if (release_apt) apartment_release(apt);
3001  return hres;
3002  }
3003  }
3004 
3005  /*
3006  * First, try and see if we can't match the class ID with one of the
3007  * registered classes.
3008  */
3009  if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3010  &regClassObject))
3011  {
3012  /* Get the required interface from the retrieved pointer. */
3013  hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3014 
3015  /*
3016  * Since QI got another reference on the pointer, we want to release the
3017  * one we already have. If QI was unsuccessful, this will release the object. This
3018  * is good since we are not returning it in the "out" parameter.
3019  */
3020  IUnknown_Release(regClassObject);
3021  if (release_apt) apartment_release(apt);
3022  return hres;
3023  }
3024 
3025  /* First try in-process server */
3026  if (CLSCTX_INPROC_SERVER & dwClsContext)
3027  {
3028  static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3029  HKEY hkey;
3030 
3031  hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3032  if (FAILED(hres))
3033  {
3034  if (hres == REGDB_E_CLASSNOTREG)
3035  ERR("class %s not registered\n", debugstr_guid(rclsid));
3036  else if (hres == REGDB_E_KEYMISSING)
3037  {
3038  WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3039  hres = REGDB_E_CLASSNOTREG;
3040  }
3041  }
3042 
3043  if (SUCCEEDED(hres))
3044  {
3045  clsreg.u.hkey = hkey;
3046  clsreg.hkey = TRUE;
3047 
3048  hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3049  RegCloseKey(hkey);
3050  }
3051 
3052  /* return if we got a class, otherwise fall through to one of the
3053  * other types */
3054  if (SUCCEEDED(hres))
3055  {
3056  if (release_apt) apartment_release(apt);
3057  return hres;
3058  }
3059  }
3060 
3061  /* Next try in-process handler */
3062  if (CLSCTX_INPROC_HANDLER & dwClsContext)
3063  {
3064  static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3065  HKEY hkey;
3066 
3067  hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3068  if (FAILED(hres))
3069  {
3070  if (hres == REGDB_E_CLASSNOTREG)
3071  ERR("class %s not registered\n", debugstr_guid(rclsid));
3072  else if (hres == REGDB_E_KEYMISSING)
3073  {
3074  WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3075  hres = REGDB_E_CLASSNOTREG;
3076  }
3077  }
3078 
3079  if (SUCCEEDED(hres))
3080  {
3081  clsreg.u.hkey = hkey;
3082  clsreg.hkey = TRUE;
3083 
3084  hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3085  RegCloseKey(hkey);
3086  }
3087 
3088  /* return if we got a class, otherwise fall through to one of the
3089  * other types */
3090  if (SUCCEEDED(hres))
3091  {
3092  if (release_apt) apartment_release(apt);
3093  return hres;
3094  }
3095  }
3096  if (release_apt) apartment_release(apt);
3097 
3098  /* Next try out of process */
3099  if (CLSCTX_LOCAL_SERVER & dwClsContext)
3100  {
3101  hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3102  if (SUCCEEDED(hres))
3103  return hres;
3104  }
3105 
3106  /* Finally try remote: this requires networked DCOM (a lot of work) */
3107  if (CLSCTX_REMOTE_SERVER & dwClsContext)
3108  {
3109  FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3110  hres = REGDB_E_CLASSNOTREG;
3111  }
3112 
3113  if (FAILED(hres))
3114  ERR("no class object %s could be created for context 0x%x\n",
3115  debugstr_guid(rclsid), dwClsContext);
3116  return hres;
3117 }
3118 
3119 /***********************************************************************
3120  * CoResumeClassObjects (OLE32.@)
3121  *
3122  * Resumes all class objects registered with REGCLS_SUSPENDED.
3123  *
3124  * RETURNS
3125  * Success: S_OK.
3126  * Failure: HRESULT code.
3127  */
3129 {
3130  FIXME("stub\n");
3131  return S_OK;
3132 }
3133 
3134 /***********************************************************************
3135  * CoCreateInstance [OLE32.@]
3136  *
3137  * Creates an instance of the specified class.
3138  *
3139  * PARAMS
3140  * rclsid [I] Class ID to create an instance of.
3141  * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3142  * dwClsContext [I] Flags to restrict the location of the created instance.
3143  * iid [I] The ID of the interface of the instance to return.
3144  * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3145  *
3146  * RETURNS
3147  * Success: S_OK
3148  * Failure: HRESULT code.
3149  *
3150  * NOTES
3151  * The dwClsContext parameter can be one or more of the following:
3152  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3153  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3154  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3155  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3156  *
3157  * Aggregation is the concept of deferring the IUnknown of an object to another
3158  * object. This allows a separate object to behave as though it was part of
3159  * the object and to allow this the pUnkOuter parameter can be set. Note that
3160  * not all objects support having an outer of unknown.
3161  *
3162  * SEE ALSO
3163  * CoGetClassObject()
3164  */
3166  REFCLSID rclsid,
3167  LPUNKNOWN pUnkOuter,
3168  DWORD dwClsContext,
3169  REFIID iid,
3170  LPVOID *ppv)
3171 {
3172  MULTI_QI multi_qi = { iid };
3173  HRESULT hres;
3174 
3175  TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3176  pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3177 
3178  if (ppv==0)
3179  return E_POINTER;
3180 
3181  hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3182  *ppv = multi_qi.pItf;
3183  return hres;
3184 }
3185 
3186 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3187 {
3188  ULONG i;
3189 
3190  for (i = 0; i < count; i++)
3191  {
3192  mqi[i].pItf = NULL;
3193  mqi[i].hr = hr;
3194  }
3195 }
3196 
3197 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3198 {
3199  ULONG index = 0, fetched = 0;
3200 
3201  if (include_unk)
3202  {
3203  mqi[0].hr = S_OK;
3204  mqi[0].pItf = unk;
3205  index = fetched = 1;
3206  }
3207 
3208  for (; index < count; index++)
3209  {
3210  mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3211  if (mqi[index].hr == S_OK)
3212  fetched++;
3213  }
3214 
3215  if (!include_unk)
3216  IUnknown_Release(unk);
3217 
3218  if (fetched == 0)
3219  return E_NOINTERFACE;
3220 
3221  return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3222 }
3223 
3224 /***********************************************************************
3225  * CoCreateInstanceEx [OLE32.@]
3226  */
3228  REFCLSID rclsid,
3229  LPUNKNOWN pUnkOuter,
3230  DWORD dwClsContext,
3231  COSERVERINFO* pServerInfo,
3232  ULONG cmq,
3233  MULTI_QI* pResults)
3234 {
3235  IUnknown *unk = NULL;
3236  IClassFactory *cf;
3237  APARTMENT *apt;
3238  CLSID clsid;
3239  HRESULT hres;
3240 
3241  TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3242 
3243  if (!cmq || !pResults)
3244  return E_INVALIDARG;
3245 
3246  if (pServerInfo)
3247  FIXME("() non-NULL pServerInfo not supported!\n");
3248 
3249  init_multi_qi(cmq, pResults, E_NOINTERFACE);
3250 
3251  hres = CoGetTreatAsClass(rclsid, &clsid);
3252  if(FAILED(hres))
3253  clsid = *rclsid;
3254 
3255  if (!(apt = COM_CurrentApt()))
3256  {
3257  if (!(apt = apartment_find_multi_threaded()))
3258  {
3259  ERR("apartment not initialised\n");
3260  return CO_E_NOTINITIALIZED;
3261  }
3262  apartment_release(apt);
3263  }
3264 
3265  /*
3266  * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3267  */
3269  {
3271  TRACE("Retrieving GIT\n");
3272  return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3273  }
3274 
3275  if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3276  hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3277  if (FAILED(hres))
3278  return hres;
3279  return return_multi_qi(unk, cmq, pResults, TRUE);
3280  }
3281 
3282  /*
3283  * Get a class factory to construct the object we want.
3284  */
3285  hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3286  if (FAILED(hres))
3287  return hres;
3288 
3289  /*
3290  * Create the object and don't forget to release the factory
3291  */
3292  hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3293  IClassFactory_Release(cf);
3294  if (FAILED(hres))
3295  {
3296  if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3297  FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3298  else
3299  FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3300  debugstr_guid(pResults[0].pIID),
3301  debugstr_guid(&clsid),hres);
3302  return hres;
3303  }
3304 
3305  return return_multi_qi(unk, cmq, pResults, TRUE);
3306 }
3307 
3308 /***********************************************************************
3309  * CoGetInstanceFromFile [OLE32.@]
3310  */
3313  CLSID *rclsid,
3314  IUnknown *outer,
3315  DWORD cls_context,
3316  DWORD grfmode,
3317  OLECHAR *filename,
3318  DWORD count,
3319  MULTI_QI *results
3320 )
3321 {
3322  IPersistFile *pf = NULL;
3323  IUnknown* unk = NULL;
3324  CLSID clsid;
3325  HRESULT hr;
3326 
3327  if (count == 0 || !results)
3328  return E_INVALIDARG;
3329 
3330  if (server_info)
3331  FIXME("() non-NULL server_info not supported\n");
3332 
3333  init_multi_qi(count, results, E_NOINTERFACE);
3334 
3335  /* optionally get CLSID from a file */
3336  if (!rclsid)
3337  {
3338  hr = GetClassFile(filename, &clsid);
3339  if (FAILED(hr))
3340  {
3341  ERR("failed to get CLSID from a file\n");
3342  return hr;
3343  }
3344 
3345  rclsid = &clsid;
3346  }
3347 
3348  hr = CoCreateInstance(rclsid,
3349  outer,
3350  cls_context,
3351  &IID_IUnknown,
3352  (void**)&unk);
3353 
3354  if (hr != S_OK)
3355  {
3356  init_multi_qi(count, results, hr);
3357  return hr;
3358  }
3359 
3360  /* init from file */
3361  hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3362  if (FAILED(hr))
3363  {
3364  init_multi_qi(count, results, hr);
3365  IUnknown_Release(unk);
3366  return hr;
3367  }
3368 
3369  hr = IPersistFile_Load(pf, filename, grfmode);
3370  IPersistFile_Release(pf);
3371  if (SUCCEEDED(hr))
3372  return return_multi_qi(unk, count, results, FALSE);
3373  else
3374  {
3375  init_multi_qi(count, results, hr);
3376  IUnknown_Release(unk);
3377  return hr;
3378  }
3379 }
3380 
3381 /***********************************************************************
3382  * CoGetInstanceFromIStorage [OLE32.@]
3383  */
3386  CLSID *rclsid,
3387  IUnknown *outer,
3388  DWORD cls_context,
3389  IStorage *storage,
3390  DWORD count,
3391  MULTI_QI *results
3392 )
3393 {
3394  IPersistStorage *ps = NULL;
3395  IUnknown* unk = NULL;
3396  STATSTG stat;
3397  HRESULT hr;
3398 
3399  if (count == 0 || !results || !storage)
3400  return E_INVALIDARG;
3401 
3402  if (server_info)
3403  FIXME("() non-NULL server_info not supported\n");
3404 
3405  init_multi_qi(count, results, E_NOINTERFACE);
3406 
3407  /* optionally get CLSID from a file */
3408  if (!rclsid)
3409  {
3410  memset(&stat.clsid, 0, sizeof(stat.clsid));
3411  hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3412  if (FAILED(hr))
3413  {
3414  ERR("failed to get CLSID from a file\n");
3415  return hr;
3416  }
3417 
3418  rclsid = &stat.clsid;
3419  }
3420 
3421  hr = CoCreateInstance(rclsid,
3422  outer,
3423  cls_context,
3424  &IID_IUnknown,
3425  (void**)&unk);
3426 
3427  if (hr != S_OK)
3428  return hr;
3429 
3430  /* init from IStorage */
3431  hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3432  if (FAILED(hr))
3433  ERR("failed to get IPersistStorage\n");
3434 
3435  if (ps)
3436  {
3437  IPersistStorage_Load(ps, storage);
3438  IPersistStorage_Release(ps);
3439  }
3440 
3441  return return_multi_qi(unk, count, results, FALSE);
3442 }
3443 
3444 /***********************************************************************
3445  * CoLoadLibrary (OLE32.@)
3446  *
3447  * Loads a library.
3448  *
3449  * PARAMS
3450  * lpszLibName [I] Path to library.
3451  * bAutoFree [I] Whether the library should automatically be freed.
3452  *
3453  * RETURNS
3454  * Success: Handle to loaded library.
3455  * Failure: NULL.
3456  *
3457  * SEE ALSO
3458  * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3459  */
3460 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3461 {
3462  TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3463 
3464  return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3465 }
3466 
3467 /***********************************************************************
3468  * CoFreeLibrary [OLE32.@]
3469  *
3470  * Unloads a library from memory.
3471  *
3472  * PARAMS
3473  * hLibrary [I] Handle to library to unload.
3474  *
3475  * RETURNS
3476  * Nothing
3477  *
3478  * SEE ALSO
3479  * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3480  */
3482 {
3483  FreeLibrary(hLibrary);
3484 }
3485 
3486 
3487 /***********************************************************************
3488  * CoFreeAllLibraries [OLE32.@]
3489  *
3490  * Function for backwards compatibility only. Does nothing.
3491  *
3492  * RETURNS
3493  * Nothing.
3494  *
3495  * SEE ALSO
3496  * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3497  */
3499 {
3500  /* NOP */
3501 }
3502 
3503 /***********************************************************************
3504  * CoFreeUnusedLibrariesEx [OLE32.@]
3505  *
3506  * Frees any previously unused libraries whose delay has expired and marks
3507  * currently unused libraries for unloading. Unused are identified as those that
3508  * return S_OK from their DllCanUnloadNow function.
3509  *
3510  * PARAMS
3511  * dwUnloadDelay [I] Unload delay in milliseconds.
3512  * dwReserved [I] Reserved. Set to 0.
3513  *
3514  * RETURNS
3515  * Nothing.
3516  *
3517  * SEE ALSO
3518  * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3519  */
3521 {
3522  struct apartment *apt = COM_CurrentApt();
3523  if (!apt)
3524  {
3525  ERR("apartment not initialised\n");
3526  return;
3527  }
3528 
3529  apartment_freeunusedlibraries(apt, dwUnloadDelay);
3530 }
3531 
3532 /***********************************************************************
3533  * CoFreeUnusedLibraries [OLE32.@]
3534  *
3535  * Frees any unused libraries. Unused are identified as those that return
3536  * S_OK from their DllCanUnloadNow function.
3537  *
3538  * RETURNS
3539  * Nothing.
3540  *
3541  * SEE ALSO
3542  * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3543  */
3545 {
3547 }
3548 
3549 /***********************************************************************
3550  * CoFileTimeNow [OLE32.@]
3551  *
3552  * Retrieves the current time in FILETIME format.
3553  *
3554  * PARAMS
3555  * lpFileTime [O] The current time.
3556  *
3557  * RETURNS
3558  * S_OK.
3559  */
3561 {
3562  GetSystemTimeAsFileTime( lpFileTime );
3563  return S_OK;
3564 }
3565 
3566 /******************************************************************************
3567  * CoLockObjectExternal [OLE32.@]
3568  *
3569  * Increments or decrements the external reference count of a stub object.
3570  *
3571  * PARAMS
3572  * pUnk [I] Stub object.
3573  * fLock [I] If TRUE then increments the external ref-count,
3574  * otherwise decrements.
3575  * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3576  * calling CoDisconnectObject.
3577  *
3578  * RETURNS
3579  * Success: S_OK.
3580  * Failure: HRESULT code.
3581  *
3582  * NOTES
3583  * If fLock is TRUE and an object is passed in that doesn't have a stub
3584  * manager then a new stub manager is created for the object.
3585  */
3587  LPUNKNOWN pUnk,
3588  BOOL fLock,
3589  BOOL fLastUnlockReleases)
3590 {
3591  struct stub_manager *stubmgr;
3592  struct apartment *apt;
3593 
3594  TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3595  pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3596 
3597  apt = COM_CurrentApt();
3598  if (!apt) return CO_E_NOTINITIALIZED;
3599 
3600  stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3601  if (!stubmgr)
3602  {
3603  WARN("stub object not found %p\n", pUnk);
3604  /* Note: native is pretty broken here because it just silently
3605  * fails, without returning an appropriate error code, making apps
3606  * think that the object was disconnected, when it actually wasn't */
3607  return S_OK;
3608  }
3609 
3610  if (fLock)
3611  stub_manager_ext_addref(stubmgr, 1, FALSE);
3612  else
3613  stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3614 
3615  stub_manager_int_release(stubmgr);
3616  return S_OK;
3617 }
3618 
3619 /***********************************************************************
3620  * CoInitializeWOW (OLE32.@)
3621  *
3622  * WOW equivalent of CoInitialize?
3623  *
3624  * PARAMS
3625  * x [I] Unknown.
3626  * y [I] Unknown.
3627  *
3628  * RETURNS
3629  * Unknown.
3630  */
3632 {
3633  FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3634  return 0;
3635 }
3636 
3637 /***********************************************************************
3638  * CoGetState [OLE32.@]
3639  *
3640  * Retrieves the thread state object previously stored by CoSetState().
3641  *
3642  * PARAMS
3643  * ppv [I] Address where pointer to object will be stored.
3644  *
3645  * RETURNS
3646  * Success: S_OK.
3647  * Failure: E_OUTOFMEMORY.
3648  *
3649  * NOTES
3650  * Crashes on all invalid ppv addresses, including NULL.
3651  * If the function returns a non-NULL object then the caller must release its
3652  * reference on the object when the object is no longer required.
3653  *
3654  * SEE ALSO
3655  * CoSetState().
3656  */
3658 {
3659  struct oletls *info = COM_CurrentInfo();
3660  if (!info) return E_OUTOFMEMORY;
3661 
3662  *ppv = NULL;
3663 
3664  if (info->state)
3665  {
3666  IUnknown_AddRef(info->state);
3667  *ppv = info->state;
3668  TRACE("apt->state=%p\n", info->state);
3669  }
3670 
3671  return S_OK;
3672 }
3673 
3674 /***********************************************************************
3675  * CoSetState [OLE32.@]
3676  *
3677  * Sets the thread state object.
3678  *
3679  * PARAMS
3680  * pv [I] Pointer to state object to be stored.
3681  *
3682  * NOTES
3683  * The system keeps a reference on the object while the object stored.
3684  *
3685  * RETURNS
3686  * Success: S_OK.
3687  * Failure: E_OUTOFMEMORY.
3688  */
3690 {
3691  struct oletls *info = COM_CurrentInfo();
3692  if (!info) return E_OUTOFMEMORY;
3693 
3694  if (pv) IUnknown_AddRef(pv);
3695 
3696  if (info->state)
3697  {
3698  TRACE("-- release %p now\n", info->state);
3699  IUnknown_Release(info->state);
3700  }
3701 
3702  info->state = pv;
3703 
3704  return S_OK;
3705 }
3706 
3707 
3708 /******************************************************************************
3709  * CoTreatAsClass [OLE32.@]
3710  *
3711  * Sets the TreatAs value of a class.
3712  *
3713  * PARAMS
3714  * clsidOld [I] Class to set TreatAs value on.
3715  * clsidNew [I] The class the clsidOld should be treated as.
3716  *
3717  * RETURNS
3718  * Success: S_OK.
3719  * Failure: HRESULT code.
3720  *
3721  * SEE ALSO
3722  * CoGetTreatAsClass
3723  */
3725 {
3726  static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3727  static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3728  HKEY hkey = NULL;
3729  WCHAR szClsidNew[CHARS_IN_GUID];
3730  HRESULT res = S_OK;
3731  WCHAR auto_treat_as[CHARS_IN_GUID];
3732  LONG auto_treat_as_size = sizeof(auto_treat_as);
3733  CLSID id;
3734 
3735  res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3736  if (FAILED(res))
3737  goto done;
3738 
3739  if (IsEqualGUID( clsidOld, clsidNew ))
3740  {
3741  if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3742  CLSIDFromString(auto_treat_as, &id) == S_OK)
3743  {
3744  if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3745  {
3746  res = REGDB_E_WRITEREGDB;
3747  goto done;
3748  }
3749  }
3750  else
3751  {
3752  if(RegDeleteKeyW(hkey, wszTreatAs))
3753  res = REGDB_E_WRITEREGDB;
3754  goto done;
3755  }
3756  }
3757  else
3758  {
3759  if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3760  RegDeleteKeyW(hkey, wszTreatAs);
3761  }else{
3762  if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3763  WARN("StringFromGUID2 failed\n");
3764  res = E_FAIL;
3765  goto done;
3766  }
3767 
3768  if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3769  WARN("RegSetValue failed\n");
3770  res = REGDB_E_WRITEREGDB;
3771  goto done;
3772  }
3773  }
3774  }
3775 
3776 done:
3777  if (hkey) RegCloseKey(hkey);
3778  return res;
3779 }
3780 
3781 /******************************************************************************
3782  * CoGetTreatAsClass [OLE32.@]
3783  *
3784  * Gets the TreatAs value of a class.
3785  *
3786  * PARAMS
3787  * clsidOld [I] Class to get the TreatAs value of.
3788  * clsidNew [I] The class the clsidOld should be treated as.
3789  *
3790  * RETURNS
3791  * Success: S_OK.
3792  * Failure: HRESULT code.
3793  *
3794  * SEE ALSO
3795  * CoSetTreatAsClass
3796  */
3798 {
3799  static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3800  HKEY hkey = NULL;
3801  WCHAR szClsidNew[CHARS_IN_GUID];
3802  HRESULT res = S_OK;
3803  LONG len = sizeof(szClsidNew);
3804 
3805  TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3806  *clsidNew = *clsidOld; /* copy over old value */
3807 
3808  res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3809  if (FAILED(res))
3810  {
3811  res = S_FALSE;
3812  goto done;
3813  }
3814  if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3815  {
3816  res = S_FALSE;
3817  goto done;
3818  }
3819  res = CLSIDFromString(szClsidNew,clsidNew);
3820  if (FAILED(res))
3821  ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3822 done:
3823  if (hkey) RegCloseKey(hkey);
3824  return res;
3825 }
3826 
3827 /******************************************************************************
3828  * CoGetCurrentProcess [OLE32.@]
3829  *
3830  * Gets the current process ID.
3831  *
3832  * RETURNS
3833  * The current process ID.
3834  *
3835  * NOTES
3836  * Is DWORD really the correct return type for this function?
3837  */
3839 {
3840  return GetCurrentProcessId();
3841 }
3842 
3843 /***********************************************************************
3844  * CoGetCurrentLogicalThreadId [OLE32.@]
3845  */
3847 {
3848  TRACE("(%p)\n", id);
3849 
3850  if (!id)
3851  return E_INVALIDARG;
3852 
3853  *id = COM_CurrentCausalityId();
3854  return S_OK;
3855 }
3856 
3857 /******************************************************************************
3858  * CoRegisterMessageFilter [OLE32.@]
3859  *
3860  * Registers a message filter.
3861  *
3862  * PARAMS
3863  * lpMessageFilter [I] Pointer to interface.
3864  * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3865  *
3866  * RETURNS
3867  * Success: S_OK.
3868  * Failure: HRESULT code.
3869  *
3870  * NOTES
3871  * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3872  * lpMessageFilter removes the message filter.
3873  *
3874  * If lplpMessageFilter is not NULL the previous message filter will be
3875  * returned in the memory pointer to this parameter and the caller is
3876  * responsible for releasing the object.
3877  *
3878  * The current thread be in an apartment otherwise the function will crash.
3879  */
3881  LPMESSAGEFILTER lpMessageFilter,
3882  LPMESSAGEFILTER *lplpMessageFilter)
3883 {
3884  struct apartment *apt;
3885  IMessageFilter *lpOldMessageFilter;
3886 
3887  TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3888 
3889  apt = COM_CurrentApt();
3890 
3891  /* can't set a message filter in a multi-threaded apartment */
3892  if (!apt || apt->multi_threaded)
3893  {
3894  WARN("can't set message filter in MTA or uninitialized apt\n");
3895  return CO_E_NOT_SUPPORTED;
3896  }
3897 
3898  if (lpMessageFilter)
3899  IMessageFilter_AddRef(lpMessageFilter);
3900 
3901  EnterCriticalSection(&apt->cs);
3902 
3903  lpOldMessageFilter = apt->filter;
3904  apt->filter = lpMessageFilter;
3905 
3906  LeaveCriticalSection(&apt->cs);
3907 
3908  if (lplpMessageFilter)
3909  *lplpMessageFilter = lpOldMessageFilter;
3910  else if (lpOldMessageFilter)
3911  IMessageFilter_Release(lpOldMessageFilter);
3912 
3913  return S_OK;
3914 }
3915 
3916 /***********************************************************************
3917  * CoIsOle1Class [OLE32.@]
3918  *
3919  * Determines whether the specified class an OLE v1 class.
3920  *
3921  * PARAMS
3922  * clsid [I] Class to test.
3923  *
3924  * RETURNS
3925  * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3926  */
3928 {
3929  FIXME("%s\n", debugstr_guid(clsid));
3930  return FALSE;
3931 }
3932 
3933 /***********************************************************************
3934  * IsEqualGUID [OLE32.@]
3935  *
3936  * Compares two Unique Identifiers.
3937  *
3938  * PARAMS
3939  * rguid1 [I] The first GUID to compare.
3940  * rguid2 [I] The other GUID to compare.
3941  *
3942  * RETURNS
3943  * TRUE if equal
3944  */
3945 #undef IsEqualGUID
3947  REFGUID rguid1,
3948  REFGUID rguid2)
3949 {
3950  return !memcmp(rguid1,rguid2,sizeof(GUID));
3951 }
3952 
3953 /***********************************************************************
3954  * CoInitializeSecurity [OLE32.@]
3955  */
3957  SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3958  void* pReserved1, DWORD dwAuthnLevel,
3959  DWORD dwImpLevel, void* pReserved2,
3960  DWORD dwCapabilities, void* pReserved3)
3961 {
3962  FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3963  asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3964  dwCapabilities, pReserved3);
3965  return S_OK;
3966 }
3967 
3968 /***********************************************************************
3969  * CoSuspendClassObjects [OLE32.@]
3970  *
3971  * Suspends all registered class objects to prevent further requests coming in
3972  * for those objects.
3973  *
3974  * RETURNS
3975  * Success: S_OK.
3976  * Failure: HRESULT code.
3977  */
3979 {
3980  FIXME("\n");
3981  return S_OK;
3982 }
3983 
3984 /***********************************************************************
3985  * CoAddRefServerProcess [OLE32.@]
3986  *
3987  * Helper function for incrementing the reference count of a local-server
3988  * process.
3989  *
3990  * RETURNS
3991  * New reference count.
3992  *
3993  * SEE ALSO
3994  * CoReleaseServerProcess().
3995  */
3997 {
3998  ULONG refs;
3999 
4000  TRACE("\n");
4001 
4002  EnterCriticalSection(&csRegisteredClassList);
4004  LeaveCriticalSection(&csRegisteredClassList);
4005 
4006  TRACE("refs before: %d\n", refs - 1);
4007 
4008  return refs;
4009 }
4010 
4011 /***********************************************************************
4012  * CoReleaseServerProcess [OLE32.@]
4013  *
4014  * Helper function for decrementing the reference count of a local-server
4015  * process.
4016  *
4017  * RETURNS
4018  * New reference count.
4019  *
4020  * NOTES
4021  * When reference count reaches 0, this function suspends all registered
4022  * classes so no new connections are accepted.
4023  *
4024  * SEE ALSO
4025  * CoAddRefServerProcess(), CoSuspendClassObjects().
4026  */
4028 {
4029  ULONG refs;
4030 
4031  TRACE("\n");
4032 
4033  EnterCriticalSection(&csRegisteredClassList);
4034 
4036  /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4037 
4038  LeaveCriticalSection(&csRegisteredClassList);
4039 
4040  TRACE("refs after: %d\n", refs);
4041 
4042  return refs;
4043 }
4044 
4045 /***********************************************************************
4046  * CoIsHandlerConnected [OLE32.@]
4047  *
4048  * Determines whether a proxy is connected to a remote stub.
4049  *
4050  * PARAMS
4051  * pUnk [I] Pointer to object that may or may not be connected.
4052  *
4053  * RETURNS
4054  * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4055  * FALSE otherwise.
4056  */
4058 {
4059  FIXME("%p\n", pUnk);
4060 
4061  return TRUE;
4062 }
4063 
4064 /***********************************************************************
4065  * CoAllowSetForegroundWindow [OLE32.@]
4066  *
4067  */
4069 {
4070  FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4071  return S_OK;
4072 }
4073 
4074 /***********************************************************************
4075  * CoQueryProxyBlanket [OLE32.@]
4076  *
4077  * Retrieves the security settings being used by a proxy.
4078  *
4079  * PARAMS
4080  * pProxy [I] Pointer to the proxy object.
4081  * pAuthnSvc [O] The type of authentication service.
4082  * pAuthzSvc [O] The type of authorization service.
4083  * ppServerPrincName [O] Optional. The server prinicple name.
4084  * pAuthnLevel [O] The authentication level.
4085  * pImpLevel [O] The impersonation level.
4086  * ppAuthInfo [O] Information specific to the authorization/authentication service.
4087  * pCapabilities [O] Flags affecting the security behaviour.
4088  *
4089  * RETURNS
4090  * Success: S_OK.
4091  * Failure: HRESULT code.
4092  *
4093  * SEE ALSO
4094  * CoCopyProxy, CoSetProxyBlanket.
4095  */
4097  DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4098  DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4099 {
4100  IClientSecurity *pCliSec;
4101  HRESULT hr;
4102 
4103  TRACE("%p\n", pProxy);
4104 
4105  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4106  if (SUCCEEDED(hr))
4107  {
4108  hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4109  pAuthzSvc, ppServerPrincName,
4110  pAuthnLevel, pImpLevel, ppAuthInfo,
4111  pCapabilities);
4112  IClientSecurity_Release(pCliSec);
4113  }
4114 
4115  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4116  return hr;
4117 }
4118 
4119 /***********************************************************************
4120  * CoSetProxyBlanket [OLE32.@]
4121  *
4122  * Sets the security settings for a proxy.
4123  *
4124  * PARAMS
4125  * pProxy [I] Pointer to the proxy object.
4126  * AuthnSvc [I] The type of authentication service.
4127  * AuthzSvc [I] The type of authorization service.
4128  * pServerPrincName [I] The server prinicple name.
4129  * AuthnLevel [I] The authentication level.
4130  * ImpLevel [I] The impersonation level.
4131  * pAuthInfo [I] Information specific to the authorization/authentication service.
4132  * Capabilities [I] Flags affecting the security behaviour.
4133  *
4134  * RETURNS
4135  * Success: S_OK.
4136  * Failure: HRESULT code.
4137  *
4138  * SEE ALSO
4139  * CoQueryProxyBlanket, CoCopyProxy.
4140  */
4142  DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4143  DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4144 {
4145  IClientSecurity *pCliSec;
4146  HRESULT hr;
4147 
4148  TRACE("%p\n", pProxy);
4149 
4150  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4151  if (SUCCEEDED(hr))
4152  {
4153  hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4154  AuthzSvc, pServerPrincName,
4155  AuthnLevel, ImpLevel, pAuthInfo,
4156  Capabilities);
4157  IClientSecurity_Release(pCliSec);
4158  }
4159 
4160  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4161  return hr;
4162 }
4163 
4164 /***********************************************************************
4165  * CoCopyProxy [OLE32.@]
4166  *
4167  * Copies a proxy.
4168  *
4169  * PARAMS
4170  * pProxy [I] Pointer to the proxy object.
4171  * ppCopy [O] Copy of the proxy.
4172  *
4173  * RETURNS
4174  * Success: S_OK.
4175  * Failure: HRESULT code.
4176  *
4177  * SEE ALSO
4178  * CoQueryProxyBlanket, CoSetProxyBlanket.
4179  */
4181 {
4182  IClientSecurity *pCliSec;
4183  HRESULT hr;
4184 
4185  TRACE("%p\n", pProxy);
4186 
4187  hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4188  if (SUCCEEDED(hr))
4189  {
4190  hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4191  IClientSecurity_Release(pCliSec);
4192  }
4193 
4194  if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4195  return hr;
4196 }
4197 
4198 
4199 /***********************************************************************
4200  * CoGetCallContext [OLE32.@]
4201  *
4202  * Gets the context of the currently executing server call in the current
4203  * thread.
4204  *
4205  * PARAMS
4206  * riid [I] Context interface to return.
4207  * ppv [O] Pointer to memory that will receive the context on return.
4208  *
4209  * RETURNS
4210  * Success: S_OK.
4211  * Failure: HRESULT code.
4212  */
4214 {
4215  struct oletls *info = COM_CurrentInfo();
4216 
4217  TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4218 
4219  if (!info)
4220  return E_OUTOFMEMORY;
4221 
4222  if (!info->call_state)
4223  return RPC_E_CALL_COMPLETE;
4224 
4225  return IUnknown_QueryInterface(info->call_state, riid, ppv);
4226 }
4227 
4228 /***********************************************************************
4229  * CoSwitchCallContext [OLE32.@]
4230  *
4231  * Switches the context of the currently executing server call in the current
4232  * thread.
4233  *
4234  * PARAMS
4235  * pObject [I] Pointer to new context object
4236  * ppOldObject [O] Pointer to memory that will receive old context object pointer
4237  *
4238  * RETURNS
4239  * Success: S_OK.
4240  * Failure: HRESULT code.
4241  */
4243 {
4244  struct oletls *info = COM_CurrentInfo();
4245 
4246  TRACE("(%p, %p)\n", pObject, ppOldObject);
4247 
4248  if (!info)
4249  return E_OUTOFMEMORY;
4250 
4251  *ppOldObject = info->call_state;
4252  info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4253 
4254  return S_OK;
4255 }
4256 
4257 /***********************************************************************
4258  * CoQueryClientBlanket [OLE32.@]
4259  *
4260  * Retrieves the authentication information about the client of the currently
4261  * executing server call in the current thread.
4262  *
4263  * PARAMS
4264  * pAuthnSvc [O] Optional. The type of authentication service.
4265  * pAuthzSvc [O] Optional. The type of authorization service.
4266  * pServerPrincName [O] Optional. The server prinicple name.
4267  * pAuthnLevel [O] Optional. The authentication level.
4268  * pImpLevel [O] Optional. The impersonation level.
4269  * pPrivs [O] Optional. Information about the privileges of the client.
4270  * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4271  *
4272  * RETURNS
4273  * Success: S_OK.
4274  * Failure: HRESULT code.
4275  *
4276  * SEE ALSO
4277  * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4278  */
4280  DWORD *pAuthnSvc,
4281  DWORD *pAuthzSvc,
4282  OLECHAR **pServerPrincName,
4283  DWORD *pAuthnLevel,
4284  DWORD *pImpLevel,
4285  RPC_AUTHZ_HANDLE *pPrivs,
4286  DWORD *pCapabilities)
4287 {
4288  IServerSecurity *pSrvSec;
4289  HRESULT hr;
4290 
4291  TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4292  pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4293  pPrivs, pCapabilities);
4294 
4295  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4296  if (SUCCEEDED(hr))
4297  {
4298  hr = IServerSecurity_QueryBlanket(
4299  pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4300  pImpLevel, pPrivs, pCapabilities);
4301  IServerSecurity_Release(pSrvSec);
4302  }
4303 
4304  return hr;
4305 }
4306 
4307 /***********************************************************************
4308  * CoImpersonateClient [OLE32.@]
4309  *
4310  * Impersonates the client of the currently executing server call in the
4311  * current thread.
4312  *
4313  * PARAMS
4314  * None.
4315  *
4316  * RETURNS
4317  * Success: S_OK.
4318  * Failure: HRESULT code.
4319  *
4320  * NOTES
4321  * If this function fails then the current thread will not be impersonating
4322  * the client and all actions will take place on behalf of the server.
4323  * Therefore, it is important to check the return value from this function.
4324  *
4325  * SEE ALSO
4326  * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4327  */
4329 {
4330  IServerSecurity *pSrvSec;
4331  HRESULT hr;
4332 
4333  TRACE("\n");
4334 
4335  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4336  if (SUCCEEDED(hr))
4337  {
4338  hr = IServerSecurity_ImpersonateClient(pSrvSec);
4339  IServerSecurity_Release(pSrvSec);
4340  }
4341 
4342  return hr;
4343 }
4344 
4345 /***********************************************************************
4346  * CoRevertToSelf [OLE32.@]
4347  *
4348  * Ends the impersonation of the client of the currently executing server
4349  * call in the current thread.
4350  *
4351  * PARAMS
4352  * None.
4353  *
4354  * RETURNS
4355  * Success: S_OK.
4356  * Failure: HRESULT code.
4357  *
4358  * SEE ALSO
4359  * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4360  */
4362 {
4363  IServerSecurity *pSrvSec;
4364  HRESULT hr;
4365 
4366  TRACE("\n");
4367 
4368  hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4369  if (SUCCEEDED(hr))
4370  {
4371  hr = IServerSecurity_RevertToSelf(pSrvSec);
4372  IServerSecurity_Release(pSrvSec);
4373  }
4374 
4375  return hr;
4376 }
4377 
4379 {
4380  /* first try to retrieve messages for incoming COM calls to the apartment window */
4381  return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4382  /* next retrieve other messages necessary for the app to remain responsive */
4384  PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4385 }
4386 
4387 /***********************************************************************
4388  * CoWaitForMultipleHandles [OLE32.@]
4389  *
4390  * Waits for one or more handles to become signaled.
4391  *
4392  * PARAMS
4393  * dwFlags [I] Flags. See notes.
4394  * dwTimeout [I] Timeout in milliseconds.
4395  * cHandles [I] Number of handles pointed to by pHandles.
4396  * pHandles [I] Handles to wait for.
4397  * lpdwindex [O] Index of handle that was signaled.
4398  *
4399  * RETURNS
4400  * Success: S_OK.
4401  * Failure: RPC_S_CALLPENDING on timeout.
4402  *
4403  * NOTES
4404  *
4405  * The dwFlags parameter can be zero or more of the following:
4406  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4407  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4408  *
4409  * SEE ALSO
4410  * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4411  */
4413  ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4414 {
4415  HRESULT hr = S_OK;
4416  DWORD start_time = GetTickCount();
4418  BOOL message_loop = apt && !apt->multi_threaded;
4419  BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4420 
4421  TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4422  pHandles, lpdwindex);
4423 
4424  if (!lpdwindex)
4425  return E_INVALIDARG;
4426 
4427  *lpdwindex = 0;
4428 
4429  if (!pHandles)
4430  return E_INVALIDARG;
4431 
4432  if (!cHandles)
4433  return RPC_E_NO_SYNC;
4434 
4435  while (TRUE)
4436  {
4437  DWORD now = GetTickCount();
4438  DWORD res;
4439 
4440  if (now - start_time > dwTimeout)
4441  {
4442  hr = RPC_S_CALLPENDING;
4443  break;
4444  }
4445 
4446  if (message_loop)
4447  {
4448  DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4449  ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4450 
4451  TRACE("waiting for rpc completion or window message\n");
4452 
4453  res = WAIT_TIMEOUT;
4454 
4455  if (check_apc)
4456  {
4457  res = WaitForMultipleObjectsEx(cHandles, pHandles,
4458  (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4459  check_apc = FALSE;
4460  }
4461 
4462  if (res == WAIT_TIMEOUT)
4463  res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4464  (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4465  QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4466 
4467  if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4468  {
4469  MSG msg;
4470  int count = 0;
4471 
4472  /* call message filter */
4473 
4474  if (COM_CurrentApt()->filter)
4475  {
4476  PENDINGTYPE pendingtype =
4477  COM_CurrentInfo()->pending_call_count_server ?
4478  PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4479  DWORD be_handled = IMessageFilter_MessagePending(
4480  COM_CurrentApt()->filter, 0 /* FIXME */,
4481  now - start_time, pendingtype);
4482  TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4483  switch (be_handled)
4484  {
4485  case PENDINGMSG_CANCELCALL:
4486  WARN("call canceled\n");
4487  hr = RPC_E_CALL_CANCELED;
4488  break;
4489  case PENDINGMSG_WAITNOPROCESS:
4490  case PENDINGMSG_WAITDEFPROCESS:
4491  default:
4492  /* FIXME: MSDN is very vague about the difference
4493  * between WAITNOPROCESS and WAITDEFPROCESS - there
4494  * appears to be none, so it is possibly a left-over
4495  * from the 16-bit world. */
4496  break;
4497  }
4498  }
4499 
4500  /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4501  * so after processing 100 messages we go back to checking the wait handles */
4502  while (count++ < 100 && COM_PeekMessage(apt, &msg))
4503  {
4504  TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4505  TranslateMessage(&msg);
4506  DispatchMessageW(&msg);
4507  if (msg.message == WM_QUIT)
4508  {
4509  TRACE("resending WM_QUIT to outer message loop\n");
4510  PostQuitMessage(msg.wParam);
4511  /* no longer need to process messages */
4512  message_loop = FALSE;
4513  break;
4514  }
4515  }
4516  continue;
4517  }
4518  }
4519  else
4520  {
4521  TRACE("waiting for rpc completion\n");
4522 
4523  res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4524  (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4525  (dwFlags & COWAIT_ALERTABLE) != 0);
4526  }
4527 
4528  switch (res)
4529  {
4530  case WAIT_TIMEOUT:
4531  hr = RPC_S_CALLPENDING;
4532  break;
4533  case WAIT_FAILED:
4534  hr = HRESULT_FROM_WIN32( GetLastError() );
4535  break;
4536  default:
4537  *lpdwindex = res;
4538  break;
4539  }
4540  break;
4541  }
4542  TRACE("-- 0x%08x\n", hr);
4543  return hr;
4544 }
4545 
4546 
4547 /***********************************************************************
4548  * CoGetObject [OLE32.@]
4549  *
4550  * Gets the object named by converting the name to a moniker and binding to it.
4551  *
4552  * PARAMS
4553  * pszName [I] String representing the object.
4554  * pBindOptions [I] Parameters affecting the binding to the named object.
4555  * riid [I] Interface to bind to on the objecct.
4556  * ppv [O] On output, the interface riid of the object represented
4557  * by pszName.
4558  *
4559  * RETURNS
4560  * Success: S_OK.
4561  * Failure: HRESULT code.
4562  *
4563  * SEE ALSO
4564  * MkParseDisplayName.
4565  */
4566 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4567  REFIID riid, void **ppv)
4568 {
4569  IBindCtx *pbc;
4570  HRESULT hr;
4571 
4572  *ppv = NULL;
4573 
4574  hr = CreateBindCtx(0, &pbc);
4575  if (SUCCEEDED(hr))
4576  {
4577  if (pBindOptions)
4578  hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4579 
4580  if (SUCCEEDED(hr))
4581  {
4582  ULONG chEaten;
4583  IMoniker *pmk;
4584 
4585  hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4586  if (SUCCEEDED(hr))
4587  {
4588  hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4589  IMoniker_Release(pmk);
4590  }
4591  }
4592 
4593  IBindCtx_Release(pbc);
4594  }
4595  return hr;
4596 }
4597 
4598 /***********************************************************************
4599  * CoRegisterChannelHook [OLE32.@]
4600  *
4601  * Registers a process-wide hook that is called during ORPC calls.
4602  *
4603  * PARAMS
4604  * guidExtension [I] GUID of the channel hook to register.
4605  * pChannelHook [I] Channel hook object to register.
4606  *
4607  * RETURNS
4608  * Success: S_OK.
4609  * Failure: HRESULT code.
4610  */
4612 {
4613  TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4614 
4615  return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4616 }
4617 
4618 typedef struct Context
4619 {
4624 } Context;
4625 
4627 {
4628  return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4629 }
4630 
4632 {
4633  return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4634 }
4635 
4637 {
4638  return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4639 }
4640 
4642 {
4643  *ppv = NULL;
4644 
4645  if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4646  IsEqualIID(riid, &IID_IUnknown))
4647  {
4648  *ppv = &iface->IComThreadingInfo_iface;
4649  }
4650  else if (IsEqualIID(riid, &IID_IContextCallback))
4651  {
4652  *ppv = &iface->IContextCallback_iface;
4653  }
4654  else if (IsEqualIID(riid, &IID_IObjContext))
4655  {
4656  *ppv = &iface->IObjContext_iface;
4657  }
4658 
4659  if (*ppv)
4660  {
4661  IUnknown_AddRef((IUnknown*)*ppv);
4662  return S_OK;
4663  }
4664 
4665  FIXME("interface not implemented %s\n", debugstr_guid(riid));
4666  return E_NOINTERFACE;
4667 }
4668 
4670 {
4671  return InterlockedIncrement(&This->refs);
4672 }
4673 
4675 {
4676  /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4677  releasing context while refcount is at 0 destroys it. */
4678  if (!This->refs)
4679  {
4680  HeapFree(GetProcessHeap(), 0, This);
4681  return 0;
4682  }
4683 
4684  return InterlockedDecrement(&This->refs);
4685 }
4686 
4688 {
4689  Context *This = impl_from_IComThreadingInfo(iface);
4690  return Context_QueryInterface(This, riid, ppv);
4691 }
4692 
4694 {
4695  Context *This = impl_from_IComThreadingInfo(iface);
4696  return Context_AddRef(This);
4697 }
4698 
4700 {
4701  Context *This = impl_from_IComThreadingInfo(iface);
4702  return Context_Release(This);
4703 }
4704 
4706 {
4708 
4709  TRACE("(%p)\n", apttype);
4710 
4711  return CoGetApartmentType(apttype, &qualifier);
4712 }
4713 
4715 {
4717  APTTYPE apttype;
4718  HRESULT hr;
4719 
4720  hr = CoGetApartmentType(&apttype, &qualifier);
4721  if (FAILED(hr))
4722  return hr;
4723 
4724  TRACE("(%p)\n", thdtype);
4725 
4726  switch (apttype)
4727  {
4728  case APTTYPE_STA:
4729  case APTTYPE_MAINSTA:
4730  *thdtype = THDTYPE_PROCESSMESSAGES;
4731  break;
4732  default:
4733  *thdtype = THDTYPE_BLOCKMESSAGES;
4734  break;
4735  }
4736  return S_OK;
4737 }
4738 
4740 {
4741  TRACE("(%p)\n", logical_thread_id);
4742  return CoGetCurrentLogicalThreadId(logical_thread_id);
4743 }
4744 
4746 {
4747  FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4748  return E_NOTIMPL;
4749 }
4750 
4751 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4752 {
4760 };
4761 
4763 {
4764  Context *This = impl_from_IContextCallback(iface);
4765  return Context_QueryInterface(This, riid, ppv);
4766 }
4767 
4769 {
4770  Context *This = impl_from_IContextCallback(iface);
4771  return Context_AddRef(This);
4772 }
4773 
4775 {
4776  Context *This = impl_from_IContextCallback(iface);
4777  return Context_Release(This);
4778 }
4779 
4780 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4781  ComCallData *param, REFIID riid, int method, IUnknown *punk)
4782 {
4783  Context *This = impl_from_IContextCallback(iface);
4784 
4785  FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4786  return E_NOTIMPL;
4787 }
4788 
4789 static const IContextCallbackVtbl Context_Callback_Vtbl =
4790 {
4795 };
4796 
4798 {
4799  Context *This = impl_from_IObjContext(iface);
4800  return Context_QueryInterface(This, riid, ppv);
4801 }
4802 
4804 {
4805  Context *This = impl_from_IObjContext(iface);
4806  return Context_AddRef(This);
4807 }
4808 
4810 {
4811  Context *This = impl_from_IObjContext(iface);
4812  return Context_Release(This);
4813 }
4814 
4816 {
4817  Context *This = impl_from_IObjContext(iface);
4818 
4819  FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4820  return E_NOTIMPL;
4821 }
4822 
4824 {
4825  Context *This = impl_from_IObjContext(iface);
4826 
4827  FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4828  return E_NOTIMPL;
4829 }
4830 
4832 {
4833  Context *This = impl_from_IObjContext(iface);
4834 
4835  FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4836  return E_NOTIMPL;
4837 }
4838 
4840 {
4841  Context *This = impl_from_IObjContext(iface);
4842 
4843  FIXME("(%p/%p)->(%p)\n", This, iface, props);
4844  return E_NOTIMPL;
4845 }
4846 
4848 {
4849  Context *This = impl_from_IObjContext(iface);
4850  FIXME("(%p/%p)\n", This, iface);
4851 }
4852 
4854 {
4855  Context *This = impl_from_IObjContext(iface);
4856  FIXME("(%p/%p)\n", This, iface);
4857 }
4858 
4860 {
4861  Context *This = impl_from_IObjContext(iface);
4862  FIXME("(%p/%p)\n", This, iface);
4863 }
4864 
4866 {
4867  Context *This = impl_from_IObjContext(iface);
4868  FIXME("(%p/%p)\n", This, iface);
4869 }
4870 
4872 {
4873  Context *This = impl_from_IObjContext(iface);
4874  FIXME("(%p/%p)\n", This, iface);
4875 }
4876 
4878 {
4879  Context *This = impl_from_IObjContext(iface);
4880  FIXME("(%p/%p)\n", This, iface);
4881 }
4882 
4884 {
4885  Context *This = impl_from_IObjContext(iface);
4886  FIXME("(%p/%p)\n", This, iface);
4887 }
4888 
4889 static const IObjContextVtbl Context_Object_Vtbl =
4890 {
4905 };
4906 
4907 /***********************************************************************
4908  * CoGetObjectContext [OLE32.@]
4909  *
4910  * Retrieves an object associated with the current context (i.e. apartment).
4911  *
4912  * PARAMS
4913  * riid [I] ID of the interface of the object to retrieve.
4914  * ppv [O] Address where object will be stored on return.
4915  *
4916  * RETURNS
4917  * Success: S_OK.
4918  * Failure: HRESULT code.
4919  */
4921 {
4923  HRESULT hr;
4924 
4925  TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4926 
4927  *ppv = NULL;
4928  hr = CoGetContextToken((ULONG_PTR*)&context);
4929  if (FAILED(hr))
4930  return hr;
4931 
4932  return IObjContext_QueryInterface(context, riid, ppv);
4933 }
4934 
4935 /***********************************************************************
4936  * CoGetContextToken [OLE32.@]
4937  */
4939 {
4940  struct oletls *info = COM_CurrentInfo();
4941 
4942  TRACE("(%p)\n", token);
4943 
4944  if (!info)
4945  return E_OUTOFMEMORY;
4946 
4947  if (!info->apt)
4948  {
4949  APARTMENT *apt;
4950  if (!(apt = apartment_find_multi_threaded()))
4951  {
4952  ERR("apartment not initialised\n");
4953  return CO_E_NOTINITIALIZED;
4954  }
4955  apartment_release(apt);
4956  }
4957 
4958  if (!token)
4959  return E_POINTER;
4960 
4961  if (!info->context_token)
4962  {
4963  Context *context;
4964 
4965  context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4966  if (!context)
4967  return E_OUTOFMEMORY;
4968 
4970  context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4971  context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4972  /* Context token does not take a reference, it's always zero until the
4973  interface is explicitly requested with CoGetObjectContext(). */
4974  context->refs = 0;
4975 
4976  info->context_token = &context->IObjContext_iface;
4977  }
4978 
4979  *token = (ULONG_PTR)info->context_token;
4980  TRACE("context_token=%p\n", info->context_token);
4981 
4982  return S_OK;
4983 }
4984 
4985 /***********************************************************************
4986  * CoGetDefaultContext [OLE32.@]
4987  */
4989 {
4990  FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4991  return E_NOINTERFACE;
4992 }
4993 
4995 {
4996  static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4997  HKEY hkey;
4998  HRESULT hres;
4999 
5000  hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5001  if (SUCCEEDED(hres))
5002  {
5003  struct class_reg_data regdata;
5004  WCHAR dllpath[MAX_PATH+1];
5005 
5006  regdata.u.hkey = hkey;
5007  regdata.<