4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
27 * Therefore do not test against COINIT_MULTITHREADED
29 * TODO list: (items bunched together depend on each other)
31 * - Once that's done, replace wine_marshal_id with STDOBJREF
33 * - Rewrite the CoLockObjectExternal code, it does totally the wrong
34 * thing currently (should be controlling the stub manager)
36 * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
38 * - Implement the service control manager (in rpcss) to keep track
39 * of registered class objects: ISCM::ServerRegisterClsid et al
40 * - Implement the OXID resolver so we don't need magic pipe names for
41 * clients and servers to meet up
42 * - Flip our marshalling on top of the RPC runtime transport API,
43 * so we no longer use named pipes to communicate
44 * - Rework threading so re-entrant calls don't need to be sent on
46 * - Implement RPC thread affinity (should fix InstallShield painting
49 * - Implement IRemUnknown and marshalling for it, then use that for
50 * reffing/unreffing the stub manager from a proxy instead of our
51 * current hack of simply reffing the stub manager once when it's
53 * - Implement table marshalling, then use it to let us do the final
54 * rework of the threading
56 * - Make our custom marshalling use NDR to be wire compatible with
71 #define NONAMELESSUNION
72 #define NONAMELESSSTRUCT
84 #include "wine/unicode.h"
86 #include "ole32_main.h"
87 #include "compobj_private.h"
89 #include "wine/debug.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(ole);
93 typedef LPCSTR LPCOLESTR16;
95 /****************************************************************************
96 * This section defines variables internal to the COM module.
98 * TODO: Most of these things will have to be made thread-safe.
101 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
102 static void COM_RevokeAllClasses(void);
103 static void COM_ExternalLockFreeList(void);
105 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
107 APARTMENT *MTA; /* protected by csApartment */
108 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
110 static CRITICAL_SECTION csApartment;
111 static CRITICAL_SECTION_DEBUG critsect_debug =
114 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
115 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
117 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
120 * This lock count counts the number of times CoInitialize is called. It is
121 * decreased every time CoUninitialize is called. When it hits 0, the COM
122 * libraries are freed
124 static LONG s_COMLockCount = 0;
127 * This linked list contains the list of registered class objects. These
128 * are mostly used to register the factories for out-of-proc servers of OLE
131 * TODO: Make this data structure aware of inter-process communication. This
132 * means that parts of this will be exported to the Wine Server.
134 typedef struct tagRegisteredClass
136 CLSID classIdentifier;
137 LPUNKNOWN classObject;
141 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
142 struct tagRegisteredClass* nextClass;
145 static RegisteredClass* firstRegisteredClass = NULL;
147 static CRITICAL_SECTION csRegisteredClassList;
148 static CRITICAL_SECTION_DEBUG class_cs_debug =
150 0, 0, &csRegisteredClassList,
151 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
152 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
154 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
156 /*****************************************************************************
157 * This section contains OpenDllList definitions
159 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
160 * other functions that do LoadLibrary _without_ giving back a HMODULE.
161 * Without this list these handles would never be freed.
163 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
164 * next unload-call but not before 600 sec.
167 typedef struct tagOpenDll {
169 struct tagOpenDll *next;
172 static OpenDll *openDllList = NULL; /* linked list of open dlls */
174 static CRITICAL_SECTION csOpenDllList;
175 static CRITICAL_SECTION_DEBUG dll_cs_debug =
177 0, 0, &csOpenDllList,
178 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
179 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
181 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
183 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
184 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
187 static void COMPOBJ_DllList_FreeUnused(int Timeout);
189 void COMPOBJ_InitProcess( void )
193 /* Dispatching to the correct thread in an apartment is done through
194 * window messages rather than RPC transports. When an interface is
195 * marshalled into another apartment in the same process, a window of the
196 * following class is created. The *caller* of CoMarshalInterface (ie the
197 * application) is responsible for pumping the message loop in that thread.
198 * The WM_USER messages which point to the RPCs are then dispatched to
199 * COM_AptWndProc by the user's code from the apartment in which the interface
202 memset(&wclass, 0, sizeof(wclass));
203 wclass.lpfnWndProc = &COM_AptWndProc;
204 wclass.hInstance = OLE32_hInstance;
205 wclass.lpszClassName = aptWinClass;
206 RegisterClassA(&wclass);
209 void COMPOBJ_UninitProcess( void )
211 UnregisterClassA(aptWinClass, OLE32_hInstance);
214 /******************************************************************************
218 /* creates an apartment structure which stores OLE apartment-local
220 APARTMENT* COM_CreateApartment(DWORD model)
222 APARTMENT *apt = COM_CurrentApt();
226 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
227 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
230 EnterCriticalSection(&csApartment);
231 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
233 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
235 COM_ApartmentAddRef(apt);
237 LeaveCriticalSection(&csApartment);
239 COM_CurrentInfo()->apt = apt;
243 TRACE("creating new apartment, model=%ld\n", model);
245 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
246 apt->tid = GetCurrentThreadId();
247 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
248 GetCurrentProcess(), &apt->thread,
249 THREAD_ALL_ACCESS, FALSE, 0);
251 list_init(&apt->proxies);
252 list_init(&apt->stubmgrs);
255 InitializeCriticalSection(&apt->cs);
259 if (model & COINIT_APARTMENTTHREADED)
261 /* FIXME: should be randomly generated by in an RPC call to rpcss */
262 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
263 apt->win = CreateWindowA(aptWinClass, NULL, 0,
265 0, 0, OLE32_hInstance, NULL);
269 /* FIXME: should be randomly generated by in an RPC call to rpcss */
270 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
277 LeaveCriticalSection(&csApartment);
279 COM_CurrentInfo()->apt = apt;
285 DWORD COM_ApartmentAddRef(struct apartment *apt)
287 return InterlockedIncrement(&apt->refs);
290 DWORD COM_ApartmentRelease(struct apartment *apt)
294 EnterCriticalSection(&csApartment);
296 ret = InterlockedDecrement(&apt->refs);
297 /* destruction stuff that needs to happen under csApartment CS */
300 if (apt == MTA) MTA = NULL;
301 list_remove(&apt->entry);
304 LeaveCriticalSection(&csApartment);
308 struct list *cursor, *cursor2;
310 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
312 MARSHAL_Disconnect_Proxies(apt);
314 if (apt->win) DestroyWindow(apt->win);
316 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
318 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
319 /* release the implicit reference given by the fact that the
320 * stub has external references (it must do since it is in the
321 * stub manager list in the apartment and all non-apartment users
322 * must have a ref on the apartment and so it cannot be destroyed).
324 stub_manager_int_release(stubmgr);
327 /* if this assert fires, then another thread took a reference to a
328 * stub manager without taking a reference to the containing
329 * apartment, which it must do. */
330 assert(list_empty(&apt->stubmgrs));
332 if (apt->filter) IUnknown_Release(apt->filter);
334 DeleteCriticalSection(&apt->cs);
335 CloseHandle(apt->thread);
336 HeapFree(GetProcessHeap(), 0, apt);
342 /* The given OXID must be local to this process: you cannot use
343 * apartment windows to send RPCs to other processes. This all needs
346 * The ref parameter is here mostly to ensure people remember that
347 * they get one, you should normally take a ref for thread safety.
349 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
351 APARTMENT *result = NULL;
354 EnterCriticalSection(&csApartment);
355 LIST_FOR_EACH( cursor, &apts )
357 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
358 if (apt->oxid == oxid)
361 if (ref) COM_ApartmentAddRef(result);
365 LeaveCriticalSection(&csApartment);
370 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
374 apt = COM_ApartmentFromOXID(oxid, ref);
375 if (!apt) return NULL;
380 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
381 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
383 return DefWindowProcA(hWnd, msg, wParam, lParam);
386 /*****************************************************************************
387 * This section contains OpenDllList implemantation
390 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
397 EnterCriticalSection( &csOpenDllList );
399 if (openDllList == NULL) {
400 /* empty list -- add first node */
401 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
402 openDllList->hLibrary=hLibrary;
403 openDllList->next = NULL;
405 /* search for this dll */
407 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
408 if (ptr->hLibrary == hLibrary) {
414 /* dll not found, add it */
416 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
417 openDllList->hLibrary = hLibrary;
418 openDllList->next = tmp;
422 LeaveCriticalSection( &csOpenDllList );
425 static void COMPOBJ_DllList_FreeUnused(int Timeout)
427 OpenDll *curr, *next, *prev = NULL;
428 typedef HRESULT(*DllCanUnloadNowFunc)(void);
429 DllCanUnloadNowFunc DllCanUnloadNow;
433 EnterCriticalSection( &csOpenDllList );
435 for (curr = openDllList; curr != NULL; ) {
436 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
438 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
441 TRACE("freeing %p\n", curr->hLibrary);
442 FreeLibrary(curr->hLibrary);
444 HeapFree(GetProcessHeap(), 0, curr);
445 if (curr == openDllList) {
458 LeaveCriticalSection( &csOpenDllList );
461 /******************************************************************************
462 * CoBuildVersion [OLE32.@]
463 * CoBuildVersion [COMPOBJ.1]
465 * Gets the build version of the DLL.
470 * Current build version, hiword is majornumber, loword is minornumber
472 DWORD WINAPI CoBuildVersion(void)
474 TRACE("Returning version %d, build %d.\n", rmm, rup);
475 return (rmm<<16)+rup;
478 /******************************************************************************
479 * CoInitialize [OLE32.@]
481 * Initializes the COM libraries by calling CoInitializeEx with
482 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
485 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
488 * Success: S_OK if not already initialized, S_FALSE otherwise.
489 * Failure: HRESULT code.
494 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
497 * Just delegate to the newer method.
499 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
502 /******************************************************************************
503 * CoInitializeEx [OLE32.@]
505 * Initializes the COM libraries.
508 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
509 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
512 * S_OK if successful,
513 * S_FALSE if this function was called already.
514 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
519 * The behavior used to set the IMalloc used for memory management is
521 * The dwCoInit parameter must specify of of the following apartment
523 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
524 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
525 * The parameter may also specify zero or more of the following flags:
526 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
527 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
532 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
537 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
539 if (lpReserved!=NULL)
541 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
545 * Check the lock count. If this is the first time going through the initialize
546 * process, we have to initialize the libraries.
548 * And crank-up that lock count.
550 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
553 * Initialize the various COM libraries and data structures.
555 TRACE("() - Initializing the COM libraries\n");
557 /* we may need to defer this until after apartment initialisation */
558 RunningObjectTableImpl_Initialize();
561 if (!(apt = COM_CurrentInfo()->apt))
563 apt = COM_CreateApartment(dwCoInit);
564 if (!apt) return E_OUTOFMEMORY;
566 else if (dwCoInit != apt->model)
568 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
569 code then we are probably using the wrong threading model to implement that API. */
570 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
571 COM_ApartmentRelease(apt);
572 return RPC_E_CHANGED_MODE;
577 COM_CurrentInfo()->inits++;
582 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
583 pending RPCs are ignored. Non-COM messages are discarded at this point.
585 void COM_FlushMessageQueue(void)
588 APARTMENT *apt = COM_CurrentApt();
590 if (!apt || !apt->win) return;
592 TRACE("Flushing STA message queue\n");
594 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
596 if (message.hwnd != apt->win)
598 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
602 TranslateMessage(&message);
603 DispatchMessageA(&message);
607 /***********************************************************************
608 * CoUninitialize [OLE32.@]
610 * This method will decrement the refcount on the current apartment, freeing
611 * the resources associated with it if it is the last thread in the apartment.
612 * If the last apartment is freed, the function will additionally release
613 * any COM resources associated with the process.
623 void WINAPI CoUninitialize(void)
625 struct oletls * info = COM_CurrentInfo();
630 /* will only happen on OOM */
636 ERR("Mismatched CoUninitialize\n");
642 COM_ApartmentRelease(info->apt);
647 * Decrease the reference count.
648 * If we are back to 0 locks on the COM library, make sure we free
649 * all the associated data structures.
651 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
654 TRACE("() - Releasing the COM libraries\n");
656 RunningObjectTableImpl_UnInitialize();
658 /* Release the references to the registered class objects */
659 COM_RevokeAllClasses();
661 /* This will free the loaded COM Dlls */
662 CoFreeAllLibraries();
664 /* This will free list of external references to COM objects */
665 COM_ExternalLockFreeList();
667 /* This ensures we deal with any pending RPCs */
668 COM_FlushMessageQueue();
670 else if (lCOMRefCnt<1) {
671 ERR( "CoUninitialize() - not CoInitialized.\n" );
672 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
676 /******************************************************************************
677 * CoDisconnectObject [OLE32.@]
678 * CoDisconnectObject [COMPOBJ.15]
680 * Disconnects all connections to this object from remote processes. Dispatches
681 * pending RPCs while blocking new RPCs from occurring, and then calls
682 * IMarshal::DisconnectObject on the given object.
684 * Typically called when the object server is forced to shut down, for instance by
688 * lpUnk [I] The object whose stub should be disconnected.
689 * reserved [I] Reserved. Should be set to 0.
693 * Failure: HRESULT code.
696 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
698 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
700 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
704 /******************************************************************************
705 * CoCreateGuid [OLE32.@]
707 * Simply forwards to UuidCreate in RPCRT4.
710 * pguid [O] Points to the GUID to initialize.
714 * Failure: HRESULT code.
719 HRESULT WINAPI CoCreateGuid(GUID *pguid)
721 return UuidCreate(pguid);
724 /******************************************************************************
725 * CLSIDFromString [OLE32.@]
726 * IIDFromString [OLE32.@]
728 * Converts a unique identifier from its string representation into
732 * idstr [I] The string representation of the GUID.
733 * id [O] GUID converted from the string.
737 * CO_E_CLASSSTRING if idstr is not a valid CLSID
741 * In Windows, if idstr is not a valid CLSID string then it gets
742 * treated as a ProgID. Wine currently doesn't do this. If idstr is
743 * NULL it's treated as an all-zero GUID.
748 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
750 const BYTE *s = (const BYTE *) idstr;
755 s = "{00000000-0000-0000-0000-000000000000}";
756 else { /* validate the CLSID string */
759 return CO_E_CLASSSTRING;
761 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
762 return CO_E_CLASSSTRING;
764 for (i=1; i<37; i++) {
765 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
766 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
767 ((s[i] >= 'a') && (s[i] <= 'f')) ||
768 ((s[i] >= 'A') && (s[i] <= 'F'))))
769 return CO_E_CLASSSTRING;
773 TRACE("%s -> %p\n", s, id);
775 /* quick lookup table */
776 memset(table, 0, 256);
778 for (i = 0; i < 10; i++) {
781 for (i = 0; i < 6; i++) {
782 table['A' + i] = i+10;
783 table['a' + i] = i+10;
786 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
788 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
789 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
790 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
791 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
793 /* these are just sequential bytes */
794 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
795 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
796 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
797 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
798 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
799 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
800 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
801 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
806 /*****************************************************************************/
808 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
813 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
814 return CO_E_CLASSSTRING;
817 ret = __CLSIDFromStringA(xid,id);
818 if(ret != S_OK) { /* It appears a ProgID is also valid */
819 ret = CLSIDFromProgID(idstr, id);
824 /* Converts a GUID into the respective string representation. */
825 HRESULT WINE_StringFromCLSID(
826 const CLSID *id, /* [in] GUID to be converted */
827 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
829 static const char *hex = "0123456789ABCDEF";
834 { ERR("called with id=Null\n");
839 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
840 id->Data1, id->Data2, id->Data3,
841 id->Data4[0], id->Data4[1]);
845 for (i = 2; i < 8; i++) {
846 *s++ = hex[id->Data4[i]>>4];
847 *s++ = hex[id->Data4[i] & 0xf];
853 TRACE("%p->%s\n", id, idstr);
859 /******************************************************************************
860 * StringFromCLSID [OLE32.@]
861 * StringFromIID [OLE32.@]
863 * Converts a GUID into the respective string representation.
864 * The target string is allocated using the OLE IMalloc.
867 * id [I] the GUID to be converted.
868 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
875 * StringFromGUID2, CLSIDFromString
877 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
883 if ((ret = CoGetMalloc(0,&mllc)))
886 ret=WINE_StringFromCLSID(id,buf);
888 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
889 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
890 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
895 /******************************************************************************
896 * StringFromGUID2 [OLE32.@]
897 * StringFromGUID2 [COMPOBJ.76]
899 * Modified version of StringFromCLSID that allows you to specify max
903 * id [I] GUID to convert to string.
904 * str [O] Buffer where the result will be stored.
905 * cmax [I] Size of the buffer in characters.
908 * Success: The length of the resulting string in characters.
911 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
915 if (WINE_StringFromCLSID(id,xguid))
917 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
920 /******************************************************************************
921 * ProgIDFromCLSID [OLE32.@]
923 * Converts a class id into the respective program ID.
926 * clsid [I] Class ID, as found in registry.
927 * lplpszProgID [O] Associated ProgID.
932 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
934 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
936 char strCLSID[50], *buf, *buf2;
942 WINE_StringFromCLSID(clsid, strCLSID);
944 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
945 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
946 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
947 ret = REGDB_E_CLASSNOTREG;
949 HeapFree(GetProcessHeap(), 0, buf);
953 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
955 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
956 ret = REGDB_E_CLASSNOTREG;
960 if (CoGetMalloc(0,&mllc))
964 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
965 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
966 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
969 HeapFree(GetProcessHeap(), 0, buf2);
976 HRESULT WINAPI CLSIDFromProgID16(
977 LPCOLESTR16 progid, /* [in] program id as found in registry */
978 LPCLSID riid /* [out] associated CLSID */
985 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
986 sprintf(buf,"%s\\CLSID",progid);
987 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
988 HeapFree(GetProcessHeap(),0,buf);
989 return CO_E_CLASSSTRING;
991 HeapFree(GetProcessHeap(),0,buf);
992 buf2len = sizeof(buf2);
993 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
995 return CO_E_CLASSSTRING;
998 return __CLSIDFromStringA(buf2,riid);
1001 /******************************************************************************
1002 * CLSIDFromProgID [OLE32.@]
1003 * CLSIDFromProgID [COMPOBJ.61]
1005 * Converts a program id into the respective GUID.
1008 * progid [I] Unicode program ID, as found in registry.
1009 * riid [O] Associated CLSID.
1013 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1015 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1017 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1019 DWORD buf2len = sizeof(buf2);
1022 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1023 strcpyW( buf, progid );
1024 strcatW( buf, clsidW );
1025 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1027 HeapFree(GetProcessHeap(),0,buf);
1028 return CO_E_CLASSSTRING;
1030 HeapFree(GetProcessHeap(),0,buf);
1032 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1035 return CO_E_CLASSSTRING;
1038 return __CLSIDFromStringA(buf2,riid);
1043 /*****************************************************************************
1044 * CoGetPSClsid [OLE32.@]
1046 * This function returns the CLSID of the proxy/stub factory that
1047 * implements IPSFactoryBuffer for the specified interface.
1050 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1051 * pclsid [O] Where to store returned proxy/stub CLSID.
1056 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1060 * The standard marshaller activates the object with the CLSID
1061 * returned and uses the CreateProxy and CreateStub methods on its
1062 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1065 * CoGetPSClsid determines this CLSID by searching the
1066 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1067 * in the registry and any interface id registered by
1068 * CoRegisterPSClsid within the current process.
1072 * We only search the registry, not ids registered with
1073 * CoRegisterPSClsid.
1075 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1077 char *buf, buf2[40];
1081 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1083 /* Get the input iid as a string */
1084 WINE_StringFromCLSID(riid, buf2);
1085 /* Allocate memory for the registry key we will construct.
1086 (length of iid string plus constant length of static text */
1087 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1090 return (E_OUTOFMEMORY);
1093 /* Construct the registry key we want */
1094 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1096 /* Open the key.. */
1097 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1099 WARN("No PSFactoryBuffer object is registered for this IID\n");
1100 HeapFree(GetProcessHeap(),0,buf);
1101 return (E_INVALIDARG);
1103 HeapFree(GetProcessHeap(),0,buf);
1105 /* ... Once we have the key, query the registry to get the
1106 value of CLSID as a string, and convert it into a
1107 proper CLSID structure to be passed back to the app */
1108 buf2len = sizeof(buf2);
1109 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1112 return E_INVALIDARG;
1116 /* We have the CLSid we want back from the registry as a string, so
1117 lets convert it into a CLSID structure */
1118 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1119 return E_INVALIDARG;
1122 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1128 /***********************************************************************
1129 * WriteClassStm (OLE32.@)
1131 * Writes a CLSID to a stream.
1134 * pStm [I] Stream to write to.
1135 * rclsid [I] CLSID to write.
1139 * Failure: HRESULT code.
1141 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1143 TRACE("(%p,%p)\n",pStm,rclsid);
1146 return E_INVALIDARG;
1148 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1151 /***********************************************************************
1152 * ReadClassStm (OLE32.@)
1154 * Reads a CLSID from a stream.
1157 * pStm [I] Stream to read from.
1158 * rclsid [O] CLSID to read.
1162 * Failure: HRESULT code.
1164 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1169 TRACE("(%p,%p)\n",pStm,pclsid);
1172 return E_INVALIDARG;
1174 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1179 if (nbByte != sizeof(CLSID))
1187 * COM_GetRegisteredClassObject
1189 * This internal method is used to scan the registered class list to
1190 * find a class object.
1193 * rclsid Class ID of the class to find.
1194 * dwClsContext Class context to match.
1195 * ppv [out] returns a pointer to the class object. Complying
1196 * to normal COM usage, this method will increase the
1197 * reference count on this object.
1199 static HRESULT COM_GetRegisteredClassObject(
1204 HRESULT hr = S_FALSE;
1205 RegisteredClass* curClass;
1207 EnterCriticalSection( &csRegisteredClassList );
1215 * Iterate through the whole list and try to match the class ID.
1217 curClass = firstRegisteredClass;
1219 while (curClass != 0)
1222 * Check if we have a match on the class ID.
1224 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1227 * Since we don't do out-of process or DCOM just right away, let's ignore the
1232 * We have a match, return the pointer to the class object.
1234 *ppUnk = curClass->classObject;
1236 IUnknown_AddRef(curClass->classObject);
1243 * Step to the next class in the list.
1245 curClass = curClass->nextClass;
1249 LeaveCriticalSection( &csRegisteredClassList );
1251 * If we get to here, we haven't found our class.
1256 /******************************************************************************
1257 * CoRegisterClassObject [OLE32.@]
1259 * Registers the class object for a given class ID. Servers housed in EXE
1260 * files use this method instead of exporting DllGetClassObject to allow
1261 * other code to connect to their objects.
1264 * rclsid [I] CLSID of the object to register.
1265 * pUnk [I] IUnknown of the object.
1266 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1267 * flags [I] REGCLS flags indicating how connections are made.
1268 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1272 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1273 * CO_E_OBJISREG if the object is already registered. We should not return this.
1276 * CoRevokeClassObject, CoGetClassObject
1279 * MSDN claims that multiple interface registrations are legal, but we
1280 * can't do that with our current implementation.
1282 HRESULT WINAPI CoRegisterClassObject(
1287 LPDWORD lpdwRegister)
1289 RegisteredClass* newClass;
1290 LPUNKNOWN foundObject;
1293 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1294 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1296 if ( (lpdwRegister==0) || (pUnk==0) )
1297 return E_INVALIDARG;
1299 if (!COM_CurrentApt())
1301 ERR("COM was not initialized\n");
1302 return CO_E_NOTINITIALIZED;
1308 * First, check if the class is already registered.
1309 * If it is, this should cause an error.
1311 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1313 IUnknown_Release(foundObject);
1314 return CO_E_OBJISREG;
1317 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1318 if ( newClass == NULL )
1319 return E_OUTOFMEMORY;
1321 EnterCriticalSection( &csRegisteredClassList );
1323 newClass->classIdentifier = *rclsid;
1324 newClass->runContext = dwClsContext;
1325 newClass->connectFlags = flags;
1327 * Use the address of the chain node as the cookie since we are sure it's
1328 * unique. FIXME: not on 64-bit platforms.
1330 newClass->dwCookie = (DWORD)newClass;
1331 newClass->nextClass = firstRegisteredClass;
1334 * Since we're making a copy of the object pointer, we have to increase its
1337 newClass->classObject = pUnk;
1338 IUnknown_AddRef(newClass->classObject);
1340 firstRegisteredClass = newClass;
1341 LeaveCriticalSection( &csRegisteredClassList );
1343 *lpdwRegister = newClass->dwCookie;
1345 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1346 IClassFactory *classfac;
1348 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1349 (LPVOID*)&classfac);
1352 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1354 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1355 IUnknown_Release(classfac);
1358 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1359 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1360 MSHLFLAGS_TABLESTRONG);
1362 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1363 IUnknown_Release(classfac);
1367 IUnknown_Release(classfac);
1369 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1374 /***********************************************************************
1375 * CoRevokeClassObject [OLE32.@]
1377 * Removes a class object from the class registry.
1380 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1384 * Failure: HRESULT code.
1387 * CoRegisterClassObject
1389 HRESULT WINAPI CoRevokeClassObject(
1392 HRESULT hr = E_INVALIDARG;
1393 RegisteredClass** prevClassLink;
1394 RegisteredClass* curClass;
1396 TRACE("(%08lx)\n",dwRegister);
1398 EnterCriticalSection( &csRegisteredClassList );
1401 * Iterate through the whole list and try to match the cookie.
1403 curClass = firstRegisteredClass;
1404 prevClassLink = &firstRegisteredClass;
1406 while (curClass != 0)
1409 * Check if we have a match on the cookie.
1411 if (curClass->dwCookie == dwRegister)
1414 * Remove the class from the chain.
1416 *prevClassLink = curClass->nextClass;
1419 * Release the reference to the class object.
1421 IUnknown_Release(curClass->classObject);
1423 if (curClass->pMarshaledData)
1426 memset(&zero, 0, sizeof(zero));
1427 /* FIXME: stop local server thread */
1428 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1429 CoReleaseMarshalData(curClass->pMarshaledData);
1433 * Free the memory used by the chain node.
1435 HeapFree(GetProcessHeap(), 0, curClass);
1442 * Step to the next class in the list.
1444 prevClassLink = &(curClass->nextClass);
1445 curClass = curClass->nextClass;
1449 LeaveCriticalSection( &csRegisteredClassList );
1451 * If we get to here, we haven't found our class.
1456 /***********************************************************************
1457 * compobj_RegReadPath [internal]
1459 * Reads a registry value and expands it when necessary
1461 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1467 DWORD dwLength = dstlen;
1469 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1470 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1471 if (keytype == REG_EXPAND_SZ) {
1472 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1474 lstrcpynA(dst, src, dstlen);
1482 /***********************************************************************
1483 * CoGetClassObject [COMPOBJ.7]
1484 * CoGetClassObject [OLE32.@]
1486 * FIXME. If request allows of several options and there is a failure
1487 * with one (other than not being registered) do we try the
1488 * others or return failure? (E.g. inprocess is registered but
1489 * the DLL is not found but the server version works)
1491 HRESULT WINAPI CoGetClassObject(
1492 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1493 REFIID iid, LPVOID *ppv
1495 LPUNKNOWN regClassObject;
1496 HRESULT hres = E_UNEXPECTED;
1499 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1500 DllGetClassObjectFunc DllGetClassObject;
1502 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1504 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1507 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1508 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1512 * First, try and see if we can't match the class ID with one of the
1513 * registered classes.
1515 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1518 * Get the required interface from the retrieved pointer.
1520 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1523 * Since QI got another reference on the pointer, we want to release the
1524 * one we already have. If QI was unsuccessful, this will release the object. This
1525 * is good since we are not returning it in the "out" parameter.
1527 IUnknown_Release(regClassObject);
1532 /* first try: in-process */
1533 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1534 char keyname[MAX_PATH];
1535 char dllpath[MAX_PATH+1];
1537 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1539 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1540 /* failure: CLSID is not found in registry */
1541 WARN("class %s not registered inproc\n", xclsid);
1542 hres = REGDB_E_CLASSNOTREG;
1544 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1545 /* failure: DLL could not be loaded */
1546 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1547 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1548 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1549 /* failure: the dll did not export DllGetClassObject */
1550 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1551 FreeLibrary( hLibrary );
1552 hres = CO_E_DLLNOTFOUND;
1554 /* OK: get the ClassObject */
1555 COMPOBJ_DLLList_Add( hLibrary );
1556 return DllGetClassObject(rclsid, iid, ppv);
1561 /* Next try out of process */
1562 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1564 return create_marshalled_proxy(rclsid,iid,ppv);
1567 /* Finally try remote: this requires networked DCOM (a lot of work) */
1568 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1570 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1571 hres = E_NOINTERFACE;
1576 /***********************************************************************
1577 * CoResumeClassObjects (OLE32.@)
1579 * Resumes all class objects registered with REGCLS_SUSPENDED.
1583 * Failure: HRESULT code.
1585 HRESULT WINAPI CoResumeClassObjects(void)
1591 /***********************************************************************
1592 * GetClassFile (OLE32.@)
1594 * This function supplies the CLSID associated with the given filename.
1596 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1600 int nbElm, length, i;
1602 LPOLESTR *pathDec=0,absFile=0,progId=0;
1604 static const WCHAR bkslashW[] = {'\\',0};
1605 static const WCHAR dotW[] = {'.',0};
1607 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1609 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1610 if((StgIsStorageFile(filePathName))==S_OK){
1612 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1615 res=ReadClassStg(pstg,pclsid);
1617 IStorage_Release(pstg);
1621 /* if the file is not a storage object then attemps to match various bits in the file against a
1622 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1625 for(i=0;i<nFileTypes;i++)
1627 for(i=0;j<nPatternsForType;j++){
1632 pat=ReadPatternFromRegistry(i,j);
1633 hFile=CreateFileW(filePathName,,,,,,hFile);
1634 SetFilePosition(hFile,pat.offset);
1635 ReadFile(hFile,buf,pat.size,&r,NULL);
1636 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1638 *pclsid=ReadCLSIDFromRegistry(i);
1644 /* if the above strategies fail then search for the extension key in the registry */
1646 /* get the last element (absolute file) in the path name */
1647 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1648 absFile=pathDec[nbElm-1];
1650 /* failed if the path represente a directory and not an absolute file name*/
1651 if (!lstrcmpW(absFile, bkslashW))
1652 return MK_E_INVALIDEXTENSION;
1654 /* get the extension of the file */
1656 length=lstrlenW(absFile);
1657 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1660 if (!extension || !lstrcmpW(extension, dotW))
1661 return MK_E_INVALIDEXTENSION;
1663 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1665 /* get the progId associated to the extension */
1666 progId = CoTaskMemAlloc(sizeProgId);
1667 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1669 if (res==ERROR_SUCCESS)
1670 /* return the clsid associated to the progId */
1671 res= CLSIDFromProgID(progId,pclsid);
1673 for(i=0; pathDec[i]!=NULL;i++)
1674 CoTaskMemFree(pathDec[i]);
1675 CoTaskMemFree(pathDec);
1677 CoTaskMemFree(progId);
1679 if (res==ERROR_SUCCESS)
1682 return MK_E_INVALIDEXTENSION;
1684 /***********************************************************************
1685 * CoCreateInstance [COMPOBJ.13]
1686 * CoCreateInstance [OLE32.@]
1688 HRESULT WINAPI CoCreateInstance(
1690 LPUNKNOWN pUnkOuter,
1696 LPCLASSFACTORY lpclf = 0;
1698 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1707 * Initialize the "out" parameter
1712 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1713 * Rather than create a class factory, we can just check for it here
1715 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1716 if (StdGlobalInterfaceTableInstance == NULL)
1717 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1718 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1719 if (hres) return hres;
1721 TRACE("Retrieved GIT (%p)\n", *ppv);
1726 * Get a class factory to construct the object we want.
1728 hres = CoGetClassObject(rclsid,
1735 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1736 debugstr_guid(rclsid),hres);
1741 * Create the object and don't forget to release the factory
1743 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1744 IClassFactory_Release(lpclf);
1746 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1747 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1752 /***********************************************************************
1753 * CoCreateInstanceEx [OLE32.@]
1755 HRESULT WINAPI CoCreateInstanceEx(
1757 LPUNKNOWN pUnkOuter,
1759 COSERVERINFO* pServerInfo,
1763 IUnknown* pUnk = NULL;
1766 ULONG successCount = 0;
1771 if ( (cmq==0) || (pResults==NULL))
1772 return E_INVALIDARG;
1774 if (pServerInfo!=NULL)
1775 FIXME("() non-NULL pServerInfo not supported!\n");
1778 * Initialize all the "out" parameters.
1780 for (index = 0; index < cmq; index++)
1782 pResults[index].pItf = NULL;
1783 pResults[index].hr = E_NOINTERFACE;
1787 * Get the object and get its IUnknown pointer.
1789 hr = CoCreateInstance(rclsid,
1799 * Then, query for all the interfaces requested.
1801 for (index = 0; index < cmq; index++)
1803 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1804 pResults[index].pIID,
1805 (VOID**)&(pResults[index].pItf));
1807 if (pResults[index].hr == S_OK)
1812 * Release our temporary unknown pointer.
1814 IUnknown_Release(pUnk);
1816 if (successCount == 0)
1817 return E_NOINTERFACE;
1819 if (successCount!=cmq)
1820 return CO_S_NOTALLINTERFACES;
1825 /***********************************************************************
1826 * CoLoadLibrary (OLE32.@)
1831 * lpszLibName [I] Path to library.
1832 * bAutoFree [I] Whether the library should automatically be freed.
1835 * Success: Handle to loaded library.
1839 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1841 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1843 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1845 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1848 /***********************************************************************
1849 * CoFreeLibrary [OLE32.@]
1851 * Unloads a library from memory.
1854 * hLibrary [I] Handle to library to unload.
1860 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1862 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1864 FreeLibrary(hLibrary);
1868 /***********************************************************************
1869 * CoFreeAllLibraries [OLE32.@]
1871 * Function for backwards compatibility only. Does nothing.
1877 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1879 void WINAPI CoFreeAllLibraries(void)
1885 /***********************************************************************
1886 * CoFreeUnusedLibraries [OLE32.@]
1887 * CoFreeUnusedLibraries [COMPOBJ.17]
1889 * Frees any unused libraries. Unused are identified as those that return
1890 * S_OK from their DllCanUnloadNow function.
1896 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1898 void WINAPI CoFreeUnusedLibraries(void)
1900 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1901 * through the main apartment's thread to call DllCanUnloadNow */
1902 COMPOBJ_DllList_FreeUnused(0);
1905 /***********************************************************************
1906 * CoFileTimeNow [OLE32.@]
1907 * CoFileTimeNow [COMPOBJ.82]
1909 * Retrieves the current time in FILETIME format.
1912 * lpFileTime [O] The current time.
1917 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1919 GetSystemTimeAsFileTime( lpFileTime );
1923 static void COM_RevokeAllClasses()
1925 EnterCriticalSection( &csRegisteredClassList );
1927 while (firstRegisteredClass!=0)
1929 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1932 LeaveCriticalSection( &csRegisteredClassList );
1935 /****************************************************************************
1936 * COM External Lock methods implementation
1938 * This api provides a linked list to managed external references to
1941 * The public interface consists of three calls:
1942 * COM_ExternalLockAddRef
1943 * COM_ExternalLockRelease
1944 * COM_ExternalLockFreeList
1947 #define EL_END_OF_LIST 0
1948 #define EL_NOT_FOUND 0
1951 * Declaration of the static structure that manage the
1952 * external lock to COM objects.
1954 typedef struct COM_ExternalLock COM_ExternalLock;
1955 typedef struct COM_ExternalLockList COM_ExternalLockList;
1957 struct COM_ExternalLock
1959 IUnknown *pUnk; /* IUnknown referenced */
1960 ULONG uRefCount; /* external lock counter to IUnknown object*/
1961 COM_ExternalLock *next; /* Pointer to next element in list */
1964 struct COM_ExternalLockList
1966 COM_ExternalLock *head; /* head of list */
1970 * Declaration and initialization of the static structure that manages
1971 * the external lock to COM objects.
1973 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1976 * Private methods used to managed the linked list
1980 static COM_ExternalLock* COM_ExternalLockLocate(
1981 COM_ExternalLock *element,
1984 /****************************************************************************
1985 * Internal - Insert a new IUnknown* to the linked list
1987 static BOOL COM_ExternalLockInsert(
1990 COM_ExternalLock *newLock = NULL;
1991 COM_ExternalLock *previousHead = NULL;
1994 * Allocate space for the new storage object
1996 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1998 if (newLock!=NULL) {
1999 if ( elList.head == EL_END_OF_LIST ) {
2000 elList.head = newLock; /* The list is empty */
2002 /* insert does it at the head */
2003 previousHead = elList.head;
2004 elList.head = newLock;
2007 /* Set new list item data member */
2008 newLock->pUnk = pUnk;
2009 newLock->uRefCount = 1;
2010 newLock->next = previousHead;
2017 /****************************************************************************
2018 * Internal - Method that removes an item from the linked list.
2020 static void COM_ExternalLockDelete(
2021 COM_ExternalLock *itemList)
2023 COM_ExternalLock *current = elList.head;
2025 if ( current == itemList ) {
2026 /* this section handles the deletion of the first node */
2027 elList.head = itemList->next;
2028 HeapFree( GetProcessHeap(), 0, itemList);
2031 if ( current->next == itemList ){ /* We found the item to free */
2032 current->next = itemList->next; /* readjust the list pointers */
2033 HeapFree( GetProcessHeap(), 0, itemList);
2037 /* Skip to the next item */
2038 current = current->next;
2040 } while ( current != EL_END_OF_LIST );
2044 /****************************************************************************
2045 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2047 * NOTES: how long can the list be ?? (recursive!!!)
2049 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2051 if ( element == EL_END_OF_LIST )
2052 return EL_NOT_FOUND;
2053 else if ( element->pUnk == pUnk ) /* We found it */
2055 else /* Not the right guy, keep on looking */
2056 return COM_ExternalLockLocate( element->next, pUnk);
2059 /****************************************************************************
2060 * Public - Method that increments the count for a IUnknown* in the linked
2061 * list. The item is inserted if not already in the list.
2063 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2065 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2068 * Add an external lock to the object. If it was already externally
2069 * locked, just increase the reference count. If it was not.
2070 * add the item to the list.
2072 if ( externalLock == EL_NOT_FOUND )
2073 COM_ExternalLockInsert(pUnk);
2075 externalLock->uRefCount++;
2078 * Add an internal lock to the object
2080 IUnknown_AddRef(pUnk);
2083 /****************************************************************************
2084 * Public - Method that decrements the count for a IUnknown* in the linked
2085 * list. The item is removed from the list if its count end up at zero or if
2088 static void COM_ExternalLockRelease(
2092 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2094 if ( externalLock != EL_NOT_FOUND ) {
2096 externalLock->uRefCount--; /* release external locks */
2097 IUnknown_Release(pUnk); /* release local locks as well */
2099 if ( bRelAll == FALSE ) break; /* perform single release */
2101 } while ( externalLock->uRefCount > 0 );
2103 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2104 COM_ExternalLockDelete(externalLock);
2107 /****************************************************************************
2108 * Public - Method that frees the content of the list.
2110 static void COM_ExternalLockFreeList()
2112 COM_ExternalLock *head;
2114 head = elList.head; /* grab it by the head */
2115 while ( head != EL_END_OF_LIST ) {
2116 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2117 head = elList.head; /* get the new head... */
2121 /****************************************************************************
2122 * Public - Method that dump the content of the list.
2124 void COM_ExternalLockDump()
2126 COM_ExternalLock *current = elList.head;
2128 DPRINTF("\nExternal lock list contains:\n");
2130 while ( current != EL_END_OF_LIST ) {
2131 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2133 /* Skip to the next item */
2134 current = current->next;
2138 /******************************************************************************
2139 * CoLockObjectExternal [OLE32.@]
2141 * Increments or decrements the external reference count of a stub object.
2144 * pUnk [I] Stub object.
2145 * fLock [I] If TRUE then increments the external ref-count,
2146 * otherwise decrements.
2147 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2148 * calling CoDisconnectObject.
2152 * Failure: HRESULT code.
2154 HRESULT WINAPI CoLockObjectExternal(
2155 LPUNKNOWN pUnk, /* */
2156 BOOL fLock, /* [in] do lock */
2157 BOOL fLastUnlockReleases) /* [in] unlock all */
2159 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2160 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2164 * Increment the external lock coutner, COM_ExternalLockAddRef also
2165 * increment the object's internal lock counter.
2167 COM_ExternalLockAddRef( pUnk);
2170 * Decrement the external lock coutner, COM_ExternalLockRelease also
2171 * decrement the object's internal lock counter.
2173 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2179 /***********************************************************************
2180 * CoInitializeWOW (OLE32.@)
2182 * WOW equivalent of CoInitialize?
2191 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2193 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2197 /***********************************************************************
2198 * CoGetState [OLE32.@]
2200 * Retrieves the thread state object previously stored by CoSetState().
2203 * ppv [I] Address where pointer to object will be stored.
2207 * Failure: E_OUTOFMEMORY.
2210 * Crashes on all invalid ppv addresses, including NULL.
2211 * If the function returns a non-NULL object then the caller must release its
2212 * reference on the object when the object is no longer required.
2217 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2219 struct oletls *info = COM_CurrentInfo();
2220 if (!info) return E_OUTOFMEMORY;
2226 IUnknown_AddRef(info->state);
2228 TRACE("apt->state=%p\n", info->state);
2234 /***********************************************************************
2235 * CoSetState [OLE32.@]
2237 * Sets the thread state object.
2240 * pv [I] Pointer to state object to be stored.
2243 * The system keeps a reference on the object while the object stored.
2247 * Failure: E_OUTOFMEMORY.
2249 HRESULT WINAPI CoSetState(IUnknown * pv)
2251 struct oletls *info = COM_CurrentInfo();
2252 if (!info) return E_OUTOFMEMORY;
2254 if (pv) IUnknown_AddRef(pv);
2258 TRACE("-- release %p now\n", info->state);
2259 IUnknown_Release(info->state);
2268 /******************************************************************************
2269 * OleGetAutoConvert [OLE32.@]
2271 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2279 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2280 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2282 res = REGDB_E_CLASSNOTREG;
2286 /* we can just query for the default value of AutoConvertTo key like that,
2287 without opening the AutoConvertTo key and querying for NULL (default) */
2288 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2290 res = REGDB_E_KEYMISSING;
2293 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2294 CLSIDFromString(wbuf,pClsidNew);
2296 if (hkey) RegCloseKey(hkey);
2300 /******************************************************************************
2301 * CoTreatAsClass [OLE32.@]
2303 * Sets the TreatAs value of a class.
2306 * clsidOld [I] Class to set TreatAs value on.
2307 * clsidNew [I] The class the clsidOld should be treated as.
2311 * Failure: HRESULT code.
2316 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2320 char szClsidNew[39];
2322 char auto_treat_as[39];
2323 LONG auto_treat_as_size = sizeof(auto_treat_as);
2326 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2327 WINE_StringFromCLSID(clsidNew, szClsidNew);
2328 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2330 res = REGDB_E_CLASSNOTREG;
2333 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2335 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2336 !__CLSIDFromStringA(auto_treat_as, &id))
2338 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2340 res = REGDB_E_WRITEREGDB;
2346 RegDeleteKeyA(hkey, "TreatAs");
2350 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2352 res = REGDB_E_WRITEREGDB;
2357 if (hkey) RegCloseKey(hkey);
2361 /******************************************************************************
2362 * CoGetTreatAsClass [OLE32.@]
2364 * Gets the TreatAs value of a class.
2367 * clsidOld [I] Class to get the TreatAs value of.
2368 * clsidNew [I] The class the clsidOld should be treated as.
2372 * Failure: HRESULT code.
2377 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2380 char buf[200], szClsidNew[200];
2382 LONG len = sizeof(szClsidNew);
2384 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2385 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2386 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2388 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2390 res = REGDB_E_CLASSNOTREG;
2393 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2398 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2400 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2402 if (hkey) RegCloseKey(hkey);
2407 /******************************************************************************
2408 * CoGetCurrentProcess [OLE32.@]
2409 * CoGetCurrentProcess [COMPOBJ.34]
2411 * Gets the current process ID.
2414 * The current process ID.
2417 * Is DWORD really the correct return type for this function?
2419 DWORD WINAPI CoGetCurrentProcess(void)
2421 return GetCurrentProcessId();
2424 /******************************************************************************
2425 * CoRegisterMessageFilter [OLE32.@]
2427 * Registers a message filter.
2430 * lpMessageFilter [I] Pointer to interface.
2431 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2435 * Failure: HRESULT code.
2437 HRESULT WINAPI CoRegisterMessageFilter(
2438 LPMESSAGEFILTER lpMessageFilter,
2439 LPMESSAGEFILTER *lplpMessageFilter)
2442 if (lplpMessageFilter) {
2443 *lplpMessageFilter = NULL;
2448 /***********************************************************************
2449 * CoIsOle1Class [OLE32.@]
2451 * Determines whether the specified class an OLE v1 class.
2454 * clsid [I] Class to test.
2457 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2459 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2461 FIXME("%s\n", debugstr_guid(clsid));
2465 /***********************************************************************
2466 * IsEqualGUID [OLE32.@]
2468 * Compares two Unique Identifiers.
2471 * rguid1 [I] The first GUID to compare.
2472 * rguid2 [I] The other GUID to compare.
2478 BOOL WINAPI IsEqualGUID(
2482 return !memcmp(rguid1,rguid2,sizeof(GUID));
2485 /***********************************************************************
2486 * CoInitializeSecurity [OLE32.@]
2488 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2489 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2490 void* pReserved1, DWORD dwAuthnLevel,
2491 DWORD dwImpLevel, void* pReserved2,
2492 DWORD dwCapabilities, void* pReserved3)
2494 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2495 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2496 dwCapabilities, pReserved3);
2500 /***********************************************************************
2501 * CoSuspendClassObjects [OLE32.@]
2503 * Suspends all registered class objects to prevent further requests coming in
2504 * for those objects.
2508 * Failure: HRESULT code.
2510 HRESULT WINAPI CoSuspendClassObjects(void)
2516 /***********************************************************************
2517 * CoAddRefServerProcess [OLE32.@]
2519 * Helper function for incrementing the reference count of a local-server
2523 * New reference count.
2525 ULONG WINAPI CoAddRefServerProcess(void)
2531 /***********************************************************************
2532 * CoReleaseServerProcess [OLE32.@]
2534 * Helper function for decrementing the reference count of a local-server
2538 * New reference count.
2540 ULONG WINAPI CoReleaseServerProcess(void)