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