ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

compobj.c
Go to the documentation of this file.
00001 /*
00002  *  COMPOBJ library
00003  *
00004  *  Copyright 1995  Martin von Loewis
00005  *  Copyright 1998  Justin Bradford
00006  *      Copyright 1999  Francis Beaudet
00007  *      Copyright 1999  Sylvain St-Germain
00008  *      Copyright 2002  Marcus Meissner
00009  *      Copyright 2004  Mike Hearn
00010  *      Copyright 2005-2006 Robert Shearman (for CodeWeavers)
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Lesser General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2.1 of the License, or (at your option) any later version.
00016  *
00017  * This library is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Lesser General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Lesser General Public
00023  * License along with this library; if not, write to the Free Software
00024  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00025  *
00026  * Note
00027  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
00028  *    Therefore do not test against COINIT_MULTITHREADED
00029  *
00030  * TODO list:           (items bunched together depend on each other)
00031  *
00032  *   - Implement the service control manager (in rpcss) to keep track
00033  *     of registered class objects: ISCM::ServerRegisterClsid et al
00034  *   - Implement the OXID resolver so we don't need magic endpoint names for
00035  *     clients and servers to meet up
00036  *
00037  */
00038 
00039 #include "config.h"
00040 
00041 #include <stdarg.h>
00042 #include <stdio.h>
00043 #include <string.h>
00044 #include <assert.h>
00045 
00046 #define COBJMACROS
00047 #define NONAMELESSUNION
00048 #define NONAMELESSSTRUCT
00049 
00050 #include "windef.h"
00051 #include "winbase.h"
00052 #include "winerror.h"
00053 #include "winreg.h"
00054 #include "winuser.h"
00055 #define USE_COM_CONTEXT_DEF
00056 #include "objbase.h"
00057 #include "ole2.h"
00058 #include "ole2ver.h"
00059 #include "ctxtcall.h"
00060 #include "dde.h"
00061 
00062 #include "initguid.h"
00063 #include "compobj_private.h"
00064 #include "moniker.h"
00065 
00066 #include "wine/unicode.h"
00067 #include "wine/debug.h"
00068 
00069 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00070 
00071 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
00072 
00073 #ifdef _MSC_VER
00074 DEFINE_GUID(CLSID_PSFactoryBuffer, 0x00000320, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
00075 #endif
00076 
00077 /****************************************************************************
00078  * This section defines variables internal to the COM module.
00079  */
00080 
00081 static APARTMENT *MTA; /* protected by csApartment */
00082 static APARTMENT *MainApartment; /* the first STA apartment */
00083 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
00084 
00085 static CRITICAL_SECTION csApartment;
00086 static CRITICAL_SECTION_DEBUG critsect_debug =
00087 {
00088     0, 0, &csApartment,
00089     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
00090       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
00091 };
00092 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
00093 
00094 struct registered_psclsid
00095 {
00096     struct list entry;
00097     IID iid;
00098     CLSID clsid;
00099 };
00100 
00101 /*
00102  * This lock count counts the number of times CoInitialize is called. It is
00103  * decreased every time CoUninitialize is called. When it hits 0, the COM
00104  * libraries are freed
00105  */
00106 static LONG s_COMLockCount = 0;
00107 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
00108 static LONG s_COMServerProcessReferences = 0;
00109 
00110 /*
00111  * This linked list contains the list of registered class objects. These
00112  * are mostly used to register the factories for out-of-proc servers of OLE
00113  * objects.
00114  *
00115  * TODO: Make this data structure aware of inter-process communication. This
00116  *       means that parts of this will be exported to rpcss.
00117  */
00118 typedef struct tagRegisteredClass
00119 {
00120   struct list entry;
00121   CLSID     classIdentifier;
00122   OXID      apartment_id;
00123   LPUNKNOWN classObject;
00124   DWORD     runContext;
00125   DWORD     connectFlags;
00126   DWORD     dwCookie;
00127   LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
00128   void     *RpcRegistration;
00129 } RegisteredClass;
00130 
00131 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
00132 
00133 static CRITICAL_SECTION csRegisteredClassList;
00134 static CRITICAL_SECTION_DEBUG class_cs_debug =
00135 {
00136     0, 0, &csRegisteredClassList,
00137     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
00138       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
00139 };
00140 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
00141 
00142 /*****************************************************************************
00143  * This section contains OpenDllList definitions
00144  *
00145  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
00146  * other functions that do LoadLibrary _without_ giving back a HMODULE.
00147  * Without this list these handles would never be freed.
00148  *
00149  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
00150  * next unload-call but not before 600 sec.
00151  */
00152 
00153 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
00154 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
00155 
00156 typedef struct tagOpenDll
00157 {
00158   LONG refs;
00159   LPWSTR library_name;
00160   HANDLE library;
00161   DllGetClassObjectFunc DllGetClassObject;
00162   DllCanUnloadNowFunc DllCanUnloadNow;
00163   struct list entry;
00164 } OpenDll;
00165 
00166 static struct list openDllList = LIST_INIT(openDllList);
00167 
00168 static CRITICAL_SECTION csOpenDllList;
00169 static CRITICAL_SECTION_DEBUG dll_cs_debug =
00170 {
00171     0, 0, &csOpenDllList,
00172     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
00173       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
00174 };
00175 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
00176 
00177 struct apartment_loaded_dll
00178 {
00179     struct list entry;
00180     OpenDll *dll;
00181     DWORD unload_time;
00182     BOOL multi_threaded;
00183 };
00184 
00185 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',' ',
00186                                        '0','x','#','#','#','#','#','#','#','#',' ',0};
00187 
00188 /*****************************************************************************
00189  * This section contains OpenDllList implementation
00190  */
00191 
00192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
00193 {
00194     OpenDll *ptr;
00195     OpenDll *ret = NULL;
00196     EnterCriticalSection(&csOpenDllList);
00197     LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
00198     {
00199         if (!strcmpiW(library_name, ptr->library_name) &&
00200             (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
00201         {
00202             ret = ptr;
00203             break;
00204         }
00205     }
00206     LeaveCriticalSection(&csOpenDllList);
00207     return ret;
00208 }
00209 
00210 /* caller must ensure that library_name is not already in the open dll list */
00211 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
00212 {
00213     OpenDll *entry;
00214     int len;
00215     HRESULT hr = S_OK;
00216     HANDLE hLibrary;
00217     DllCanUnloadNowFunc DllCanUnloadNow;
00218     DllGetClassObjectFunc DllGetClassObject;
00219 
00220     TRACE("\n");
00221 
00222     *ret = COMPOBJ_DllList_Get(library_name);
00223     if (*ret) return S_OK;
00224 
00225     /* do this outside the csOpenDllList to avoid creating a lock dependency on
00226      * the loader lock */
00227     hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
00228     if (!hLibrary)
00229     {
00230         ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
00231         /* failure: DLL could not be loaded */
00232         return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
00233     }
00234 
00235     DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
00236     /* Note: failing to find DllCanUnloadNow is not a failure */
00237     DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
00238     if (!DllGetClassObject)
00239     {
00240         /* failure: the dll did not export DllGetClassObject */
00241         ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
00242         FreeLibrary(hLibrary);
00243         return CO_E_DLLNOTFOUND;
00244     }
00245 
00246     EnterCriticalSection( &csOpenDllList );
00247 
00248     *ret = COMPOBJ_DllList_Get(library_name);
00249     if (*ret)
00250     {
00251         /* another caller to this function already added the dll while we
00252          * weren't in the critical section */
00253         FreeLibrary(hLibrary);
00254     }
00255     else
00256     {
00257         len = strlenW(library_name);
00258         entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
00259         if (entry)
00260             entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
00261         if (entry && entry->library_name)
00262         {
00263             memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
00264             entry->library = hLibrary;
00265             entry->refs = 1;
00266             entry->DllCanUnloadNow = DllCanUnloadNow;
00267             entry->DllGetClassObject = DllGetClassObject;
00268             list_add_tail(&openDllList, &entry->entry);
00269         }
00270         else
00271         {
00272             HeapFree(GetProcessHeap(), 0, entry);
00273             hr = E_OUTOFMEMORY;
00274             FreeLibrary(hLibrary);
00275         }
00276         *ret = entry;
00277     }
00278 
00279     LeaveCriticalSection( &csOpenDllList );
00280 
00281     return hr;
00282 }
00283 
00284 /* pass FALSE for free_entry to release a reference without destroying the
00285  * entry if it reaches zero or TRUE otherwise */
00286 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
00287 {
00288     if (!InterlockedDecrement(&entry->refs) && free_entry)
00289     {
00290         EnterCriticalSection(&csOpenDllList);
00291         list_remove(&entry->entry);
00292         LeaveCriticalSection(&csOpenDllList);
00293 
00294         TRACE("freeing %p\n", entry->library);
00295         FreeLibrary(entry->library);
00296 
00297         HeapFree(GetProcessHeap(), 0, entry->library_name);
00298         HeapFree(GetProcessHeap(), 0, entry);
00299     }
00300 }
00301 
00302 /* frees memory associated with active dll list */
00303 static void COMPOBJ_DllList_Free(void)
00304 {
00305     OpenDll *entry, *cursor2;
00306     EnterCriticalSection(&csOpenDllList);
00307     LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
00308     {
00309         list_remove(&entry->entry);
00310 
00311         HeapFree(GetProcessHeap(), 0, entry->library_name);
00312         HeapFree(GetProcessHeap(), 0, entry);
00313     }
00314     LeaveCriticalSection(&csOpenDllList);
00315     DeleteCriticalSection(&csOpenDllList);
00316 }
00317 
00318 /******************************************************************************
00319  * Manage apartments.
00320  */
00321 
00322 static DWORD apartment_addref(struct apartment *apt)
00323 {
00324     DWORD refs = InterlockedIncrement(&apt->refs);
00325     TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
00326     return refs;
00327 }
00328 
00329 /* allocates memory and fills in the necessary fields for a new apartment
00330  * object. must be called inside apartment cs */
00331 static APARTMENT *apartment_construct(DWORD model)
00332 {
00333     APARTMENT *apt;
00334 
00335     TRACE("creating new apartment, model=%d\n", model);
00336 
00337     apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
00338     apt->tid = GetCurrentThreadId();
00339 
00340     list_init(&apt->proxies);
00341     list_init(&apt->stubmgrs);
00342     list_init(&apt->psclsids);
00343     list_init(&apt->loaded_dlls);
00344     apt->ipidc = 0;
00345     apt->refs = 1;
00346     apt->remunk_exported = FALSE;
00347     apt->oidc = 1;
00348     InitializeCriticalSection(&apt->cs);
00349     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
00350 
00351     apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
00352 
00353     if (apt->multi_threaded)
00354     {
00355         /* FIXME: should be randomly generated by in an RPC call to rpcss */
00356         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
00357     }
00358     else
00359     {
00360         /* FIXME: should be randomly generated by in an RPC call to rpcss */
00361         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
00362     }
00363 
00364     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
00365 
00366     list_add_head(&apts, &apt->entry);
00367 
00368     return apt;
00369 }
00370 
00371 /* gets and existing apartment if one exists or otherwise creates an apartment
00372  * structure which stores OLE apartment-local information and stores a pointer
00373  * to it in the thread-local storage */
00374 static APARTMENT *apartment_get_or_create(DWORD model)
00375 {
00376     APARTMENT *apt = COM_CurrentApt();
00377 
00378     if (!apt)
00379     {
00380         if (model & COINIT_APARTMENTTHREADED)
00381         {
00382             EnterCriticalSection(&csApartment);
00383 
00384             apt = apartment_construct(model);
00385             if (!MainApartment)
00386             {
00387                 MainApartment = apt;
00388                 apt->main = TRUE;
00389                 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
00390             }
00391 
00392             LeaveCriticalSection(&csApartment);
00393 
00394             if (apt->main)
00395                 apartment_createwindowifneeded(apt);
00396         }
00397         else
00398         {
00399             EnterCriticalSection(&csApartment);
00400 
00401             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
00402              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
00403              * in a process */
00404             if (MTA)
00405             {
00406                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
00407                 apartment_addref(MTA);
00408             }
00409             else
00410                 MTA = apartment_construct(model);
00411 
00412             apt = MTA;
00413 
00414             LeaveCriticalSection(&csApartment);
00415         }
00416         COM_CurrentInfo()->apt = apt;
00417     }
00418 
00419     return apt;
00420 }
00421 
00422 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
00423 {
00424     return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
00425 }
00426 
00427 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
00428 {
00429     list_remove(&curClass->entry);
00430 
00431     if (curClass->runContext & CLSCTX_LOCAL_SERVER)
00432         RPC_StopLocalServer(curClass->RpcRegistration);
00433 
00434     /*
00435      * Release the reference to the class object.
00436      */
00437     IUnknown_Release(curClass->classObject);
00438 
00439     if (curClass->pMarshaledData)
00440     {
00441         LARGE_INTEGER zero;
00442         memset(&zero, 0, sizeof(zero));
00443         IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
00444         CoReleaseMarshalData(curClass->pMarshaledData);
00445         IStream_Release(curClass->pMarshaledData);
00446     }
00447 
00448     HeapFree(GetProcessHeap(), 0, curClass);
00449 }
00450 
00451 static void COM_RevokeAllClasses(const struct apartment *apt)
00452 {
00453   RegisteredClass *curClass, *cursor;
00454 
00455   EnterCriticalSection( &csRegisteredClassList );
00456 
00457   LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
00458   {
00459     if (curClass->apartment_id == apt->oxid)
00460       COM_RevokeRegisteredClassObject(curClass);
00461   }
00462 
00463   LeaveCriticalSection( &csRegisteredClassList );
00464 }
00465 
00466 /******************************************************************************
00467  * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
00468  */
00469 
00470 typedef struct ManualResetEvent {
00471     ISynchronize   ISynchronize_iface;
00472     LONG ref;
00473     HANDLE event;
00474 } MREImpl;
00475 
00476 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
00477 {
00478     return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
00479 }
00480 
00481 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
00482 {
00483     MREImpl *This = impl_from_ISynchronize(iface);
00484     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
00485 
00486     *ppv = NULL;
00487     if(IsEqualGUID(riid, &IID_IUnknown) ||
00488        IsEqualGUID(riid, &IID_ISynchronize))
00489         *ppv = This;
00490     else
00491         ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
00492 
00493     if(*ppv)
00494     {
00495         IUnknown_AddRef((IUnknown*)*ppv);
00496         return S_OK;
00497     }
00498 
00499     return E_NOINTERFACE;
00500 }
00501 
00502 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
00503 {
00504     MREImpl *This = impl_from_ISynchronize(iface);
00505     LONG ref = InterlockedIncrement(&This->ref);
00506     TRACE("%p - ref %d\n", This, ref);
00507 
00508     return ref;
00509 }
00510 
00511 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
00512 {
00513     MREImpl *This = impl_from_ISynchronize(iface);
00514     LONG ref = InterlockedDecrement(&This->ref);
00515     TRACE("%p - ref %d\n", This, ref);
00516 
00517     if(!ref)
00518     {
00519         CloseHandle(This->event);
00520         HeapFree(GetProcessHeap(), 0, This);
00521     }
00522 
00523     return ref;
00524 }
00525 
00526 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
00527 {
00528     MREImpl *This = impl_from_ISynchronize(iface);
00529     UINT index;
00530     TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
00531     return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
00532 }
00533 
00534 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
00535 {
00536     MREImpl *This = impl_from_ISynchronize(iface);
00537     TRACE("%p\n", This);
00538     SetEvent(This->event);
00539     return S_OK;
00540 }
00541 
00542 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
00543 {
00544     MREImpl *This = impl_from_ISynchronize(iface);
00545     TRACE("%p\n", This);
00546     ResetEvent(This->event);
00547     return S_OK;
00548 }
00549 
00550 static ISynchronizeVtbl vt_ISynchronize = {
00551     ISynchronize_fnQueryInterface,
00552     ISynchronize_fnAddRef,
00553     ISynchronize_fnRelease,
00554     ISynchronize_fnWait,
00555     ISynchronize_fnSignal,
00556     ISynchronize_fnReset
00557 };
00558 
00559 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
00560 {
00561     MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
00562     HRESULT hr;
00563 
00564     if(punkouter)
00565         FIXME("Aggregation not implemented.\n");
00566 
00567     This->ref = 1;
00568     This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
00569     This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
00570 
00571     hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
00572     ISynchronize_Release(&This->ISynchronize_iface);
00573     return hr;
00574 }
00575 
00576 /***********************************************************************
00577  *           CoRevokeClassObject [OLE32.@]
00578  *
00579  * Removes a class object from the class registry.
00580  *
00581  * PARAMS
00582  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
00583  *
00584  * RETURNS
00585  *  Success: S_OK.
00586  *  Failure: HRESULT code.
00587  *
00588  * NOTES
00589  *  Must be called from the same apartment that called CoRegisterClassObject(),
00590  *  otherwise it will fail with RPC_E_WRONG_THREAD.
00591  *
00592  * SEE ALSO
00593  *  CoRegisterClassObject
00594  */
00595 HRESULT WINAPI CoRevokeClassObject(
00596         DWORD dwRegister)
00597 {
00598   HRESULT hr = E_INVALIDARG;
00599   RegisteredClass *curClass;
00600   APARTMENT *apt;
00601 
00602   TRACE("(%08x)\n",dwRegister);
00603 
00604   apt = COM_CurrentApt();
00605   if (!apt)
00606   {
00607     ERR("COM was not initialized\n");
00608     return CO_E_NOTINITIALIZED;
00609   }
00610 
00611   EnterCriticalSection( &csRegisteredClassList );
00612 
00613   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
00614   {
00615     /*
00616      * Check if we have a match on the cookie.
00617      */
00618     if (curClass->dwCookie == dwRegister)
00619     {
00620       if (curClass->apartment_id == apt->oxid)
00621       {
00622           COM_RevokeRegisteredClassObject(curClass);
00623           hr = S_OK;
00624       }
00625       else
00626       {
00627           ERR("called from wrong apartment, should be called from %s\n",
00628               wine_dbgstr_longlong(curClass->apartment_id));
00629           hr = RPC_E_WRONG_THREAD;
00630       }
00631       break;
00632     }
00633   }
00634 
00635   LeaveCriticalSection( &csRegisteredClassList );
00636 
00637   return hr;
00638 }
00639 
00640 /* frees unused libraries loaded by apartment_getclassobject by calling the
00641  * DLL's DllCanUnloadNow entry point */
00642 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
00643 {
00644     struct apartment_loaded_dll *entry, *next;
00645     EnterCriticalSection(&apt->cs);
00646     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
00647     {
00648     if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
00649         {
00650             DWORD real_delay = delay;
00651 
00652             if (real_delay == INFINITE)
00653             {
00654                 /* DLLs that return multi-threaded objects aren't unloaded
00655                  * straight away to cope for programs that have races between
00656                  * last object destruction and threads in the DLLs that haven't
00657                  * finished, despite DllCanUnloadNow returning S_OK */
00658                 if (entry->multi_threaded)
00659                     real_delay = 10 * 60 * 1000; /* 10 minutes */
00660                 else
00661                     real_delay = 0;
00662             }
00663 
00664             if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
00665             {
00666                 list_remove(&entry->entry);
00667                 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
00668                 HeapFree(GetProcessHeap(), 0, entry);
00669             }
00670             else
00671                 entry->unload_time = GetTickCount() + real_delay;
00672         }
00673         else if (entry->unload_time)
00674             entry->unload_time = 0;
00675     }
00676     LeaveCriticalSection(&apt->cs);
00677 }
00678 
00679 DWORD apartment_release(struct apartment *apt)
00680 {
00681     DWORD ret;
00682 
00683     EnterCriticalSection(&csApartment);
00684 
00685     ret = InterlockedDecrement(&apt->refs);
00686     TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
00687     /* destruction stuff that needs to happen under csApartment CS */
00688     if (ret == 0)
00689     {
00690         if (apt == MTA) MTA = NULL;
00691         else if (apt == MainApartment) MainApartment = NULL;
00692         list_remove(&apt->entry);
00693     }
00694 
00695     LeaveCriticalSection(&csApartment);
00696 
00697     if (ret == 0)
00698     {
00699         struct list *cursor, *cursor2;
00700 
00701         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
00702 
00703         /* Release the references to the registered class objects */
00704         COM_RevokeAllClasses(apt);
00705 
00706         /* no locking is needed for this apartment, because no other thread
00707          * can access it at this point */
00708 
00709         apartment_disconnectproxies(apt);
00710 
00711         if (apt->win) DestroyWindow(apt->win);
00712         if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
00713 
00714         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
00715         {
00716             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
00717             /* release the implicit reference given by the fact that the
00718              * stub has external references (it must do since it is in the
00719              * stub manager list in the apartment and all non-apartment users
00720              * must have a ref on the apartment and so it cannot be destroyed).
00721              */
00722             stub_manager_int_release(stubmgr);
00723         }
00724 
00725         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
00726         {
00727             struct registered_psclsid *registered_psclsid =
00728                 LIST_ENTRY(cursor, struct registered_psclsid, entry);
00729 
00730             list_remove(&registered_psclsid->entry);
00731             HeapFree(GetProcessHeap(), 0, registered_psclsid);
00732         }
00733 
00734         /* if this assert fires, then another thread took a reference to a
00735          * stub manager without taking a reference to the containing
00736          * apartment, which it must do. */
00737         assert(list_empty(&apt->stubmgrs));
00738 
00739         if (apt->filter) IUnknown_Release(apt->filter);
00740 
00741         /* free as many unused libraries as possible... */
00742         apartment_freeunusedlibraries(apt, 0);
00743 
00744         /* ... and free the memory for the apartment loaded dll entry and
00745          * release the dll list reference without freeing the library for the
00746          * rest */
00747         while ((cursor = list_head(&apt->loaded_dlls)))
00748         {
00749             struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
00750             COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
00751             list_remove(cursor);
00752             HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
00753         }
00754 
00755         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
00756         DeleteCriticalSection(&apt->cs);
00757 
00758         HeapFree(GetProcessHeap(), 0, apt);
00759     }
00760 
00761     return ret;
00762 }
00763 
00764 /* The given OXID must be local to this process: 
00765  *
00766  * The ref parameter is here mostly to ensure people remember that
00767  * they get one, you should normally take a ref for thread safety.
00768  */
00769 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
00770 {
00771     APARTMENT *result = NULL;
00772     struct list *cursor;
00773 
00774     EnterCriticalSection(&csApartment);
00775     LIST_FOR_EACH( cursor, &apts )
00776     {
00777         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
00778         if (apt->oxid == oxid)
00779         {
00780             result = apt;
00781             if (ref) apartment_addref(result);
00782             break;
00783         }
00784     }
00785     LeaveCriticalSection(&csApartment);
00786 
00787     return result;
00788 }
00789 
00790 /* gets the apartment which has a given creator thread ID. The caller must
00791  * release the reference from the apartment as soon as the apartment pointer
00792  * is no longer required. */
00793 APARTMENT *apartment_findfromtid(DWORD tid)
00794 {
00795     APARTMENT *result = NULL;
00796     struct list *cursor;
00797 
00798     EnterCriticalSection(&csApartment);
00799     LIST_FOR_EACH( cursor, &apts )
00800     {
00801         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
00802         if (apt->tid == tid)
00803         {
00804             result = apt;
00805             apartment_addref(result);
00806             break;
00807         }
00808     }
00809     LeaveCriticalSection(&csApartment);
00810 
00811     return result;
00812 }
00813 
00814 /* gets the main apartment if it exists. The caller must
00815  * release the reference from the apartment as soon as the apartment pointer
00816  * is no longer required. */
00817 static APARTMENT *apartment_findmain(void)
00818 {
00819     APARTMENT *result;
00820 
00821     EnterCriticalSection(&csApartment);
00822 
00823     result = MainApartment;
00824     if (result) apartment_addref(result);
00825 
00826     LeaveCriticalSection(&csApartment);
00827 
00828     return result;
00829 }
00830 
00831 /* gets the multi-threaded apartment if it exists. The caller must
00832  * release the reference from the apartment as soon as the apartment pointer
00833  * is no longer required. */
00834 static APARTMENT *apartment_find_multi_threaded(void)
00835 {
00836     APARTMENT *result = NULL;
00837     struct list *cursor;
00838 
00839     EnterCriticalSection(&csApartment);
00840 
00841     LIST_FOR_EACH( cursor, &apts )
00842     {
00843         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
00844         if (apt->multi_threaded)
00845         {
00846             result = apt;
00847             apartment_addref(result);
00848             break;
00849         }
00850     }
00851 
00852     LeaveCriticalSection(&csApartment);
00853     return result;
00854 }
00855 
00856 /* gets the specified class object by loading the appropriate DLL, if
00857  * necessary and calls the DllGetClassObject function for the DLL */
00858 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
00859                                         BOOL apartment_threaded,
00860                                         REFCLSID rclsid, REFIID riid, void **ppv)
00861 {
00862     static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
00863     HRESULT hr = S_OK;
00864     BOOL found = FALSE;
00865     struct apartment_loaded_dll *apartment_loaded_dll;
00866 
00867     if (!strcmpiW(dllpath, wszOle32))
00868     {
00869         /* we don't need to control the lifetime of this dll, so use the local
00870          * implementation of DllGetClassObject directly */
00871         TRACE("calling ole32!DllGetClassObject\n");
00872         hr = DllGetClassObject(rclsid, riid, ppv);
00873 
00874         if (hr != S_OK)
00875             ERR("DllGetClassObject returned error 0x%08x\n", hr);
00876 
00877         return hr;
00878     }
00879 
00880     EnterCriticalSection(&apt->cs);
00881 
00882     LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
00883         if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
00884         {
00885             TRACE("found %s already loaded\n", debugstr_w(dllpath));
00886             found = TRUE;
00887             break;
00888         }
00889 
00890     if (!found)
00891     {
00892         apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
00893         if (!apartment_loaded_dll)
00894             hr = E_OUTOFMEMORY;
00895         if (SUCCEEDED(hr))
00896         {
00897             apartment_loaded_dll->unload_time = 0;
00898             apartment_loaded_dll->multi_threaded = FALSE;
00899             hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
00900             if (FAILED(hr))
00901                 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
00902         }
00903         if (SUCCEEDED(hr))
00904         {
00905             TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
00906             list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
00907         }
00908     }
00909 
00910     LeaveCriticalSection(&apt->cs);
00911 
00912     if (SUCCEEDED(hr))
00913     {
00914         /* one component being multi-threaded overrides any number of
00915          * apartment-threaded components */
00916         if (!apartment_threaded)
00917             apartment_loaded_dll->multi_threaded = TRUE;
00918 
00919         TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
00920         /* OK: get the ClassObject */
00921         hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
00922 
00923         if (hr != S_OK)
00924             ERR("DllGetClassObject returned error 0x%08x\n", hr);
00925     }
00926 
00927     return hr;
00928 }
00929 
00930 /***********************************************************************
00931  *  COM_RegReadPath [internal]
00932  *
00933  *  Reads a registry value and expands it when necessary
00934  */
00935 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
00936 {
00937     DWORD ret;
00938     HKEY key;
00939     DWORD keytype;
00940     WCHAR src[MAX_PATH];
00941     DWORD dwLength = dstlen * sizeof(WCHAR);
00942 
00943     if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
00944           if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
00945             if (keytype == REG_EXPAND_SZ) {
00946               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
00947             } else {
00948               const WCHAR *quote_start;
00949               quote_start = strchrW(src, '\"');
00950               if (quote_start) {
00951                 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
00952                 if (quote_end) {
00953                   memmove(src, quote_start + 1,
00954                           (quote_end - quote_start - 1) * sizeof(WCHAR));
00955                   src[quote_end - quote_start - 1] = '\0';
00956                 }
00957               }
00958               lstrcpynW(dst, src, dstlen);
00959             }
00960       }
00961           RegCloseKey (key);
00962     }
00963     return ret;
00964 }
00965 
00966 struct host_object_params
00967 {
00968     HKEY hkeydll;
00969     CLSID clsid; /* clsid of object to marshal */
00970     IID iid; /* interface to marshal */
00971     HANDLE event; /* event signalling when ready for multi-threaded case */
00972     HRESULT hr; /* result for multi-threaded case */
00973     IStream *stream; /* stream that the object will be marshaled into */
00974     BOOL apartment_threaded; /* is the component purely apartment-threaded? */
00975 };
00976 
00977 static HRESULT apartment_hostobject(struct apartment *apt,
00978                                     const struct host_object_params *params)
00979 {
00980     IUnknown *object;
00981     HRESULT hr;
00982     static const LARGE_INTEGER llZero;
00983     WCHAR dllpath[MAX_PATH+1];
00984 
00985     TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
00986 
00987     if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
00988     {
00989         /* failure: CLSID is not found in registry */
00990         WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
00991         return REGDB_E_CLASSNOTREG;
00992     }
00993 
00994     hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
00995                                   &params->clsid, &params->iid, (void **)&object);
00996     if (FAILED(hr))
00997         return hr;
00998 
00999     hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
01000     if (FAILED(hr))
01001         IUnknown_Release(object);
01002     IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
01003 
01004     return hr;
01005 }
01006 
01007 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
01008 {
01009     switch (msg)
01010     {
01011     case DM_EXECUTERPC:
01012         RPC_ExecuteCall((struct dispatch_params *)lParam);
01013         return 0;
01014     case DM_HOSTOBJECT:
01015         return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
01016     default:
01017         return DefWindowProcW(hWnd, msg, wParam, lParam);
01018     }
01019 }
01020 
01021 struct host_thread_params
01022 {
01023     COINIT threading_model;
01024     HANDLE ready_event;
01025     HWND apartment_hwnd;
01026 };
01027 
01028 /* thread for hosting an object to allow an object to appear to be created in
01029  * an apartment with an incompatible threading model */
01030 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
01031 {
01032     struct host_thread_params *params = p;
01033     MSG msg;
01034     HRESULT hr;
01035     struct apartment *apt;
01036 
01037     TRACE("\n");
01038 
01039     hr = CoInitializeEx(NULL, params->threading_model);
01040     if (FAILED(hr)) return hr;
01041 
01042     apt = COM_CurrentApt();
01043     if (params->threading_model == COINIT_APARTMENTTHREADED)
01044     {
01045         apartment_createwindowifneeded(apt);
01046         params->apartment_hwnd = apartment_getwindow(apt);
01047     }
01048     else
01049         params->apartment_hwnd = NULL;
01050 
01051     /* force the message queue to be created before signaling parent thread */
01052     PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
01053 
01054     SetEvent(params->ready_event);
01055     params = NULL; /* can't touch params after here as it may be invalid */
01056 
01057     while (GetMessageW(&msg, NULL, 0, 0))
01058     {
01059         if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
01060         {
01061             struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
01062             obj_params->hr = apartment_hostobject(apt, obj_params);
01063             SetEvent(obj_params->event);
01064         }
01065         else
01066         {
01067             TranslateMessage(&msg);
01068             DispatchMessageW(&msg);
01069         }
01070     }
01071 
01072     TRACE("exiting\n");
01073 
01074     CoUninitialize();
01075 
01076     return S_OK;
01077 }
01078 
01079 /* finds or creates a host apartment, creates the object inside it and returns
01080  * a proxy to it so that the object can be used in the apartment of the
01081  * caller of this function */
01082 static HRESULT apartment_hostobject_in_hostapt(
01083     struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
01084     HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
01085 {
01086     struct host_object_params params;
01087     HWND apartment_hwnd = NULL;
01088     DWORD apartment_tid = 0;
01089     HRESULT hr;
01090 
01091     if (!multi_threaded && main_apartment)
01092     {
01093         APARTMENT *host_apt = apartment_findmain();
01094         if (host_apt)
01095         {
01096             apartment_hwnd = apartment_getwindow(host_apt);
01097             apartment_release(host_apt);
01098         }
01099     }
01100 
01101     if (!apartment_hwnd)
01102     {
01103         EnterCriticalSection(&apt->cs);
01104 
01105         if (!apt->host_apt_tid)
01106         {
01107             struct host_thread_params thread_params;
01108             HANDLE handles[2];
01109             DWORD wait_value;
01110 
01111             thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
01112             handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01113             thread_params.apartment_hwnd = NULL;
01114             handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
01115             if (!handles[1])
01116             {
01117                 CloseHandle(handles[0]);
01118                 LeaveCriticalSection(&apt->cs);
01119                 return E_OUTOFMEMORY;
01120             }
01121             wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
01122             CloseHandle(handles[0]);
01123             CloseHandle(handles[1]);
01124             if (wait_value == WAIT_OBJECT_0)
01125                 apt->host_apt_hwnd = thread_params.apartment_hwnd;
01126             else
01127             {
01128                 LeaveCriticalSection(&apt->cs);
01129                 return E_OUTOFMEMORY;
01130             }
01131         }
01132 
01133         if (multi_threaded || !main_apartment)
01134         {
01135             apartment_hwnd = apt->host_apt_hwnd;
01136             apartment_tid = apt->host_apt_tid;
01137         }
01138 
01139         LeaveCriticalSection(&apt->cs);
01140     }
01141 
01142     /* another thread may have become the main apartment in the time it took
01143      * us to create the thread for the host apartment */
01144     if (!apartment_hwnd && !multi_threaded && main_apartment)
01145     {
01146         APARTMENT *host_apt = apartment_findmain();
01147         if (host_apt)
01148         {
01149             apartment_hwnd = apartment_getwindow(host_apt);
01150             apartment_release(host_apt);
01151         }
01152     }
01153 
01154     params.hkeydll = hkeydll;
01155     params.clsid = *rclsid;
01156     params.iid = *riid;
01157     hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
01158     if (FAILED(hr))
01159         return hr;
01160     params.apartment_threaded = !multi_threaded;
01161     if (multi_threaded)
01162     {
01163         params.hr = S_OK;
01164         params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
01165         if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
01166             hr = E_OUTOFMEMORY;
01167         else
01168         {
01169             WaitForSingleObject(params.event, INFINITE);
01170             hr = params.hr;
01171         }
01172         CloseHandle(params.event);
01173     }
01174     else
01175     {
01176         if (!apartment_hwnd)
01177         {
01178             ERR("host apartment didn't create window\n");
01179             hr = E_OUTOFMEMORY;
01180         }
01181         else
01182             hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
01183     }
01184     if (SUCCEEDED(hr))
01185         hr = CoUnmarshalInterface(params.stream, riid, ppv);
01186     IStream_Release(params.stream);
01187     return hr;
01188 }
01189 
01190 /* create a window for the apartment or return the current one if one has
01191  * already been created */
01192 HRESULT apartment_createwindowifneeded(struct apartment *apt)
01193 {
01194     if (apt->multi_threaded)
01195         return S_OK;
01196 
01197     if (!apt->win)
01198     {
01199         HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
01200                                   0, 0, 0, 0,
01201                                   HWND_MESSAGE, 0, hProxyDll, NULL);
01202         if (!hwnd)
01203         {
01204             ERR("CreateWindow failed with error %d\n", GetLastError());
01205             return HRESULT_FROM_WIN32(GetLastError());
01206         }
01207         if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
01208             /* someone beat us to it */
01209             DestroyWindow(hwnd);
01210     }
01211 
01212     return S_OK;
01213 }
01214 
01215 /* retrieves the window for the main- or apartment-threaded apartment */
01216 HWND apartment_getwindow(const struct apartment *apt)
01217 {
01218     assert(!apt->multi_threaded);
01219     return apt->win;
01220 }
01221 
01222 void apartment_joinmta(void)
01223 {
01224     apartment_addref(MTA);
01225     COM_CurrentInfo()->apt = MTA;
01226 }
01227 
01228 static void COMPOBJ_InitProcess( void )
01229 {
01230     WNDCLASSW wclass;
01231 
01232     /* Dispatching to the correct thread in an apartment is done through
01233      * window messages rather than RPC transports. When an interface is
01234      * marshalled into another apartment in the same process, a window of the
01235      * following class is created. The *caller* of CoMarshalInterface (i.e., the
01236      * application) is responsible for pumping the message loop in that thread.
01237      * The WM_USER messages which point to the RPCs are then dispatched to
01238      * apartment_wndproc by the user's code from the apartment in which the
01239      * interface was unmarshalled.
01240      */
01241     memset(&wclass, 0, sizeof(wclass));
01242     wclass.lpfnWndProc = apartment_wndproc;
01243     wclass.hInstance = hProxyDll;
01244     wclass.lpszClassName = wszAptWinClass;
01245     RegisterClassW(&wclass);
01246 }
01247 
01248 static void COMPOBJ_UninitProcess( void )
01249 {
01250     UnregisterClassW(wszAptWinClass, hProxyDll);
01251 }
01252 
01253 static void COM_TlsDestroy(void)
01254 {
01255     struct oletls *info = NtCurrentTeb()->ReservedForOle;
01256     if (info)
01257     {
01258         if (info->apt) apartment_release(info->apt);
01259         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
01260         if (info->state) IUnknown_Release(info->state);
01261         if (info->spy) IUnknown_Release(info->spy);
01262         if (info->context_token) IObjContext_Release(info->context_token);
01263         HeapFree(GetProcessHeap(), 0, info);
01264         NtCurrentTeb()->ReservedForOle = NULL;
01265     }
01266 }
01267 
01268 /******************************************************************************
01269  *           CoBuildVersion [OLE32.@]
01270  *
01271  * Gets the build version of the DLL.
01272  *
01273  * PARAMS
01274  *
01275  * RETURNS
01276  *  Current build version, hiword is majornumber, loword is minornumber
01277  */
01278 DWORD WINAPI CoBuildVersion(void)
01279 {
01280     TRACE("Returning version %d, build %d.\n", rmm, rup);
01281     return (rmm<<16)+rup;
01282 }
01283 
01284 /******************************************************************************
01285  *              CoRegisterInitializeSpy [OLE32.@]
01286  *
01287  * Add a Spy that watches CoInitializeEx calls
01288  *
01289  * PARAMS
01290  *  spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
01291  *  cookie [II] cookie receiver
01292  *
01293  * RETURNS
01294  *  Success: S_OK if not already initialized, S_FALSE otherwise.
01295  *  Failure: HRESULT code.
01296  *
01297  * SEE ALSO
01298  *   CoInitializeEx
01299  */
01300 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
01301 {
01302     struct oletls *info = COM_CurrentInfo();
01303     HRESULT hr;
01304 
01305     TRACE("(%p, %p)\n", spy, cookie);
01306 
01307     if (!spy || !cookie || !info)
01308     {
01309         if (!info)
01310             WARN("Could not allocate tls\n");
01311         return E_INVALIDARG;
01312     }
01313 
01314     if (info->spy)
01315     {
01316         FIXME("Already registered?\n");
01317         return E_UNEXPECTED;
01318     }
01319 
01320     hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
01321     if (SUCCEEDED(hr))
01322     {
01323         cookie->QuadPart = (DWORD_PTR)spy;
01324         return S_OK;
01325     }
01326     return hr;
01327 }
01328 
01329 /******************************************************************************
01330  *              CoRevokeInitializeSpy [OLE32.@]
01331  *
01332  * Remove a spy that previously watched CoInitializeEx calls
01333  *
01334  * PARAMS
01335  *  cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
01336  *
01337  * RETURNS
01338  *  Success: S_OK if a spy is removed
01339  *  Failure: E_INVALIDARG
01340  *
01341  * SEE ALSO
01342  *   CoInitializeEx
01343  */
01344 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
01345 {
01346     struct oletls *info = COM_CurrentInfo();
01347     TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
01348 
01349     if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
01350         return E_INVALIDARG;
01351 
01352     IUnknown_Release(info->spy);
01353     info->spy = NULL;
01354     return S_OK;
01355 }
01356 
01357 
01358 /******************************************************************************
01359  *      CoInitialize    [OLE32.@]
01360  *
01361  * Initializes the COM libraries by calling CoInitializeEx with
01362  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
01363  *
01364  * PARAMS
01365  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
01366  *
01367  * RETURNS
01368  *  Success: S_OK if not already initialized, S_FALSE otherwise.
01369  *  Failure: HRESULT code.
01370  *
01371  * SEE ALSO
01372  *   CoInitializeEx
01373  */
01374 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
01375 {
01376   /*
01377    * Just delegate to the newer method.
01378    */
01379   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
01380 }
01381 
01382 /******************************************************************************
01383  *      CoInitializeEx  [OLE32.@]
01384  *
01385  * Initializes the COM libraries.
01386  *
01387  * PARAMS
01388  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
01389  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
01390  *
01391  * RETURNS
01392  *  S_OK               if successful,
01393  *  S_FALSE            if this function was called already.
01394  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
01395  *                     threading model.
01396  *
01397  * NOTES
01398  *
01399  * The behavior used to set the IMalloc used for memory management is
01400  * obsolete.
01401  * The dwCoInit parameter must specify one of the following apartment
01402  * threading models:
01403  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
01404  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
01405  * The parameter may also specify zero or more of the following flags:
01406  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
01407  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
01408  *
01409  * SEE ALSO
01410  *   CoUninitialize
01411  */
01412 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
01413 {
01414   struct oletls *info = COM_CurrentInfo();
01415   HRESULT hr = S_OK;
01416   APARTMENT *apt;
01417 
01418   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
01419 
01420   if (lpReserved!=NULL)
01421   {
01422     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
01423   }
01424 
01425   /*
01426    * Check the lock count. If this is the first time going through the initialize
01427    * process, we have to initialize the libraries.
01428    *
01429    * And crank-up that lock count.
01430    */
01431   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
01432   {
01433     /*
01434      * Initialize the various COM libraries and data structures.
01435      */
01436     TRACE("() - Initializing the COM libraries\n");
01437 
01438     /* we may need to defer this until after apartment initialisation */
01439     RunningObjectTableImpl_Initialize();
01440   }
01441 
01442   if (info->spy)
01443       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
01444 
01445   if (!(apt = info->apt))
01446   {
01447     apt = apartment_get_or_create(dwCoInit);
01448     if (!apt) return E_OUTOFMEMORY;
01449   }
01450   else if (!apartment_is_model(apt, dwCoInit))
01451   {
01452     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
01453        code then we are probably using the wrong threading model to implement that API. */
01454     ERR("Attempt to change threading model of this apartment from %s to %s\n",
01455         apt->multi_threaded ? "multi-threaded" : "apartment threaded",
01456         dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
01457     return RPC_E_CHANGED_MODE;
01458   }
01459   else
01460     hr = S_FALSE;
01461 
01462   info->inits++;
01463 
01464   if (info->spy)
01465       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
01466 
01467   return hr;
01468 }
01469 
01470 /***********************************************************************
01471  *           CoUninitialize   [OLE32.@]
01472  *
01473  * This method will decrement the refcount on the current apartment, freeing
01474  * the resources associated with it if it is the last thread in the apartment.
01475  * If the last apartment is freed, the function will additionally release
01476  * any COM resources associated with the process.
01477  *
01478  * PARAMS
01479  *
01480  * RETURNS
01481  *  Nothing.
01482  *
01483  * SEE ALSO
01484  *   CoInitializeEx
01485  */
01486 void WINAPI CoUninitialize(void)
01487 {
01488   struct oletls * info = COM_CurrentInfo();
01489   LONG lCOMRefCnt;
01490 
01491   TRACE("()\n");
01492 
01493   /* will only happen on OOM */
01494   if (!info) return;
01495 
01496   if (info->spy)
01497       IInitializeSpy_PreUninitialize(info->spy, info->inits);
01498 
01499   /* sanity check */
01500   if (!info->inits)
01501   {
01502     ERR("Mismatched CoUninitialize\n");
01503 
01504     if (info->spy)
01505         IInitializeSpy_PostUninitialize(info->spy, info->inits);
01506     return;
01507   }
01508 
01509   if (!--info->inits)
01510   {
01511     apartment_release(info->apt);
01512     info->apt = NULL;
01513   }
01514 
01515   /*
01516    * Decrease the reference count.
01517    * If we are back to 0 locks on the COM library, make sure we free
01518    * all the associated data structures.
01519    */
01520   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
01521   if (lCOMRefCnt==1)
01522   {
01523     TRACE("() - Releasing the COM libraries\n");
01524 
01525     RunningObjectTableImpl_UnInitialize();
01526   }
01527   else if (lCOMRefCnt<1) {
01528     ERR( "CoUninitialize() - not CoInitialized.\n" );
01529     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
01530   }
01531   if (info->spy)
01532       IInitializeSpy_PostUninitialize(info->spy, info->inits);
01533 }
01534 
01535 /******************************************************************************
01536  *      CoDisconnectObject  [OLE32.@]
01537  *
01538  * Disconnects all connections to this object from remote processes. Dispatches
01539  * pending RPCs while blocking new RPCs from occurring, and then calls
01540  * IMarshal::DisconnectObject on the given object.
01541  *
01542  * Typically called when the object server is forced to shut down, for instance by
01543  * the user.
01544  *
01545  * PARAMS
01546  *  lpUnk    [I] The object whose stub should be disconnected.
01547  *  reserved [I] Reserved. Should be set to 0.
01548  *
01549  * RETURNS
01550  *  Success: S_OK.
01551  *  Failure: HRESULT code.
01552  *
01553  * SEE ALSO
01554  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
01555  */
01556 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
01557 {
01558     HRESULT hr;
01559     IMarshal *marshal;
01560     APARTMENT *apt;
01561 
01562     TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
01563 
01564     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
01565     if (hr == S_OK)
01566     {
01567         hr = IMarshal_DisconnectObject(marshal, reserved);
01568         IMarshal_Release(marshal);
01569         return hr;
01570     }
01571 
01572     apt = COM_CurrentApt();
01573     if (!apt)
01574         return CO_E_NOTINITIALIZED;
01575 
01576     apartment_disconnectobject(apt, lpUnk);
01577 
01578     /* Note: native is pretty broken here because it just silently
01579      * fails, without returning an appropriate error code if the object was
01580      * not found, making apps think that the object was disconnected, when
01581      * it actually wasn't */
01582 
01583     return S_OK;
01584 }
01585 
01586 /******************************************************************************
01587  *      CoCreateGuid [OLE32.@]
01588  *
01589  * Simply forwards to UuidCreate in RPCRT4.
01590  *
01591  * PARAMS
01592  *  pguid [O] Points to the GUID to initialize.
01593  *
01594  * RETURNS
01595  *  Success: S_OK.
01596  *  Failure: HRESULT code.
01597  *
01598  * SEE ALSO
01599  *   UuidCreate
01600  */
01601 HRESULT WINAPI CoCreateGuid(GUID *pguid)
01602 {
01603     DWORD status = UuidCreate(pguid);
01604     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
01605     return HRESULT_FROM_WIN32( status );
01606 }
01607 
01608 static inline BOOL is_valid_hex(WCHAR c)
01609 {
01610     if (!(((c >= '0') && (c <= '9'))  ||
01611           ((c >= 'a') && (c <= 'f'))  ||
01612           ((c >= 'A') && (c <= 'F'))))
01613         return FALSE;
01614     return TRUE;
01615 }
01616 
01617 /******************************************************************************
01618  *      CLSIDFromString [OLE32.@]
01619  *      IIDFromString   [OLE32.@]
01620  *
01621  * Converts a unique identifier from its string representation into
01622  * the GUID struct.
01623  *
01624  * PARAMS
01625  *  idstr [I] The string representation of the GUID.
01626  *  id    [O] GUID converted from the string.
01627  *
01628  * RETURNS
01629  *   S_OK on success
01630  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
01631  *
01632  * SEE ALSO
01633  *  StringFromCLSID
01634  */
01635 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
01636 {
01637   int   i;
01638   BYTE table[256];
01639 
01640   if (!s || s[0]!='{') {
01641     memset( id, 0, sizeof (CLSID) );
01642     if(!s) return S_OK;
01643     return CO_E_CLASSSTRING;
01644   }
01645 
01646   TRACE("%s -> %p\n", debugstr_w(s), id);
01647 
01648   /* quick lookup table */
01649   memset(table, 0, 256);
01650 
01651   for (i = 0; i < 10; i++) {
01652     table['0' + i] = i;
01653   }
01654   for (i = 0; i < 6; i++) {
01655     table['A' + i] = i+10;
01656     table['a' + i] = i+10;
01657   }
01658 
01659   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
01660 
01661   id->Data1 = 0;
01662   for (i = 1; i < 9; i++) {
01663     if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
01664     id->Data1 = (id->Data1 << 4) | table[s[i]];
01665   }
01666   if (s[9]!='-') return CO_E_CLASSSTRING;
01667 
01668   id->Data2 = 0;
01669   for (i = 10; i < 14; i++) {
01670     if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
01671     id->Data2 = (id->Data2 << 4) | table[s[i]];
01672   }
01673   if (s[14]!='-') return CO_E_CLASSSTRING;
01674 
01675   id->Data3 = 0;
01676   for (i = 15; i < 19; i++) {
01677     if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
01678     id->Data3 = (id->Data3 << 4) | table[s[i]];
01679   }
01680   if (s[19]!='-') return CO_E_CLASSSTRING;
01681 
01682   for (i = 20; i < 37; i+=2) {
01683     if (i == 24) {
01684       if (s[i]!='-') return CO_E_CLASSSTRING;
01685       i++;
01686     }
01687     if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
01688     id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
01689   }
01690 
01691   if (s[37] == '}' && s[38] == '\0')
01692     return S_OK;
01693 
01694   return CO_E_CLASSSTRING;
01695 }
01696 
01697 /*****************************************************************************/
01698 
01699 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
01700 {
01701     HRESULT ret;
01702 
01703     if (!id)
01704         return E_INVALIDARG;
01705 
01706     ret = __CLSIDFromString(idstr, id);
01707     if(ret != S_OK) { /* It appears a ProgID is also valid */
01708         CLSID tmp_id;
01709         ret = CLSIDFromProgID(idstr, &tmp_id);
01710         if(SUCCEEDED(ret))
01711             *id = tmp_id;
01712     }
01713     return ret;
01714 }
01715 
01716 
01717 /******************************************************************************
01718  *      StringFromCLSID [OLE32.@]
01719  *      StringFromIID   [OLE32.@]
01720  *
01721  * Converts a GUID into the respective string representation.
01722  * The target string is allocated using the OLE IMalloc.
01723  *
01724  * PARAMS
01725  *  id    [I] the GUID to be converted.
01726  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
01727  *
01728  * RETURNS
01729  *   S_OK
01730  *   E_FAIL
01731  *
01732  * SEE ALSO
01733  *  StringFromGUID2, CLSIDFromString
01734  */
01735 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
01736 {
01737     HRESULT ret;
01738     LPMALLOC mllc;
01739 
01740     if ((ret = CoGetMalloc(0,&mllc))) return ret;
01741     if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
01742     StringFromGUID2( id, *idstr, CHARS_IN_GUID );
01743     return S_OK;
01744 }
01745 
01746 /******************************************************************************
01747  *      StringFromGUID2 [OLE32.@]
01748  *
01749  * Modified version of StringFromCLSID that allows you to specify max
01750  * buffer size.
01751  *
01752  * PARAMS
01753  *  id   [I] GUID to convert to string.
01754  *  str  [O] Buffer where the result will be stored.
01755  *  cmax [I] Size of the buffer in characters.
01756  *
01757  * RETURNS
01758  *  Success: The length of the resulting string in characters.
01759  *  Failure: 0.
01760  */
01761 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
01762 {
01763     static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
01764                                      '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
01765                                      '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
01766                                      '%','0','2','X','%','0','2','X','}',0 };
01767     if (!id || cmax < CHARS_IN_GUID) return 0;
01768     sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
01769               id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
01770               id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
01771     return CHARS_IN_GUID;
01772 }
01773 
01774 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
01775 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
01776 {
01777     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
01778     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
01779     LONG res;
01780     HKEY key;
01781 
01782     strcpyW(path, wszCLSIDSlash);
01783     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
01784     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
01785     if (res == ERROR_FILE_NOT_FOUND)
01786         return REGDB_E_CLASSNOTREG;
01787     else if (res != ERROR_SUCCESS)
01788         return REGDB_E_READREGDB;
01789 
01790     if (!keyname)
01791     {
01792         *subkey = key;
01793         return S_OK;
01794     }
01795 
01796     res = RegOpenKeyExW(key, keyname, 0, access, subkey);
01797     RegCloseKey(key);
01798     if (res == ERROR_FILE_NOT_FOUND)
01799         return REGDB_E_KEYMISSING;
01800     else if (res != ERROR_SUCCESS)
01801         return REGDB_E_READREGDB;
01802 
01803     return S_OK;
01804 }
01805 
01806 /* open HKCR\\AppId\\{string form of appid clsid} key */
01807 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
01808 {
01809     static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
01810     static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
01811     DWORD res;
01812     WCHAR buf[CHARS_IN_GUID];
01813     WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
01814     DWORD size;
01815     HKEY hkey;
01816     DWORD type;
01817     HRESULT hr;
01818 
01819     /* read the AppID value under the class's key */
01820     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
01821     if (FAILED(hr))
01822         return hr;
01823 
01824     size = sizeof(buf);
01825     res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
01826     RegCloseKey(hkey);
01827     if (res == ERROR_FILE_NOT_FOUND)
01828         return REGDB_E_KEYMISSING;
01829     else if (res != ERROR_SUCCESS || type!=REG_SZ)
01830         return REGDB_E_READREGDB;
01831 
01832     strcpyW(keyname, szAppIdKey);
01833     strcatW(keyname, buf);
01834     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
01835     if (res == ERROR_FILE_NOT_FOUND)
01836         return REGDB_E_KEYMISSING;
01837     else if (res != ERROR_SUCCESS)
01838         return REGDB_E_READREGDB;
01839 
01840     return S_OK;
01841 }
01842 
01843 /******************************************************************************
01844  *               ProgIDFromCLSID [OLE32.@]
01845  *
01846  * Converts a class id into the respective program ID.
01847  *
01848  * PARAMS
01849  *  clsid        [I] Class ID, as found in registry.
01850  *  ppszProgID [O] Associated ProgID.
01851  *
01852  * RETURNS
01853  *   S_OK
01854  *   E_OUTOFMEMORY
01855  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
01856  */
01857 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
01858 {
01859     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
01860     HKEY     hkey;
01861     HRESULT  ret;
01862     LONG progidlen = 0;
01863 
01864     if (!ppszProgID)
01865     {
01866         ERR("ppszProgId isn't optional\n");
01867         return E_INVALIDARG;
01868     }
01869 
01870     *ppszProgID = NULL;
01871     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
01872     if (FAILED(ret))
01873         return ret;
01874 
01875     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
01876       ret = REGDB_E_CLASSNOTREG;
01877 
01878     if (ret == S_OK)
01879     {
01880       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
01881       if (*ppszProgID)
01882       {
01883         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
01884           ret = REGDB_E_CLASSNOTREG;
01885       }
01886       else
01887         ret = E_OUTOFMEMORY;
01888     }
01889 
01890     RegCloseKey(hkey);
01891     return ret;
01892 }
01893 
01894 /******************************************************************************
01895  *      CLSIDFromProgID [OLE32.@]
01896  *
01897  * Converts a program id into the respective GUID.
01898  *
01899  * PARAMS
01900  *  progid [I] Unicode program ID, as found in registry.
01901  *  clsid  [O] Associated CLSID.
01902  *
01903  * RETURNS
01904  *  Success: S_OK
01905  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
01906  */
01907 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
01908 {
01909     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
01910     WCHAR buf2[CHARS_IN_GUID];
01911     LONG buf2len = sizeof(buf2);
01912     HKEY xhkey;
01913     WCHAR *buf;
01914 
01915     if (!progid || !clsid)
01916     {
01917         ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
01918         return E_INVALIDARG;
01919     }
01920 
01921     /* initialise clsid in case of failure */
01922     memset(clsid, 0, sizeof(*clsid));
01923 
01924     buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
01925     strcpyW( buf, progid );
01926     strcatW( buf, clsidW );
01927     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
01928     {
01929         HeapFree(GetProcessHeap(),0,buf);
01930         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
01931         return CO_E_CLASSSTRING;
01932     }
01933     HeapFree(GetProcessHeap(),0,buf);
01934 
01935     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
01936     {
01937         RegCloseKey(xhkey);
01938         WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
01939         return CO_E_CLASSSTRING;
01940     }
01941     RegCloseKey(xhkey);
01942     return __CLSIDFromString(buf2,clsid);
01943 }
01944 
01945 
01946 /*****************************************************************************
01947  *             CoGetPSClsid [OLE32.@]
01948  *
01949  * Retrieves the CLSID of the proxy/stub factory that implements
01950  * IPSFactoryBuffer for the specified interface.
01951  *
01952  * PARAMS
01953  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
01954  *  pclsid [O] Where to store returned proxy/stub CLSID.
01955  * 
01956  * RETURNS
01957  *   S_OK
01958  *   E_OUTOFMEMORY
01959  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
01960  *
01961  * NOTES
01962  *
01963  * The standard marshaller activates the object with the CLSID
01964  * returned and uses the CreateProxy and CreateStub methods on its
01965  * IPSFactoryBuffer interface to construct the proxies and stubs for a
01966  * given object.
01967  *
01968  * CoGetPSClsid determines this CLSID by searching the
01969  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
01970  * in the registry and any interface id registered by
01971  * CoRegisterPSClsid within the current process.
01972  *
01973  * BUGS
01974  *
01975  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
01976  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
01977  * considered a bug in native unless an application depends on this (unlikely).
01978  *
01979  * SEE ALSO
01980  *  CoRegisterPSClsid.
01981  */
01982 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
01983 {
01984     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
01985     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
01986     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
01987     WCHAR value[CHARS_IN_GUID];
01988     LONG len;
01989     HKEY hkey;
01990     APARTMENT *apt = COM_CurrentApt();
01991     struct registered_psclsid *registered_psclsid;
01992 
01993     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
01994 
01995     if (!apt)
01996     {
01997         ERR("apartment not initialised\n");
01998         return CO_E_NOTINITIALIZED;
01999     }
02000 
02001     if (!pclsid)
02002     {
02003         ERR("pclsid isn't optional\n");
02004         return E_INVALIDARG;
02005     }
02006 
02007     EnterCriticalSection(&apt->cs);
02008 
02009     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
02010         if (IsEqualIID(&registered_psclsid->iid, riid))
02011         {
02012             *pclsid = registered_psclsid->clsid;
02013             LeaveCriticalSection(&apt->cs);
02014             return S_OK;
02015         }
02016 
02017     LeaveCriticalSection(&apt->cs);
02018 
02019     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
02020     strcpyW(path, wszInterface);
02021     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
02022     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
02023 
02024     /* Open the key.. */
02025     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
02026     {
02027         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
02028         return REGDB_E_IIDNOTREG;
02029     }
02030 
02031     /* ... Once we have the key, query the registry to get the
02032        value of CLSID as a string, and convert it into a
02033        proper CLSID structure to be passed back to the app */
02034     len = sizeof(value);
02035     if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
02036     {
02037         RegCloseKey(hkey);
02038         return REGDB_E_IIDNOTREG;
02039     }
02040     RegCloseKey(hkey);
02041 
02042     /* We have the CLSID we want back from the registry as a string, so
02043        let's convert it into a CLSID structure */
02044     if (CLSIDFromString(value, pclsid) != NOERROR)
02045         return REGDB_E_IIDNOTREG;
02046 
02047     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
02048     return S_OK;
02049 }
02050 
02051 /*****************************************************************************
02052  *             CoRegisterPSClsid [OLE32.@]
02053  *
02054  * Register a proxy/stub CLSID for the given interface in the current process
02055  * only.
02056  *
02057  * PARAMS
02058  *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
02059  *  rclsid [I] CLSID of the proxy/stub.
02060  * 
02061  * RETURNS
02062  *   Success: S_OK
02063  *   Failure: E_OUTOFMEMORY
02064  *
02065  * NOTES
02066  *
02067  * This function does not add anything to the registry and the effects are
02068  * limited to the lifetime of the current process.
02069  *
02070  * SEE ALSO
02071  *  CoGetPSClsid.
02072  */
02073 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
02074 {
02075     APARTMENT *apt = COM_CurrentApt();
02076     struct registered_psclsid *registered_psclsid;
02077 
02078     TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
02079 
02080     if (!apt)
02081     {
02082         ERR("apartment not initialised\n");
02083         return CO_E_NOTINITIALIZED;
02084     }
02085 
02086     EnterCriticalSection(&apt->cs);
02087 
02088     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
02089         if (IsEqualIID(&registered_psclsid->iid, riid))
02090         {
02091             registered_psclsid->clsid = *rclsid;
02092             LeaveCriticalSection(&apt->cs);
02093             return S_OK;
02094         }
02095 
02096     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
02097     if (!registered_psclsid)
02098     {
02099         LeaveCriticalSection(&apt->cs);
02100         return E_OUTOFMEMORY;
02101     }
02102 
02103     registered_psclsid->iid = *riid;
02104     registered_psclsid->clsid = *rclsid;
02105     list_add_head(&apt->psclsids, &registered_psclsid->entry);
02106 
02107     LeaveCriticalSection(&apt->cs);
02108 
02109     return S_OK;
02110 }
02111 
02112 
02113 /***
02114  * COM_GetRegisteredClassObject
02115  *
02116  * This internal method is used to scan the registered class list to
02117  * find a class object.
02118  *
02119  * Params:
02120  *   rclsid        Class ID of the class to find.
02121  *   dwClsContext  Class context to match.
02122  *   ppv           [out] returns a pointer to the class object. Complying
02123  *                 to normal COM usage, this method will increase the
02124  *                 reference count on this object.
02125  */
02126 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
02127                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
02128 {
02129   HRESULT hr = S_FALSE;
02130   RegisteredClass *curClass;
02131 
02132   EnterCriticalSection( &csRegisteredClassList );
02133 
02134   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
02135   {
02136     /*
02137      * Check if we have a match on the class ID and context.
02138      */
02139     if ((apt->oxid == curClass->apartment_id) &&
02140         (dwClsContext & curClass->runContext) &&
02141         IsEqualGUID(&(curClass->classIdentifier), rclsid))
02142     {
02143       /*
02144        * We have a match, return the pointer to the class object.
02145        */
02146       *ppUnk = curClass->classObject;
02147 
02148       IUnknown_AddRef(curClass->classObject);
02149 
02150       hr = S_OK;
02151       break;
02152     }
02153   }
02154 
02155   LeaveCriticalSection( &csRegisteredClassList );
02156 
02157   return hr;
02158 }
02159 
02160 /******************************************************************************
02161  *      CoRegisterClassObject   [OLE32.@]
02162  *
02163  * Registers the class object for a given class ID. Servers housed in EXE
02164  * files use this method instead of exporting DllGetClassObject to allow
02165  * other code to connect to their objects.
02166  *
02167  * PARAMS
02168  *  rclsid       [I] CLSID of the object to register.
02169  *  pUnk         [I] IUnknown of the object.
02170  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
02171  *  flags        [I] REGCLS flags indicating how connections are made.
02172  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
02173  *
02174  * RETURNS
02175  *   S_OK on success,
02176  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
02177  *   CO_E_OBJISREG if the object is already registered. We should not return this.
02178  *
02179  * SEE ALSO
02180  *   CoRevokeClassObject, CoGetClassObject
02181  *
02182  * NOTES
02183  *  In-process objects are only registered for the current apartment.
02184  *  CoGetClassObject() and CoCreateInstance() will not return objects registered
02185  *  in other apartments.
02186  *
02187  * BUGS
02188  *  MSDN claims that multiple interface registrations are legal, but we
02189  *  can't do that with our current implementation.
02190  */
02191 HRESULT WINAPI CoRegisterClassObject(
02192     REFCLSID rclsid,
02193     LPUNKNOWN pUnk,
02194     DWORD dwClsContext,
02195     DWORD flags,
02196     LPDWORD lpdwRegister)
02197 {
02198   static LONG next_cookie;
02199   RegisteredClass* newClass;
02200   LPUNKNOWN        foundObject;
02201   HRESULT          hr;
02202   APARTMENT *apt;
02203 
02204   TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
02205     debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
02206 
02207   if ( (lpdwRegister==0) || (pUnk==0) )
02208     return E_INVALIDARG;
02209 
02210   apt = COM_CurrentApt();
02211   if (!apt)
02212   {
02213       ERR("COM was not initialized\n");
02214       return CO_E_NOTINITIALIZED;
02215   }
02216 
02217   *lpdwRegister = 0;
02218 
02219   /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
02220    * differentiates the flag from REGCLS_MULTI_SEPARATE. */
02221   if (flags & REGCLS_MULTIPLEUSE)
02222     dwClsContext |= CLSCTX_INPROC_SERVER;
02223 
02224   /*
02225    * First, check if the class is already registered.
02226    * If it is, this should cause an error.
02227    */
02228   hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
02229   if (hr == S_OK) {
02230     if (flags & REGCLS_MULTIPLEUSE) {
02231       if (dwClsContext & CLSCTX_LOCAL_SERVER)
02232         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
02233       IUnknown_Release(foundObject);
02234       return hr;
02235     }
02236     IUnknown_Release(foundObject);
02237     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
02238     return CO_E_OBJISREG;
02239   }
02240 
02241   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
02242   if ( newClass == NULL )
02243     return E_OUTOFMEMORY;
02244 
02245   newClass->classIdentifier = *rclsid;
02246   newClass->apartment_id    = apt->oxid;
02247   newClass->runContext      = dwClsContext;
02248   newClass->connectFlags    = flags;
02249   newClass->pMarshaledData  = NULL;
02250   newClass->RpcRegistration = NULL;
02251 
02252   if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
02253       newClass->dwCookie = InterlockedIncrement( &next_cookie );
02254 
02255   /*
02256    * Since we're making a copy of the object pointer, we have to increase its
02257    * reference count.
02258    */
02259   newClass->classObject     = pUnk;
02260   IUnknown_AddRef(newClass->classObject);
02261 
02262   EnterCriticalSection( &csRegisteredClassList );
02263   list_add_tail(&RegisteredClassList, &newClass->entry);
02264   LeaveCriticalSection( &csRegisteredClassList );
02265 
02266   *lpdwRegister = newClass->dwCookie;
02267 
02268   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
02269       hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
02270       if (hr) {
02271           FIXME("Failed to create stream on hglobal, %x\n", hr);
02272           return hr;
02273       }
02274       hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
02275                               newClass->classObject, MSHCTX_LOCAL, NULL,
02276                               MSHLFLAGS_TABLESTRONG);
02277       if (hr) {
02278           FIXME("CoMarshalInterface failed, %x!\n",hr);
02279           return hr;
02280       }
02281 
02282       hr = RPC_StartLocalServer(&newClass->classIdentifier,
02283                                 newClass->pMarshaledData,
02284                                 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
02285                                 &newClass->RpcRegistration);
02286   }
02287   return S_OK;
02288 }
02289 
02290 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
02291 {
02292     static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
02293     DWORD keytype;
02294     DWORD ret;
02295     DWORD dwLength = len * sizeof(WCHAR);
02296 
02297     ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
02298     if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
02299         value[0] = '\0';
02300 }
02301 
02302 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
02303                                        REFCLSID rclsid, REFIID riid,
02304                                        BOOL hostifnecessary, void **ppv)
02305 {
02306     WCHAR dllpath[MAX_PATH+1];
02307     BOOL apartment_threaded;
02308 
02309     if (hostifnecessary)
02310     {
02311         static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
02312         static const WCHAR wszFree[] = {'F','r','e','e',0};
02313         static const WCHAR wszBoth[] = {'B','o','t','h',0};
02314         WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
02315 
02316         get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
02317         /* "Apartment" */
02318         if (!strcmpiW(threading_model, wszApartment))
02319         {
02320             apartment_threaded = TRUE;
02321             if (apt->multi_threaded)
02322                 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
02323         }
02324         /* "Free" */
02325         else if (!strcmpiW(threading_model, wszFree))
02326         {
02327             apartment_threaded = FALSE;
02328             if (!apt->multi_threaded)
02329                 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
02330         }
02331         /* everything except "Apartment", "Free" and "Both" */
02332         else if (strcmpiW(threading_model, wszBoth))
02333         {
02334             apartment_threaded = TRUE;
02335             /* everything else is main-threaded */
02336             if (threading_model[0])
02337                 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
02338                     debugstr_w(threading_model), debugstr_guid(rclsid));
02339 
02340             if (apt->multi_threaded || !apt->main)
02341                 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
02342         }
02343         else
02344             apartment_threaded = FALSE;
02345     }
02346     else
02347         apartment_threaded = !apt->multi_threaded;
02348 
02349     if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
02350     {
02351         /* failure: CLSID is not found in registry */
02352         WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
02353         return REGDB_E_CLASSNOTREG;
02354     }
02355 
02356     return apartment_getclassobject(apt, dllpath, apartment_threaded,
02357                                     rclsid, riid, ppv);
02358 }
02359 
02360 /***********************************************************************
02361  *           CoGetClassObject [OLE32.@]
02362  *
02363  * Creates an object of the specified class.
02364  *
02365  * PARAMS
02366  *  rclsid       [I] Class ID to create an instance of.
02367  *  dwClsContext [I] Flags to restrict the location of the created instance.
02368  *  pServerInfo  [I] Optional. Details for connecting to a remote server.
02369  *  iid          [I] The ID of the interface of the instance to return.
02370  *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
02371  *
02372  * RETURNS
02373  *  Success: S_OK
02374  *  Failure: HRESULT code.
02375  *
02376  * NOTES
02377  *  The dwClsContext parameter can be one or more of the following:
02378  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
02379  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
02380  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
02381  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
02382  *
02383  * SEE ALSO
02384  *  CoCreateInstance()
02385  */
02386 HRESULT WINAPI CoGetClassObject(
02387     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
02388     REFIID iid, LPVOID *ppv)
02389 {
02390     LPUNKNOWN   regClassObject;
02391     HRESULT hres = E_UNEXPECTED;
02392     APARTMENT  *apt;
02393     BOOL release_apt = FALSE;
02394 
02395     TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
02396 
02397     if (!ppv)
02398         return E_INVALIDARG;
02399 
02400     *ppv = NULL;
02401 
02402     if (!(apt = COM_CurrentApt()))
02403     {
02404         if (!(apt = apartment_find_multi_threaded()))
02405         {
02406             ERR("apartment not initialised\n");
02407             return CO_E_NOTINITIALIZED;
02408         }
02409         release_apt = TRUE;
02410     }
02411 
02412     if (pServerInfo) {
02413     FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
02414               debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
02415     }
02416 
02417     /*
02418      * First, try and see if we can't match the class ID with one of the
02419      * registered classes.
02420      */
02421     if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
02422                                              &regClassObject))
02423     {
02424       /* Get the required interface from the retrieved pointer. */
02425       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
02426 
02427       /*
02428        * Since QI got another reference on the pointer, we want to release the
02429        * one we already have. If QI was unsuccessful, this will release the object. This
02430        * is good since we are not returning it in the "out" parameter.
02431        */
02432       IUnknown_Release(regClassObject);
02433       if (release_apt) apartment_release(apt);
02434       return hres;
02435     }
02436 
02437     /* First try in-process server */
02438     if (CLSCTX_INPROC_SERVER & dwClsContext)
02439     {
02440         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
02441         HKEY hkey;
02442 
02443         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
02444         {
02445             if (release_apt) apartment_release(apt);
02446             return FTMarshalCF_Create(iid, ppv);
02447         }
02448 
02449         hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
02450         if (FAILED(hres))
02451         {
02452             if (hres == REGDB_E_CLASSNOTREG)
02453                 ERR("class %s not registered\n", debugstr_guid(rclsid));
02454             else if (hres == REGDB_E_KEYMISSING)
02455             {
02456                 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
02457                 hres = REGDB_E_CLASSNOTREG;
02458             }
02459         }
02460 
02461         if (SUCCEEDED(hres))
02462         {
02463             hres = get_inproc_class_object(apt, hkey, rclsid, iid,
02464                 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
02465             RegCloseKey(hkey);
02466         }
02467 
02468         /* return if we got a class, otherwise fall through to one of the
02469          * other types */
02470         if (SUCCEEDED(hres))
02471         {
02472             if (release_apt) apartment_release(apt);
02473             return hres;
02474         }
02475     }
02476 
02477     /* Next try in-process handler */
02478     if (CLSCTX_INPROC_HANDLER & dwClsContext)
02479     {
02480         static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
02481         HKEY hkey;
02482 
02483         hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
02484         if (FAILED(hres))
02485         {
02486             if (hres == REGDB_E_CLASSNOTREG)
02487                 ERR("class %s not registered\n", debugstr_guid(rclsid));
02488             else if (hres == REGDB_E_KEYMISSING)
02489             {
02490                 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
02491                 hres = REGDB_E_CLASSNOTREG;
02492             }
02493         }
02494 
02495         if (SUCCEEDED(hres))
02496         {
02497             hres = get_inproc_class_object(apt, hkey, rclsid, iid,
02498                 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
02499             RegCloseKey(hkey);
02500         }
02501 
02502         /* return if we got a class, otherwise fall through to one of the
02503          * other types */
02504         if (SUCCEEDED(hres))
02505         {
02506             if (release_apt) apartment_release(apt);
02507             return hres;
02508         }
02509     }
02510     if (release_apt) apartment_release(apt);
02511 
02512     /* Next try out of process */
02513     if (CLSCTX_LOCAL_SERVER & dwClsContext)
02514     {
02515         hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
02516         if (SUCCEEDED(hres))
02517             return hres;
02518     }
02519 
02520     /* Finally try remote: this requires networked DCOM (a lot of work) */
02521     if (CLSCTX_REMOTE_SERVER & dwClsContext)
02522     {
02523         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
02524         hres = REGDB_E_CLASSNOTREG;
02525     }
02526 
02527     if (FAILED(hres))
02528         ERR("no class object %s could be created for context 0x%x\n",
02529             debugstr_guid(rclsid), dwClsContext);
02530     return hres;
02531 }
02532 
02533 /***********************************************************************
02534  *        CoResumeClassObjects (OLE32.@)
02535  *
02536  * Resumes all class objects registered with REGCLS_SUSPENDED.
02537  *
02538  * RETURNS
02539  *  Success: S_OK.
02540  *  Failure: HRESULT code.
02541  */
02542 HRESULT WINAPI CoResumeClassObjects(void)
02543 {
02544        FIXME("stub\n");
02545     return S_OK;
02546 }
02547 
02548 /***********************************************************************
02549  *           CoCreateInstance [OLE32.@]
02550  *
02551  * Creates an instance of the specified class.
02552  *
02553  * PARAMS
02554  *  rclsid       [I] Class ID to create an instance of.
02555  *  pUnkOuter    [I] Optional outer unknown to allow aggregation with another object.
02556  *  dwClsContext [I] Flags to restrict the location of the created instance.
02557  *  iid          [I] The ID of the interface of the instance to return.
02558  *  ppv          [O] On returns, contains a pointer to the specified interface of the instance.
02559  *
02560  * RETURNS
02561  *  Success: S_OK
02562  *  Failure: HRESULT code.
02563  *
02564  * NOTES
02565  *  The dwClsContext parameter can be one or more of the following:
02566  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
02567  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
02568  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
02569  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
02570  *
02571  * Aggregation is the concept of deferring the IUnknown of an object to another
02572  * object. This allows a separate object to behave as though it was part of
02573  * the object and to allow this the pUnkOuter parameter can be set. Note that
02574  * not all objects support having an outer of unknown.
02575  *
02576  * SEE ALSO
02577  *  CoGetClassObject()
02578  */
02579 HRESULT WINAPI CoCreateInstance(
02580     REFCLSID rclsid,
02581     LPUNKNOWN pUnkOuter,
02582     DWORD dwClsContext,
02583     REFIID iid,
02584     LPVOID *ppv)
02585 {
02586   HRESULT hres;
02587   LPCLASSFACTORY lpclf = 0;
02588   APARTMENT *apt;
02589 
02590   TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
02591         pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
02592 
02593   /*
02594    * Sanity check
02595    */
02596   if (ppv==0)
02597     return E_POINTER;
02598 
02599   /*
02600    * Initialize the "out" parameter
02601    */
02602   *ppv = 0;
02603 
02604   if (!(apt = COM_CurrentApt()))
02605   {
02606     if (!(apt = apartment_find_multi_threaded()))
02607     {
02608       ERR("apartment not initialised\n");
02609       return CO_E_NOTINITIALIZED;
02610     }
02611     apartment_release(apt);
02612   }
02613 
02614   /*
02615    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
02616    * Rather than create a class factory, we can just check for it here
02617    */
02618   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
02619     if (StdGlobalInterfaceTableInstance == NULL)
02620       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
02621     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
02622     if (hres) return hres;
02623 
02624     TRACE("Retrieved GIT (%p)\n", *ppv);
02625     return S_OK;
02626   }
02627 
02628   if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
02629       return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
02630 
02631   /*
02632    * Get a class factory to construct the object we want.
02633    */
02634   hres = CoGetClassObject(rclsid,
02635               dwClsContext,
02636               NULL,
02637               &IID_IClassFactory,
02638               (LPVOID)&lpclf);
02639 
02640   if (FAILED(hres))
02641     return hres;
02642 
02643   /*
02644    * Create the object and don't forget to release the factory
02645    */
02646     hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
02647     IClassFactory_Release(lpclf);
02648     if(FAILED(hres))
02649         {
02650           if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
02651               FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
02652           else
02653               FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
02654         }
02655 
02656     return hres;
02657 }
02658 
02659 /***********************************************************************
02660  *           CoCreateInstanceEx [OLE32.@]
02661  */
02662 HRESULT WINAPI CoCreateInstanceEx(
02663   REFCLSID      rclsid,
02664   LPUNKNOWN     pUnkOuter,
02665   DWORD         dwClsContext,
02666   COSERVERINFO* pServerInfo,
02667   ULONG         cmq,
02668   MULTI_QI*     pResults)
02669 {
02670   IUnknown* pUnk = NULL;
02671   HRESULT   hr;
02672   ULONG     index;
02673   ULONG     successCount = 0;
02674 
02675   /*
02676    * Sanity check
02677    */
02678   if ( (cmq==0) || (pResults==NULL))
02679     return E_INVALIDARG;
02680 
02681   if (pServerInfo!=NULL)
02682     FIXME("() non-NULL pServerInfo not supported!\n");
02683 
02684   /*
02685    * Initialize all the "out" parameters.
02686    */
02687   for (index = 0; index < cmq; index++)
02688   {
02689     pResults[index].pItf = NULL;
02690     pResults[index].hr   = E_NOINTERFACE;
02691   }
02692 
02693   /*
02694    * Get the object and get its IUnknown pointer.
02695    */
02696   hr = CoCreateInstance(rclsid,
02697             pUnkOuter,
02698             dwClsContext,
02699             &IID_IUnknown,
02700             (VOID**)&pUnk);
02701 
02702   if (hr)
02703     return hr;
02704 
02705   /*
02706    * Then, query for all the interfaces requested.
02707    */
02708   for (index = 0; index < cmq; index++)
02709   {
02710     pResults[index].hr = IUnknown_QueryInterface(pUnk,
02711                          pResults[index].pIID,
02712                          (VOID**)&(pResults[index].pItf));
02713 
02714     if (pResults[index].hr == S_OK)
02715       successCount++;
02716   }
02717 
02718   /*
02719    * Release our temporary unknown pointer.
02720    */
02721   IUnknown_Release(pUnk);
02722 
02723   if (successCount == 0)
02724     return E_NOINTERFACE;
02725 
02726   if (successCount!=cmq)
02727     return CO_S_NOTALLINTERFACES;
02728 
02729   return S_OK;
02730 }
02731 
02732 /***********************************************************************
02733  *           CoLoadLibrary (OLE32.@)
02734  *
02735  * Loads a library.
02736  *
02737  * PARAMS
02738  *  lpszLibName [I] Path to library.
02739  *  bAutoFree   [I] Whether the library should automatically be freed.
02740  *
02741  * RETURNS
02742  *  Success: Handle to loaded library.
02743  *  Failure: NULL.
02744  *
02745  * SEE ALSO
02746  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
02747  */
02748 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
02749 {
02750     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
02751 
02752     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
02753 }
02754 
02755 /***********************************************************************
02756  *           CoFreeLibrary [OLE32.@]
02757  *
02758  * Unloads a library from memory.
02759  *
02760  * PARAMS
02761  *  hLibrary [I] Handle to library to unload.
02762  *
02763  * RETURNS
02764  *  Nothing
02765  *
02766  * SEE ALSO
02767  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
02768  */
02769 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
02770 {
02771     FreeLibrary(hLibrary);
02772 }
02773 
02774 
02775 /***********************************************************************
02776  *           CoFreeAllLibraries [OLE32.@]
02777  *
02778  * Function for backwards compatibility only. Does nothing.
02779  *
02780  * RETURNS
02781  *  Nothing.
02782  *
02783  * SEE ALSO
02784  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
02785  */
02786 void WINAPI CoFreeAllLibraries(void)
02787 {
02788     /* NOP */
02789 }
02790 
02791 /***********************************************************************
02792  *           CoFreeUnusedLibrariesEx [OLE32.@]
02793  *
02794  * Frees any previously unused libraries whose delay has expired and marks
02795  * currently unused libraries for unloading. Unused are identified as those that
02796  * return S_OK from their DllCanUnloadNow function.
02797  *
02798  * PARAMS
02799  *  dwUnloadDelay [I] Unload delay in milliseconds.
02800  *  dwReserved    [I] Reserved. Set to 0.
02801  *
02802  * RETURNS
02803  *  Nothing.
02804  *
02805  * SEE ALSO
02806  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
02807  */
02808 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
02809 {
02810     struct apartment *apt = COM_CurrentApt();
02811     if (!apt)
02812     {
02813         ERR("apartment not initialised\n");
02814         return;
02815     }
02816 
02817     apartment_freeunusedlibraries(apt, dwUnloadDelay);
02818 }
02819 
02820 /***********************************************************************
02821  *           CoFreeUnusedLibraries [OLE32.@]
02822  *
02823  * Frees any unused libraries. Unused are identified as those that return
02824  * S_OK from their DllCanUnloadNow function.
02825  *
02826  * RETURNS
02827  *  Nothing.
02828  *
02829  * SEE ALSO
02830  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
02831  */
02832 void WINAPI CoFreeUnusedLibraries(void)
02833 {
02834     CoFreeUnusedLibrariesEx(INFINITE, 0);
02835 }
02836 
02837 /***********************************************************************
02838  *           CoFileTimeNow [OLE32.@]
02839  *
02840  * Retrieves the current time in FILETIME format.
02841  *
02842  * PARAMS
02843  *  lpFileTime [O] The current time.
02844  *
02845  * RETURNS
02846  *  S_OK.
02847  */
02848 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
02849 {
02850     GetSystemTimeAsFileTime( lpFileTime );
02851     return S_OK;
02852 }
02853 
02854 /******************************************************************************
02855  *      CoLockObjectExternal    [OLE32.@]
02856  *
02857  * Increments or decrements the external reference count of a stub object.
02858  *
02859  * PARAMS
02860  *  pUnk                [I] Stub object.
02861  *  fLock               [I] If TRUE then increments the external ref-count,
02862  *                          otherwise decrements.
02863  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
02864  *                          calling CoDisconnectObject.
02865  *
02866  * RETURNS
02867  *  Success: S_OK.
02868  *  Failure: HRESULT code.
02869  *
02870  * NOTES
02871  *  If fLock is TRUE and an object is passed in that doesn't have a stub
02872  *  manager then a new stub manager is created for the object.
02873  */
02874 HRESULT WINAPI CoLockObjectExternal(
02875     LPUNKNOWN pUnk,
02876     BOOL fLock,
02877     BOOL fLastUnlockReleases)
02878 {
02879     struct stub_manager *stubmgr;
02880     struct apartment *apt;
02881 
02882     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
02883           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
02884 
02885     apt = COM_CurrentApt();
02886     if (!apt) return CO_E_NOTINITIALIZED;
02887 
02888     stubmgr = get_stub_manager_from_object(apt, pUnk);
02889     
02890     if (stubmgr)
02891     {
02892         if (fLock)
02893             stub_manager_ext_addref(stubmgr, 1, FALSE);
02894         else
02895             stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
02896         
02897         stub_manager_int_release(stubmgr);
02898 
02899         return S_OK;
02900     }
02901     else if (fLock)
02902     {
02903         stubmgr = new_stub_manager(apt, pUnk);
02904 
02905         if (stubmgr)
02906         {
02907             stub_manager_ext_addref(stubmgr, 1, FALSE);
02908             stub_manager_int_release(stubmgr);
02909         }
02910 
02911         return S_OK;
02912     }
02913     else
02914     {
02915         WARN("stub object not found %p\n", pUnk);
02916         /* Note: native is pretty broken here because it just silently
02917          * fails, without returning an appropriate error code, making apps
02918          * think that the object was disconnected, when it actually wasn't */
02919         return S_OK;
02920     }
02921 }
02922 
02923 /***********************************************************************
02924  *           CoInitializeWOW (OLE32.@)
02925  *
02926  * WOW equivalent of CoInitialize?
02927  *
02928  * PARAMS
02929  *  x [I] Unknown.
02930  *  y [I] Unknown.
02931  *
02932  * RETURNS
02933  *  Unknown.
02934  */
02935 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
02936 {
02937     FIXME("(0x%08x,0x%08x),stub!\n",x,y);
02938     return 0;
02939 }
02940 
02941 /***********************************************************************
02942  *           CoGetState [OLE32.@]
02943  *
02944  * Retrieves the thread state object previously stored by CoSetState().
02945  *
02946  * PARAMS
02947  *  ppv [I] Address where pointer to object will be stored.
02948  *
02949  * RETURNS
02950  *  Success: S_OK.
02951  *  Failure: E_OUTOFMEMORY.
02952  *
02953  * NOTES
02954  *  Crashes on all invalid ppv addresses, including NULL.
02955  *  If the function returns a non-NULL object then the caller must release its
02956  *  reference on the object when the object is no longer required.
02957  *
02958  * SEE ALSO
02959  *  CoSetState().
02960  */
02961 HRESULT WINAPI CoGetState(IUnknown ** ppv)
02962 {
02963     struct oletls *info = COM_CurrentInfo();
02964     if (!info) return E_OUTOFMEMORY;
02965 
02966     *ppv = NULL;
02967 
02968     if (info->state)
02969     {
02970         IUnknown_AddRef(info->state);
02971         *ppv = info->state;
02972         TRACE("apt->state=%p\n", info->state);
02973     }
02974 
02975     return S_OK;
02976 }
02977 
02978 /***********************************************************************
02979  *           CoSetState [OLE32.@]
02980  *
02981  * Sets the thread state object.
02982  *
02983  * PARAMS
02984  *  pv [I] Pointer to state object to be stored.
02985  *
02986  * NOTES
02987  *  The system keeps a reference on the object while the object stored.
02988  *
02989  * RETURNS
02990  *  Success: S_OK.
02991  *  Failure: E_OUTOFMEMORY.
02992  */
02993 HRESULT WINAPI CoSetState(IUnknown * pv)
02994 {
02995     struct oletls *info = COM_CurrentInfo();
02996     if (!info) return E_OUTOFMEMORY;
02997 
02998     if (pv) IUnknown_AddRef(pv);
02999 
03000     if (info->state)
03001     {
03002         TRACE("-- release %p now\n", info->state);
03003         IUnknown_Release(info->state);
03004     }
03005 
03006     info->state = pv;
03007 
03008     return S_OK;
03009 }
03010 
03011 
03012 /******************************************************************************
03013  *              CoTreatAsClass        [OLE32.@]
03014  *
03015  * Sets the TreatAs value of a class.
03016  *
03017  * PARAMS
03018  *  clsidOld [I] Class to set TreatAs value on.
03019  *  clsidNew [I] The class the clsidOld should be treated as.
03020  *
03021  * RETURNS
03022  *  Success: S_OK.
03023  *  Failure: HRESULT code.
03024  *
03025  * SEE ALSO
03026  *  CoGetTreatAsClass
03027  */
03028 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
03029 {
03030     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
03031     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
03032     HKEY hkey = NULL;
03033     WCHAR szClsidNew[CHARS_IN_GUID];
03034     HRESULT res = S_OK;
03035     WCHAR auto_treat_as[CHARS_IN_GUID];
03036     LONG auto_treat_as_size = sizeof(auto_treat_as);
03037     CLSID id;
03038 
03039     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
03040     if (FAILED(res))
03041         goto done;
03042     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
03043     {
03044        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
03045            CLSIDFromString(auto_treat_as, &id) == S_OK)
03046        {
03047            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
03048            {
03049                res = REGDB_E_WRITEREGDB;
03050                goto done;
03051            }
03052        }
03053        else
03054        {
03055            RegDeleteKeyW(hkey, wszTreatAs);
03056            goto done;
03057        }
03058     }
03059     else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
03060              !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
03061     {
03062         res = REGDB_E_WRITEREGDB;
03063     goto done;
03064     }
03065 
03066 done:
03067     if (hkey) RegCloseKey(hkey);
03068     return res;
03069 }
03070 
03071 /******************************************************************************
03072  *              CoGetTreatAsClass        [OLE32.@]
03073  *
03074  * Gets the TreatAs value of a class.
03075  *
03076  * PARAMS
03077  *  clsidOld [I] Class to get the TreatAs value of.
03078  *  clsidNew [I] The class the clsidOld should be treated as.
03079  *
03080  * RETURNS
03081  *  Success: S_OK.
03082  *  Failure: HRESULT code.
03083  *
03084  * SEE ALSO
03085  *  CoSetTreatAsClass
03086  */
03087 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
03088 {
03089     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
03090     HKEY hkey = NULL;
03091     WCHAR szClsidNew[CHARS_IN_GUID];
03092     HRESULT res = S_OK;
03093     LONG len = sizeof(szClsidNew);
03094 
03095     TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
03096     *clsidNew = *clsidOld; /* copy over old value */
03097 
03098     res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
03099     if (FAILED(res))
03100     {
03101         res = S_FALSE;
03102         goto done;
03103     }
03104     if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
03105     {
03106         res = S_FALSE;
03107     goto done;
03108     }
03109     res = CLSIDFromString(szClsidNew,clsidNew);
03110     if (FAILED(res))
03111         ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
03112 done:
03113     if (hkey) RegCloseKey(hkey);
03114     return res;
03115 }
03116 
03117 /******************************************************************************
03118  *      CoGetCurrentProcess [OLE32.@]
03119  *
03120  * Gets the current process ID.
03121  *
03122  * RETURNS
03123  *  The current process ID.
03124  *
03125  * NOTES
03126  *   Is DWORD really the correct return type for this function?
03127  */
03128 DWORD WINAPI CoGetCurrentProcess(void)
03129 {
03130     return GetCurrentProcessId();
03131 }
03132 
03133 /******************************************************************************
03134  *      CoRegisterMessageFilter [OLE32.@]
03135  *
03136  * Registers a message filter.
03137  *
03138  * PARAMS
03139  *  lpMessageFilter [I] Pointer to interface.
03140  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
03141  *
03142  * RETURNS
03143  *  Success: S_OK.
03144  *  Failure: HRESULT code.
03145  *
03146  * NOTES
03147  *  Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
03148  *  lpMessageFilter removes the message filter.
03149  *
03150  *  If lplpMessageFilter is not NULL the previous message filter will be
03151  *  returned in the memory pointer to this parameter and the caller is
03152  *  responsible for releasing the object.
03153  *
03154  *  The current thread be in an apartment otherwise the function will crash.
03155  */
03156 HRESULT WINAPI CoRegisterMessageFilter(
03157     LPMESSAGEFILTER lpMessageFilter,
03158     LPMESSAGEFILTER *lplpMessageFilter)
03159 {
03160     struct apartment *apt;
03161     IMessageFilter *lpOldMessageFilter;
03162 
03163     TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
03164 
03165     apt = COM_CurrentApt();
03166 
03167     /* can't set a message filter in a multi-threaded apartment */
03168     if (!apt || apt->multi_threaded)
03169     {
03170         WARN("can't set message filter in MTA or uninitialized apt\n");
03171         return CO_E_NOT_SUPPORTED;
03172     }
03173 
03174     if (lpMessageFilter)
03175         IMessageFilter_AddRef(lpMessageFilter);
03176 
03177     EnterCriticalSection(&apt->cs);
03178 
03179     lpOldMessageFilter = apt->filter;
03180     apt->filter = lpMessageFilter;
03181 
03182     LeaveCriticalSection(&apt->cs);
03183 
03184     if (lplpMessageFilter)
03185         *lplpMessageFilter = lpOldMessageFilter;
03186     else if (lpOldMessageFilter)
03187         IMessageFilter_Release(lpOldMessageFilter);
03188 
03189     return S_OK;
03190 }
03191 
03192 /***********************************************************************
03193  *           CoIsOle1Class [OLE32.@]
03194  *
03195  * Determines whether the specified class an OLE v1 class.
03196  *
03197  * PARAMS
03198  *  clsid [I] Class to test.
03199  *
03200  * RETURNS
03201  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
03202  */
03203 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
03204 {
03205   FIXME("%s\n", debugstr_guid(clsid));
03206   return FALSE;
03207 }
03208 
03209 /***********************************************************************
03210  *           IsEqualGUID [OLE32.@]
03211  *
03212  * Compares two Unique Identifiers.
03213  *
03214  * PARAMS
03215  *  rguid1 [I] The first GUID to compare.
03216  *  rguid2 [I] The other GUID to compare.
03217  *
03218  * RETURNS
03219  *  TRUE if equal
03220  */
03221 #undef IsEqualGUID
03222 BOOL WINAPI IsEqualGUID(
03223      REFGUID rguid1,
03224      REFGUID rguid2)
03225 {
03226     return !memcmp(rguid1,rguid2,sizeof(GUID));
03227 }
03228 
03229 /***********************************************************************
03230  *           CoInitializeSecurity [OLE32.@]
03231  */
03232 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
03233                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
03234                                     void* pReserved1, DWORD dwAuthnLevel,
03235                                     DWORD dwImpLevel, void* pReserved2,
03236                                     DWORD dwCapabilities, void* pReserved3)
03237 {
03238   FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
03239         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
03240         dwCapabilities, pReserved3);
03241   return S_OK;
03242 }
03243 
03244 /***********************************************************************
03245  *           CoSuspendClassObjects [OLE32.@]
03246  *
03247  * Suspends all registered class objects to prevent further requests coming in
03248  * for those objects.
03249  *
03250  * RETURNS
03251  *  Success: S_OK.
03252  *  Failure: HRESULT code.
03253  */
03254 HRESULT WINAPI CoSuspendClassObjects(void)
03255 {
03256     FIXME("\n");
03257     return S_OK;
03258 }
03259 
03260 /***********************************************************************
03261  *           CoAddRefServerProcess [OLE32.@]
03262  *
03263  * Helper function for incrementing the reference count of a local-server
03264  * process.
03265  *
03266  * RETURNS
03267  *  New reference count.
03268  *
03269  * SEE ALSO
03270  *  CoReleaseServerProcess().
03271  */
03272 ULONG WINAPI CoAddRefServerProcess(void)
03273 {
03274     ULONG refs;
03275 
03276     TRACE("\n");
03277 
03278     EnterCriticalSection(&csRegisteredClassList);
03279     refs = ++s_COMServerProcessReferences;
03280     LeaveCriticalSection(&csRegisteredClassList);
03281 
03282     TRACE("refs before: %d\n", refs - 1);
03283 
03284     return refs;
03285 }
03286 
03287 /***********************************************************************
03288  *           CoReleaseServerProcess [OLE32.@]
03289  *
03290  * Helper function for decrementing the reference count of a local-server
03291  * process.
03292  *
03293  * RETURNS
03294  *  New reference count.
03295  *
03296  * NOTES
03297  *  When reference count reaches 0, this function suspends all registered
03298  *  classes so no new connections are accepted.
03299  *
03300  * SEE ALSO
03301  *  CoAddRefServerProcess(), CoSuspendClassObjects().
03302  */
03303 ULONG WINAPI CoReleaseServerProcess(void)
03304 {
03305     ULONG refs;
03306 
03307     TRACE("\n");
03308 
03309     EnterCriticalSection(&csRegisteredClassList);
03310 
03311     refs = --s_COMServerProcessReferences;
03312     /* FIXME: if (!refs) COM_SuspendClassObjects(); */
03313 
03314     LeaveCriticalSection(&csRegisteredClassList);
03315 
03316     TRACE("refs after: %d\n", refs);
03317 
03318     return refs;
03319 }
03320 
03321 /***********************************************************************
03322  *           CoIsHandlerConnected [OLE32.@]
03323  *
03324  * Determines whether a proxy is connected to a remote stub.
03325  *
03326  * PARAMS
03327  *  pUnk [I] Pointer to object that may or may not be connected.
03328  *
03329  * RETURNS
03330  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
03331  *  FALSE otherwise.
03332  */
03333 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
03334 {
03335     FIXME("%p\n", pUnk);
03336 
03337     return TRUE;
03338 }
03339 
03340 /***********************************************************************
03341  *           CoAllowSetForegroundWindow [OLE32.@]
03342  *
03343  */
03344 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
03345 {
03346     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
03347     return S_OK;
03348 }
03349  
03350 /***********************************************************************
03351  *           CoQueryProxyBlanket [OLE32.@]
03352  *
03353  * Retrieves the security settings being used by a proxy.
03354  *
03355  * PARAMS
03356  *  pProxy        [I] Pointer to the proxy object.
03357  *  pAuthnSvc     [O] The type of authentication service.
03358  *  pAuthzSvc     [O] The type of authorization service.
03359  *  ppServerPrincName [O] Optional. The server prinicple name.
03360  *  pAuthnLevel   [O] The authentication level.
03361  *  pImpLevel     [O] The impersonation level.
03362  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
03363  *  pCapabilities [O] Flags affecting the security behaviour.
03364  *
03365  * RETURNS
03366  *  Success: S_OK.
03367  *  Failure: HRESULT code.
03368  *
03369  * SEE ALSO
03370  *  CoCopyProxy, CoSetProxyBlanket.
03371  */
03372 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
03373     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
03374     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
03375 {
03376     IClientSecurity *pCliSec;
03377     HRESULT hr;
03378 
03379     TRACE("%p\n", pProxy);
03380 
03381     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
03382     if (SUCCEEDED(hr))
03383     {
03384         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
03385                                           pAuthzSvc, ppServerPrincName,
03386                                           pAuthnLevel, pImpLevel, ppAuthInfo,
03387                                           pCapabilities);
03388         IClientSecurity_Release(pCliSec);
03389     }
03390 
03391     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
03392     return hr;
03393 }
03394 
03395 /***********************************************************************
03396  *           CoSetProxyBlanket [OLE32.@]
03397  *
03398  * Sets the security settings for a proxy.
03399  *
03400  * PARAMS
03401  *  pProxy       [I] Pointer to the proxy object.
03402  *  AuthnSvc     [I] The type of authentication service.
03403  *  AuthzSvc     [I] The type of authorization service.
03404  *  pServerPrincName [I] The server prinicple name.
03405  *  AuthnLevel   [I] The authentication level.
03406  *  ImpLevel     [I] The impersonation level.
03407  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
03408  *  Capabilities [I] Flags affecting the security behaviour.
03409  *
03410  * RETURNS
03411  *  Success: S_OK.
03412  *  Failure: HRESULT code.
03413  *
03414  * SEE ALSO
03415  *  CoQueryProxyBlanket, CoCopyProxy.
03416  */
03417 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
03418     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
03419     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
03420 {
03421     IClientSecurity *pCliSec;
03422     HRESULT hr;
03423 
03424     TRACE("%p\n", pProxy);
03425 
03426     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
03427     if (SUCCEEDED(hr))
03428     {
03429         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
03430                                         AuthzSvc, pServerPrincName,
03431                                         AuthnLevel, ImpLevel, pAuthInfo,
03432                                         Capabilities);
03433         IClientSecurity_Release(pCliSec);
03434     }
03435 
03436     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
03437     return hr;
03438 }
03439 
03440 /***********************************************************************
03441  *           CoCopyProxy [OLE32.@]
03442  *
03443  * Copies a proxy.
03444  *
03445  * PARAMS
03446  *  pProxy [I] Pointer to the proxy object.
03447  *  ppCopy [O] Copy of the proxy.
03448  *
03449  * RETURNS
03450  *  Success: S_OK.
03451  *  Failure: HRESULT code.
03452  *
03453  * SEE ALSO
03454  *  CoQueryProxyBlanket, CoSetProxyBlanket.
03455  */
03456 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
03457 {
03458     IClientSecurity *pCliSec;
03459     HRESULT hr;
03460 
03461     TRACE("%p\n", pProxy);
03462 
03463     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
03464     if (SUCCEEDED(hr))
03465     {
03466         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
03467         IClientSecurity_Release(pCliSec);
03468     }
03469 
03470     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
03471     return hr;
03472 }
03473 
03474 
03475 /***********************************************************************
03476  *           CoGetCallContext [OLE32.@]
03477  *
03478  * Gets the context of the currently executing server call in the current
03479  * thread.
03480  *
03481  * PARAMS
03482  *  riid [I] Context interface to return.
03483  *  ppv  [O] Pointer to memory that will receive the context on return.
03484  *
03485  * RETURNS
03486  *  Success: S_OK.
03487  *  Failure: HRESULT code.
03488  */
03489 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
03490 {
03491     struct oletls *info = COM_CurrentInfo();
03492 
03493     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
03494 
03495     if (!info)
03496         return E_OUTOFMEMORY;
03497 
03498     if (!info->call_state)
03499         return RPC_E_CALL_COMPLETE;
03500 
03501     return IUnknown_QueryInterface(info->call_state, riid, ppv);
03502 }
03503 
03504 /***********************************************************************
03505  *           CoSwitchCallContext [OLE32.@]
03506  *
03507  * Switches the context of the currently executing server call in the current
03508  * thread.
03509  *
03510  * PARAMS
03511  *  pObject     [I] Pointer to new context object
03512  *  ppOldObject [O] Pointer to memory that will receive old context object pointer
03513  *
03514  * RETURNS
03515  *  Success: S_OK.
03516  *  Failure: HRESULT code.
03517  */
03518 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
03519 {
03520     struct oletls *info = COM_CurrentInfo();
03521 
03522     TRACE("(%p, %p)\n", pObject, ppOldObject);
03523 
03524     if (!info)
03525         return E_OUTOFMEMORY;
03526 
03527     *ppOldObject = info->call_state;
03528     info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
03529 
03530     return S_OK;
03531 }
03532 
03533 /***********************************************************************
03534  *           CoQueryClientBlanket [OLE32.@]
03535  *
03536  * Retrieves the authentication information about the client of the currently
03537  * executing server call in the current thread.
03538  *
03539  * PARAMS
03540  *  pAuthnSvc     [O] Optional. The type of authentication service.
03541  *  pAuthzSvc     [O] Optional. The type of authorization service.
03542  *  pServerPrincName [O] Optional. The server prinicple name.
03543  *  pAuthnLevel   [O] Optional. The authentication level.
03544  *  pImpLevel     [O] Optional. The impersonation level.
03545  *  pPrivs        [O] Optional. Information about the privileges of the client.
03546  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
03547  *
03548  * RETURNS
03549  *  Success: S_OK.
03550  *  Failure: HRESULT code.
03551  *
03552  * SEE ALSO
03553  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
03554  */
03555 HRESULT WINAPI CoQueryClientBlanket(
03556     DWORD *pAuthnSvc,
03557     DWORD *pAuthzSvc,
03558     OLECHAR **pServerPrincName,
03559     DWORD *pAuthnLevel,
03560     DWORD *pImpLevel,
03561     RPC_AUTHZ_HANDLE *pPrivs,
03562     DWORD *pCapabilities)
03563 {
03564     IServerSecurity *pSrvSec;
03565     HRESULT hr;
03566 
03567     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
03568         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
03569         pPrivs, pCapabilities);
03570 
03571     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
03572     if (SUCCEEDED(hr))
03573     {
03574         hr = IServerSecurity_QueryBlanket(
03575             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
03576             pImpLevel, pPrivs, pCapabilities);
03577         IServerSecurity_Release(pSrvSec);
03578     }
03579 
03580     return hr;
03581 }
03582 
03583 /***********************************************************************
03584  *           CoImpersonateClient [OLE32.@]
03585  *
03586  * Impersonates the client of the currently executing server call in the
03587  * current thread.
03588  *
03589  * PARAMS
03590  *  None.
03591  *
03592  * RETURNS
03593  *  Success: S_OK.
03594  *  Failure: HRESULT code.
03595  *
03596  * NOTES
03597  *  If this function fails then the current thread will not be impersonating
03598  *  the client and all actions will take place on behalf of the server.
03599  *  Therefore, it is important to check the return value from this function.
03600  *
03601  * SEE ALSO
03602  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
03603  */
03604 HRESULT WINAPI CoImpersonateClient(void)
03605 {
03606     IServerSecurity *pSrvSec;
03607     HRESULT hr;
03608 
03609     TRACE("\n");
03610 
03611     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
03612     if (SUCCEEDED(hr))
03613     {
03614         hr = IServerSecurity_ImpersonateClient(pSrvSec);
03615         IServerSecurity_Release(pSrvSec);
03616     }
03617 
03618     return hr;
03619 }
03620 
03621 /***********************************************************************
03622  *           CoRevertToSelf [OLE32.@]
03623  *
03624  * Ends the impersonation of the client of the currently executing server
03625  * call in the current thread.
03626  *
03627  * PARAMS
03628  *  None.
03629  *
03630  * RETURNS
03631  *  Success: S_OK.
03632  *  Failure: HRESULT code.
03633  *
03634  * SEE ALSO
03635  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
03636  */
03637 HRESULT WINAPI CoRevertToSelf(void)
03638 {
03639     IServerSecurity *pSrvSec;
03640     HRESULT hr;
03641 
03642     TRACE("\n");
03643 
03644     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
03645     if (SUCCEEDED(hr))
03646     {
03647         hr = IServerSecurity_RevertToSelf(pSrvSec);
03648         IServerSecurity_Release(pSrvSec);
03649     }
03650 
03651     return hr;
03652 }
03653 
03654 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
03655 {
03656     /* first try to retrieve messages for incoming COM calls to the apartment window */
03657     return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
03658            /* next retrieve other messages necessary for the app to remain responsive */
03659            PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
03660            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
03661 }
03662 
03663 /***********************************************************************
03664  *           CoWaitForMultipleHandles [OLE32.@]
03665  *
03666  * Waits for one or more handles to become signaled.
03667  *
03668  * PARAMS
03669  *  dwFlags   [I] Flags. See notes.
03670  *  dwTimeout [I] Timeout in milliseconds.
03671  *  cHandles  [I] Number of handles pointed to by pHandles.
03672  *  pHandles  [I] Handles to wait for.
03673  *  lpdwindex [O] Index of handle that was signaled.
03674  *
03675  * RETURNS
03676  *  Success: S_OK.
03677  *  Failure: RPC_S_CALLPENDING on timeout.
03678  *
03679  * NOTES
03680  *
03681  * The dwFlags parameter can be zero or more of the following:
03682  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
03683  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
03684  *
03685  * SEE ALSO
03686  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
03687  */
03688 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
03689     ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
03690 {
03691     HRESULT hr = S_OK;
03692     DWORD start_time = GetTickCount();
03693     APARTMENT *apt = COM_CurrentApt();
03694     BOOL message_loop = apt && !apt->multi_threaded;
03695 
03696     TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
03697         pHandles, lpdwindex);
03698 
03699     while (TRUE)
03700     {
03701         DWORD now = GetTickCount();
03702         DWORD res;
03703 
03704         if (now - start_time > dwTimeout)
03705         {
03706             hr = RPC_S_CALLPENDING;
03707             break;
03708         }
03709 
03710         if (message_loop)
03711         {
03712             DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
03713                     ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
03714 
03715             TRACE("waiting for rpc completion or window message\n");
03716 
03717             res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
03718                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
03719                 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
03720 
03721             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
03722             {
03723                 MSG msg;
03724 
03725                 /* call message filter */
03726 
03727                 if (COM_CurrentApt()->filter)
03728                 {
03729                     PENDINGTYPE pendingtype =
03730                         COM_CurrentInfo()->pending_call_count_server ?
03731                             PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
03732                     DWORD be_handled = IMessageFilter_MessagePending(
03733                         COM_CurrentApt()->filter, 0 /* FIXME */,
03734                         now - start_time, pendingtype);
03735                     TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
03736                     switch (be_handled)
03737                     {
03738                     case PENDINGMSG_CANCELCALL:
03739                         WARN("call canceled\n");
03740                         hr = RPC_E_CALL_CANCELED;
03741                         break;
03742                     case PENDINGMSG_WAITNOPROCESS:
03743                     case PENDINGMSG_WAITDEFPROCESS:
03744                     default:
03745                         /* FIXME: MSDN is very vague about the difference
03746                          * between WAITNOPROCESS and WAITDEFPROCESS - there
03747                          * appears to be none, so it is possibly a left-over
03748                          * from the 16-bit world. */
03749                         break;
03750                     }
03751                 }
03752 
03753                 while (COM_PeekMessage(apt, &msg))
03754                 {
03755                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
03756                     TranslateMessage(&msg);
03757                     DispatchMessageW(&msg);
03758                     if (msg.message == WM_QUIT)
03759                     {
03760                         TRACE("resending WM_QUIT to outer message loop\n");
03761                         PostQuitMessage(msg.wParam);
03762                         /* no longer need to process messages */
03763                         message_loop = FALSE;
03764                         break;
03765                     }
03766                 }
03767                 continue;
03768             }
03769         }
03770         else
03771         {
03772             TRACE("waiting for rpc completion\n");
03773 
03774             res = WaitForMultipleObjectsEx(cHandles, pHandles,
03775                 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
03776                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
03777                 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
03778         }
03779 
03780         switch (res)
03781         {
03782         case WAIT_TIMEOUT:
03783             hr = RPC_S_CALLPENDING;
03784             break;
03785         case WAIT_FAILED:
03786             hr = HRESULT_FROM_WIN32( GetLastError() );
03787             break;
03788         default:
03789             *lpdwindex = res;
03790             break;
03791         }
03792         break;
03793     }
03794     TRACE("-- 0x%08x\n", hr);
03795     return hr;
03796 }
03797 
03798 
03799 /***********************************************************************
03800  *           CoGetObject [OLE32.@]
03801  *
03802  * Gets the object named by converting the name to a moniker and binding to it.
03803  *
03804  * PARAMS
03805  *  pszName      [I] String representing the object.
03806  *  pBindOptions [I] Parameters affecting the binding to the named object.
03807  *  riid         [I] Interface to bind to on the objecct.
03808  *  ppv          [O] On output, the interface riid of the object represented
03809  *                   by pszName.
03810  *
03811  * RETURNS
03812  *  Success: S_OK.
03813  *  Failure: HRESULT code.
03814  *
03815  * SEE ALSO
03816  *  MkParseDisplayName.
03817  */
03818 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
03819     REFIID riid, void **ppv)
03820 {
03821     IBindCtx *pbc;
03822     HRESULT hr;
03823 
03824     *ppv = NULL;
03825 
03826     hr = CreateBindCtx(0, &pbc);
03827     if (SUCCEEDED(hr))
03828     {
03829         if (pBindOptions)
03830             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
03831 
03832         if (SUCCEEDED(hr))
03833         {
03834             ULONG chEaten;
03835             IMoniker *pmk;
03836 
03837             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
03838             if (SUCCEEDED(hr))
03839             {
03840                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
03841                 IMoniker_Release(pmk);
03842             }
03843         }
03844 
03845         IBindCtx_Release(pbc);
03846     }
03847     return hr;
03848 }
03849 
03850 /***********************************************************************
03851  *           CoRegisterChannelHook [OLE32.@]
03852  *
03853  * Registers a process-wide hook that is called during ORPC calls.
03854  *
03855  * PARAMS
03856  *  guidExtension [I] GUID of the channel hook to register.
03857  *  pChannelHook  [I] Channel hook object to register.
03858  *
03859  * RETURNS
03860  *  Success: S_OK.
03861  *  Failure: HRESULT code.
03862  */
03863 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
03864 {
03865     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
03866 
03867     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
03868 }
03869 
03870 typedef struct Context
03871 {
03872     IComThreadingInfo IComThreadingInfo_iface;
03873     IContextCallback IContextCallback_iface;
03874     IObjContext IObjContext_iface;
03875     LONG refs;
03876     APTTYPE apttype;
03877 } Context;
03878 
03879 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
03880 {
03881         return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
03882 }
03883 
03884 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
03885 {
03886         return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
03887 }
03888 
03889 static inline Context *impl_from_IObjContext( IObjContext *iface )
03890 {
03891         return CONTAINING_RECORD(iface, Context, IObjContext_iface);
03892 }
03893 
03894 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
03895 {
03896     *ppv = NULL;
03897 
03898     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
03899         IsEqualIID(riid, &IID_IUnknown))
03900     {
03901         *ppv = &iface->IComThreadingInfo_iface;
03902     }
03903     else if (IsEqualIID(riid, &IID_IContextCallback))
03904     {
03905         *ppv = &iface->IContextCallback_iface;
03906     }
03907     else if (IsEqualIID(riid, &IID_IObjContext))
03908     {
03909         *ppv = &iface->IObjContext_iface;
03910     }
03911 
03912     if (*ppv)
03913     {
03914         IUnknown_AddRef((IUnknown*)*ppv);
03915         return S_OK;
03916     }
03917 
03918     FIXME("interface not implemented %s\n", debugstr_guid(riid));
03919     return E_NOINTERFACE;
03920 }
03921 
03922 static ULONG Context_AddRef(Context *This)
03923 {
03924     return InterlockedIncrement(&This->refs);
03925 }
03926 
03927 static ULONG Context_Release(Context *This)
03928 {
03929     ULONG refs = InterlockedDecrement(&This->refs);
03930     if (!refs)
03931         HeapFree(GetProcessHeap(), 0, This);
03932     return refs;
03933 }
03934 
03935 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
03936 {
03937     Context *This = impl_from_IComThreadingInfo(iface);
03938     return Context_QueryInterface(This, riid, ppv);
03939 }
03940 
03941 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
03942 {
03943     Context *This = impl_from_IComThreadingInfo(iface);
03944     return Context_AddRef(This);
03945 }
03946 
03947 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
03948 {
03949     Context *This = impl_from_IComThreadingInfo(iface);
03950     return Context_Release(This);
03951 }
03952 
03953 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
03954 {
03955     Context *This = impl_from_IComThreadingInfo(iface);
03956 
03957     TRACE("(%p)\n", apttype);
03958 
03959     *apttype = This->apttype;
03960     return S_OK;
03961 }
03962 
03963 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
03964 {
03965     Context *This = impl_from_IComThreadingInfo(iface);
03966 
03967     TRACE("(%p)\n", thdtype);
03968 
03969     switch (This->apttype)
03970     {
03971     case APTTYPE_STA:
03972     case APTTYPE_MAINSTA:
03973         *thdtype = THDTYPE_PROCESSMESSAGES;
03974         break;
03975     default:
03976         *thdtype = THDTYPE_BLOCKMESSAGES;
03977         break;
03978     }
03979     return S_OK;
03980 }
03981 
03982 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
03983 {
03984     FIXME("(%p): stub\n", logical_thread_id);
03985     return E_NOTIMPL;
03986 }
03987 
03988 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
03989 {
03990     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
03991     return E_NOTIMPL;
03992 }
03993 
03994 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
03995 {
03996     Context_CTI_QueryInterface,
03997     Context_CTI_AddRef,
03998     Context_CTI_Release,
03999     Context_CTI_GetCurrentApartmentType,
04000     Context_CTI_GetCurrentThreadType,
04001     Context_CTI_GetCurrentLogicalThreadId,
04002     Context_CTI_SetCurrentLogicalThreadId
04003 };
04004 
04005 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
04006 {
04007     Context *This = impl_from_IContextCallback(iface);
04008     return Context_QueryInterface(This, riid, ppv);
04009 }
04010 
04011 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
04012 {
04013     Context *This = impl_from_IContextCallback(iface);
04014     return Context_AddRef(This);
04015 }
04016 
04017 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
04018 {
04019     Context *This = impl_from_IContextCallback(iface);
04020     return Context_Release(This);
04021 }
04022 
04023 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
04024                             ComCallData *param, REFIID riid, int method, IUnknown *punk)
04025 {
04026     Context *This = impl_from_IContextCallback(iface);
04027 
04028     FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
04029     return E_NOTIMPL;
04030 }
04031 
04032 static const IContextCallbackVtbl Context_Callback_Vtbl =
04033 {
04034     Context_CC_QueryInterface,
04035     Context_CC_AddRef,
04036     Context_CC_Release,
04037     Context_CC_ContextCallback
04038 };
04039 
04040 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
04041 {
04042     Context *This = impl_from_IObjContext(iface);
04043     return Context_QueryInterface(This, riid, ppv);
04044 }
04045 
04046 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
04047 {
04048     Context *This = impl_from_IObjContext(iface);
04049     return Context_AddRef(This);
04050 }
04051 
04052 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
04053 {
04054     Context *This = impl_from_IObjContext(iface);
04055     return Context_Release(This);
04056 }
04057 
04058 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
04059 {
04060     Context *This = impl_from_IObjContext(iface);
04061 
04062     FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
04063     return E_NOTIMPL;
04064 }
04065 
04066 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
04067 {
04068     Context *This = impl_from_IObjContext(iface);
04069 
04070     FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
04071     return E_NOTIMPL;
04072 }
04073 
04074 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
04075 {
04076     Context *This = impl_from_IObjContext(iface);
04077 
04078     FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
04079     return E_NOTIMPL;
04080 }
04081 
04082 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
04083 {
04084     Context *This = impl_from_IObjContext(iface);
04085 
04086     FIXME("(%p/%p)->(%p)\n", This, iface, props);
04087     return E_NOTIMPL;
04088 }
04089 
04090 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
04091 {
04092     Context *This = impl_from_IObjContext(iface);
04093     FIXME("(%p/%p)\n", This, iface);
04094 }
04095 
04096 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
04097 {
04098     Context *This = impl_from_IObjContext(iface);
04099     FIXME("(%p/%p)\n", This, iface);
04100 }
04101 
04102 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
04103 {
04104     Context *This = impl_from_IObjContext(iface);
04105     FIXME("(%p/%p)\n", This, iface);
04106 }
04107 
04108 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
04109 {
04110     Context *This = impl_from_IObjContext(iface);
04111     FIXME("(%p/%p)\n", This, iface);
04112 }
04113 
04114 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
04115 {
04116     Context *This = impl_from_IObjContext(iface);
04117     FIXME("(%p/%p)\n", This, iface);
04118 }
04119 
04120 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
04121 {
04122     Context *This = impl_from_IObjContext(iface);
04123     FIXME("(%p/%p)\n", This, iface);
04124 }
04125 
04126 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
04127 {
04128     Context *This = impl_from_IObjContext(iface);
04129     FIXME("(%p/%p)\n", This, iface);
04130 }
04131 
04132 static const IObjContextVtbl Context_Object_Vtbl =
04133 {
04134     Context_OC_QueryInterface,
04135     Context_OC_AddRef,
04136     Context_OC_Release,
04137     Context_OC_SetProperty,
04138     Context_OC_RemoveProperty,
04139     Context_OC_GetProperty,
04140     Context_OC_EnumContextProps,
04141     Context_OC_Reserved1,
04142     Context_OC_Reserved2,
04143     Context_OC_Reserved3,
04144     Context_OC_Reserved4,
04145     Context_OC_Reserved5,
04146     Context_OC_Reserved6,
04147     Context_OC_Reserved7
04148 };
04149 
04150 /***********************************************************************
04151  *           CoGetObjectContext [OLE32.@]
04152  *
04153  * Retrieves an object associated with the current context (i.e. apartment).
04154  *
04155  * PARAMS
04156  *  riid [I] ID of the interface of the object to retrieve.
04157  *  ppv  [O] Address where object will be stored on return.
04158  *
04159  * RETURNS
04160  *  Success: S_OK.
04161  *  Failure: HRESULT code.
04162  */
04163 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
04164 {
04165     APARTMENT *apt = COM_CurrentApt();
04166     Context *context;
04167     HRESULT hr;
04168 
04169     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
04170 
04171     *ppv = NULL;
04172     if (!apt)
04173     {
04174         if (!(apt = apartment_find_multi_threaded()))
04175         {
04176             ERR("apartment not initialised\n");
04177             return CO_E_NOTINITIALIZED;
04178         }
04179         apartment_release(apt);
04180     }
04181 
04182     context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
04183     if (!context)
04184         return E_OUTOFMEMORY;
04185 
04186     context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
04187     context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
04188     context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
04189     context->refs = 1;
04190     if (apt->multi_threaded)
04191         context->apttype = APTTYPE_MTA;
04192     else if (apt->main)
04193         context->apttype = APTTYPE_MAINSTA;
04194     else
04195         context->apttype = APTTYPE_STA;
04196 
04197     hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
04198     IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
04199 
04200     return hr;
04201 }
04202 
04203 
04204 /***********************************************************************
04205  *           CoGetContextToken [OLE32.@]
04206  */
04207 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
04208 {
04209     struct oletls *info = COM_CurrentInfo();
04210 
04211     TRACE("(%p)\n", token);
04212 
04213     if (!info)
04214         return E_OUTOFMEMORY;
04215 
04216     if (!info->apt)
04217     {
04218         APARTMENT *apt;
04219         if (!(apt = apartment_find_multi_threaded()))
04220         {
04221             ERR("apartment not initialised\n");
04222             return CO_E_NOTINITIALIZED;
04223         }
04224         apartment_release(apt);
04225     }
04226 
04227     if (!token)
04228         return E_POINTER;
04229 
04230     if (!info->context_token)
04231     {
04232         HRESULT hr;
04233         IObjContext *ctx;
04234 
04235         hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
04236         if (FAILED(hr)) return hr;
04237         info->context_token = ctx;
04238     }
04239 
04240     *token = (ULONG_PTR)info->context_token;
04241     TRACE("apt->context_token=%p\n", info->context_token);
04242 
04243     return S_OK;
04244 }
04245 
04246 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
04247 {
04248     static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
04249     HKEY hkey;
04250     HRESULT hres;
04251 
04252     hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
04253     if (SUCCEEDED(hres))
04254     {
04255         WCHAR dllpath[MAX_PATH+1];
04256 
04257         if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
04258         {
04259             static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
04260             if (!strcmpiW(dllpath, wszOle32))
04261             {
04262                 RegCloseKey(hkey);
04263                 return HandlerCF_Create(rclsid, riid, ppv);
04264             }
04265         }
04266         else
04267             WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
04268         RegCloseKey(hkey);
04269     }
04270 
04271     return CLASS_E_CLASSNOTAVAILABLE;
04272 }
04273 
04274 /***********************************************************************
04275  *      DllMain (OLE32.@)
04276  */
04277 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
04278 {
04279     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
04280 
04281     switch(fdwReason) {
04282     case DLL_PROCESS_ATTACH:
04283         hProxyDll = hinstDLL;
04284         COMPOBJ_InitProcess();
04285     break;
04286 
04287     case DLL_PROCESS_DETACH:
04288         COMPOBJ_UninitProcess();
04289         RPC_UnregisterAllChannelHooks();
04290         COMPOBJ_DllList_Free();
04291         DeleteCriticalSection(&csRegisteredClassList);
04292         DeleteCriticalSection(&csApartment);
04293     break;
04294 
04295     case DLL_THREAD_DETACH:
04296         COM_TlsDestroy();
04297         break;
04298     }
04299     return TRUE;
04300 }
04301 
04302 /***********************************************************************
04303  *      DllRegisterServer (OLE32.@)
04304  */
04305 HRESULT WINAPI DllRegisterServer(void)
04306 {
04307     return OLE32_DllRegisterServer();
04308 }
04309 
04310 /***********************************************************************
04311  *      DllUnregisterServer (OLE32.@)
04312  */
04313 HRESULT WINAPI DllUnregisterServer(void)
04314 {
04315     return OLE32_DllUnregisterServer();
04316 }

Generated on Sat May 26 2012 04:24:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.