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