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 * - Rewrite the CoLockObjectExternal code, it does totally the wrong
32 * thing currently (should be controlling the stub manager)
34 * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
36 * - Implement the service control manager (in rpcss) to keep track
37 * of registered class objects: ISCM::ServerRegisterClsid et al
38 * - Implement the OXID resolver so we don't need magic pipe names for
39 * clients and servers to meet up
40 * - Flip our marshalling on top of the RPC runtime transport API,
41 * so we no longer use named pipes to communicate
42 * - Rework threading so re-entrant calls don't need to be sent on
44 * - Implement RPC thread affinity (should fix InstallShield painting
47 * - Implement IRemUnknown and marshalling for it, then use that for
48 * reffing/unreffing the stub manager from a proxy instead of our
49 * current hack of simply reaching into local process memory to do it,
50 * which obviously doesn't work inter-process.
52 * - Make our custom marshalling use NDR to be wire compatible with
67 #define NONAMELESSUNION
68 #define NONAMELESSSTRUCT
80 #include "wine/unicode.h"
82 #include "ole32_main.h"
83 #include "compobj_private.h"
85 #include "wine/debug.h"
87 WINE_DEFAULT_DEBUG_CHANNEL(ole);
89 typedef LPCSTR LPCOLESTR16;
91 /****************************************************************************
92 * This section defines variables internal to the COM module.
94 * TODO: Most of these things will have to be made thread-safe.
97 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
98 static void COM_RevokeAllClasses(void);
99 static void COM_ExternalLockFreeList(void);
101 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
103 APARTMENT *MTA; /* protected by csApartment */
104 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
106 static CRITICAL_SECTION csApartment;
107 static CRITICAL_SECTION_DEBUG critsect_debug =
110 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
111 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
113 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
116 * This lock count counts the number of times CoInitialize is called. It is
117 * decreased every time CoUninitialize is called. When it hits 0, the COM
118 * libraries are freed
120 static LONG s_COMLockCount = 0;
123 * This linked list contains the list of registered class objects. These
124 * are mostly used to register the factories for out-of-proc servers of OLE
127 * TODO: Make this data structure aware of inter-process communication. This
128 * means that parts of this will be exported to the Wine Server.
130 typedef struct tagRegisteredClass
132 CLSID classIdentifier;
133 LPUNKNOWN classObject;
137 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
138 struct tagRegisteredClass* nextClass;
141 static RegisteredClass* firstRegisteredClass = NULL;
143 static CRITICAL_SECTION csRegisteredClassList;
144 static CRITICAL_SECTION_DEBUG class_cs_debug =
146 0, 0, &csRegisteredClassList,
147 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
148 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
150 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
152 /*****************************************************************************
153 * This section contains OpenDllList definitions
155 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
156 * other functions that do LoadLibrary _without_ giving back a HMODULE.
157 * Without this list these handles would never be freed.
159 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
160 * next unload-call but not before 600 sec.
163 typedef struct tagOpenDll {
165 struct tagOpenDll *next;
168 static OpenDll *openDllList = NULL; /* linked list of open dlls */
170 static CRITICAL_SECTION csOpenDllList;
171 static CRITICAL_SECTION_DEBUG dll_cs_debug =
173 0, 0, &csOpenDllList,
174 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
175 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
177 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
179 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
180 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
182 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
183 static void COMPOBJ_DllList_FreeUnused(int Timeout);
185 void COMPOBJ_InitProcess( void )
189 /* Dispatching to the correct thread in an apartment is done through
190 * window messages rather than RPC transports. When an interface is
191 * marshalled into another apartment in the same process, a window of the
192 * following class is created. The *caller* of CoMarshalInterface (ie the
193 * application) is responsible for pumping the message loop in that thread.
194 * The WM_USER messages which point to the RPCs are then dispatched to
195 * COM_AptWndProc by the user's code from the apartment in which the interface
198 memset(&wclass, 0, sizeof(wclass));
199 wclass.lpfnWndProc = &COM_AptWndProc;
200 wclass.hInstance = OLE32_hInstance;
201 wclass.lpszClassName = aptWinClass;
202 RegisterClassA(&wclass);
205 void COMPOBJ_UninitProcess( void )
207 UnregisterClassA(aptWinClass, OLE32_hInstance);
210 /******************************************************************************
214 /* creates an apartment structure which stores OLE apartment-local
216 APARTMENT* COM_CreateApartment(DWORD model)
218 APARTMENT *apt = COM_CurrentApt();
222 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
223 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
226 EnterCriticalSection(&csApartment);
227 if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
229 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
231 COM_ApartmentAddRef(apt);
233 LeaveCriticalSection(&csApartment);
235 COM_CurrentInfo()->apt = apt;
239 TRACE("creating new apartment, model=%ld\n", model);
241 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
242 apt->tid = GetCurrentThreadId();
243 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
244 GetCurrentProcess(), &apt->thread,
245 THREAD_ALL_ACCESS, FALSE, 0);
247 list_init(&apt->proxies);
248 list_init(&apt->stubmgrs);
251 InitializeCriticalSection(&apt->cs);
255 if (model & COINIT_APARTMENTTHREADED)
257 /* FIXME: should be randomly generated by in an RPC call to rpcss */
258 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
259 apt->win = CreateWindowA(aptWinClass, NULL, 0,
261 0, 0, OLE32_hInstance, NULL);
265 /* FIXME: should be randomly generated by in an RPC call to rpcss */
266 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
270 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
272 list_add_head(&apts, &apt->entry);
273 LeaveCriticalSection(&csApartment);
275 COM_CurrentInfo()->apt = apt;
281 DWORD COM_ApartmentAddRef(struct apartment *apt)
283 return InterlockedIncrement(&apt->refs);
286 DWORD COM_ApartmentRelease(struct apartment *apt)
290 EnterCriticalSection(&csApartment);
292 ret = InterlockedDecrement(&apt->refs);
293 /* destruction stuff that needs to happen under csApartment CS */
296 if (apt == MTA) MTA = NULL;
297 list_remove(&apt->entry);
300 LeaveCriticalSection(&csApartment);
304 struct list *cursor, *cursor2;
306 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
308 MARSHAL_Disconnect_Proxies(apt);
310 if (apt->win) DestroyWindow(apt->win);
312 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
314 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
315 /* release the implicit reference given by the fact that the
316 * stub has external references (it must do since it is in the
317 * stub manager list in the apartment and all non-apartment users
318 * must have a ref on the apartment and so it cannot be destroyed).
320 stub_manager_int_release(stubmgr);
323 /* if this assert fires, then another thread took a reference to a
324 * stub manager without taking a reference to the containing
325 * apartment, which it must do. */
326 assert(list_empty(&apt->stubmgrs));
328 if (apt->filter) IUnknown_Release(apt->filter);
330 DeleteCriticalSection(&apt->cs);
331 CloseHandle(apt->thread);
332 HeapFree(GetProcessHeap(), 0, apt);
338 /* The given OXID must be local to this process: you cannot use
339 * apartment windows to send RPCs to other processes. This all needs
342 * The ref parameter is here mostly to ensure people remember that
343 * they get one, you should normally take a ref for thread safety.
345 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
347 APARTMENT *result = NULL;
350 EnterCriticalSection(&csApartment);
351 LIST_FOR_EACH( cursor, &apts )
353 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
354 if (apt->oxid == oxid)
357 if (ref) COM_ApartmentAddRef(result);
361 LeaveCriticalSection(&csApartment);
366 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
370 apt = COM_ApartmentFromOXID(oxid, ref);
371 if (!apt) return NULL;
376 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
377 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
379 return DefWindowProcA(hWnd, msg, wParam, lParam);
382 /*****************************************************************************
383 * This section contains OpenDllList implemantation
386 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
393 EnterCriticalSection( &csOpenDllList );
395 if (openDllList == NULL) {
396 /* empty list -- add first node */
397 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
398 openDllList->hLibrary=hLibrary;
399 openDllList->next = NULL;
401 /* search for this dll */
403 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
404 if (ptr->hLibrary == hLibrary) {
410 /* dll not found, add it */
412 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
413 openDllList->hLibrary = hLibrary;
414 openDllList->next = tmp;
418 LeaveCriticalSection( &csOpenDllList );
421 static void COMPOBJ_DllList_FreeUnused(int Timeout)
423 OpenDll *curr, *next, *prev = NULL;
424 typedef HRESULT(*DllCanUnloadNowFunc)(void);
425 DllCanUnloadNowFunc DllCanUnloadNow;
429 EnterCriticalSection( &csOpenDllList );
431 for (curr = openDllList; curr != NULL; ) {
432 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
434 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
437 TRACE("freeing %p\n", curr->hLibrary);
438 FreeLibrary(curr->hLibrary);
440 HeapFree(GetProcessHeap(), 0, curr);
441 if (curr == openDllList) {
454 LeaveCriticalSection( &csOpenDllList );
457 /******************************************************************************
458 * CoBuildVersion [OLE32.@]
459 * CoBuildVersion [COMPOBJ.1]
461 * Gets the build version of the DLL.
466 * Current build version, hiword is majornumber, loword is minornumber
468 DWORD WINAPI CoBuildVersion(void)
470 TRACE("Returning version %d, build %d.\n", rmm, rup);
471 return (rmm<<16)+rup;
474 /******************************************************************************
475 * CoInitialize [OLE32.@]
477 * Initializes the COM libraries by calling CoInitializeEx with
478 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
481 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
484 * Success: S_OK if not already initialized, S_FALSE otherwise.
485 * Failure: HRESULT code.
490 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
493 * Just delegate to the newer method.
495 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
498 /******************************************************************************
499 * CoInitializeEx [OLE32.@]
501 * Initializes the COM libraries.
504 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
505 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
508 * S_OK if successful,
509 * S_FALSE if this function was called already.
510 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
515 * The behavior used to set the IMalloc used for memory management is
517 * The dwCoInit parameter must specify of of the following apartment
519 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
520 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
521 * The parameter may also specify zero or more of the following flags:
522 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
523 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
528 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
533 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
535 if (lpReserved!=NULL)
537 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
541 * Check the lock count. If this is the first time going through the initialize
542 * process, we have to initialize the libraries.
544 * And crank-up that lock count.
546 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
549 * Initialize the various COM libraries and data structures.
551 TRACE("() - Initializing the COM libraries\n");
553 /* we may need to defer this until after apartment initialisation */
554 RunningObjectTableImpl_Initialize();
557 if (!(apt = COM_CurrentInfo()->apt))
559 apt = COM_CreateApartment(dwCoInit);
560 if (!apt) return E_OUTOFMEMORY;
562 else if (dwCoInit != apt->model)
564 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
565 code then we are probably using the wrong threading model to implement that API. */
566 ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
567 COM_ApartmentRelease(apt);
568 return RPC_E_CHANGED_MODE;
573 COM_CurrentInfo()->inits++;
578 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
579 pending RPCs are ignored. Non-COM messages are discarded at this point.
581 void COM_FlushMessageQueue(void)
584 APARTMENT *apt = COM_CurrentApt();
586 if (!apt || !apt->win) return;
588 TRACE("Flushing STA message queue\n");
590 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
592 if (message.hwnd != apt->win)
594 WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
598 TranslateMessage(&message);
599 DispatchMessageA(&message);
603 /***********************************************************************
604 * CoUninitialize [OLE32.@]
606 * This method will decrement the refcount on the current apartment, freeing
607 * the resources associated with it if it is the last thread in the apartment.
608 * If the last apartment is freed, the function will additionally release
609 * any COM resources associated with the process.
619 void WINAPI CoUninitialize(void)
621 struct oletls * info = COM_CurrentInfo();
626 /* will only happen on OOM */
632 ERR("Mismatched CoUninitialize\n");
638 COM_ApartmentRelease(info->apt);
643 * Decrease the reference count.
644 * If we are back to 0 locks on the COM library, make sure we free
645 * all the associated data structures.
647 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
650 TRACE("() - Releasing the COM libraries\n");
652 RunningObjectTableImpl_UnInitialize();
654 /* Release the references to the registered class objects */
655 COM_RevokeAllClasses();
657 /* This will free the loaded COM Dlls */
658 CoFreeAllLibraries();
660 /* This will free list of external references to COM objects */
661 COM_ExternalLockFreeList();
663 /* This ensures we deal with any pending RPCs */
664 COM_FlushMessageQueue();
666 else if (lCOMRefCnt<1) {
667 ERR( "CoUninitialize() - not CoInitialized.\n" );
668 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
672 /******************************************************************************
673 * CoDisconnectObject [OLE32.@]
674 * CoDisconnectObject [COMPOBJ.15]
676 * Disconnects all connections to this object from remote processes. Dispatches
677 * pending RPCs while blocking new RPCs from occurring, and then calls
678 * IMarshal::DisconnectObject on the given object.
680 * Typically called when the object server is forced to shut down, for instance by
684 * lpUnk [I] The object whose stub should be disconnected.
685 * reserved [I] Reserved. Should be set to 0.
689 * Failure: HRESULT code.
692 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
694 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
696 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
700 /******************************************************************************
701 * CoCreateGuid [OLE32.@]
703 * Simply forwards to UuidCreate in RPCRT4.
706 * pguid [O] Points to the GUID to initialize.
710 * Failure: HRESULT code.
715 HRESULT WINAPI CoCreateGuid(GUID *pguid)
717 return UuidCreate(pguid);
720 /******************************************************************************
721 * CLSIDFromString [OLE32.@]
722 * IIDFromString [OLE32.@]
724 * Converts a unique identifier from its string representation into
728 * idstr [I] The string representation of the GUID.
729 * id [O] GUID converted from the string.
733 * CO_E_CLASSSTRING if idstr is not a valid CLSID
737 * In Windows, if idstr is not a valid CLSID string then it gets
738 * treated as a ProgID. Wine currently doesn't do this. If idstr is
739 * NULL it's treated as an all-zero GUID.
744 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
746 const BYTE *s = (const BYTE *) idstr;
751 s = "{00000000-0000-0000-0000-000000000000}";
752 else { /* validate the CLSID string */
755 return CO_E_CLASSSTRING;
757 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
758 return CO_E_CLASSSTRING;
760 for (i=1; i<37; i++) {
761 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
762 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
763 ((s[i] >= 'a') && (s[i] <= 'f')) ||
764 ((s[i] >= 'A') && (s[i] <= 'F'))))
765 return CO_E_CLASSSTRING;
769 TRACE("%s -> %p\n", s, id);
771 /* quick lookup table */
772 memset(table, 0, 256);
774 for (i = 0; i < 10; i++) {
777 for (i = 0; i < 6; i++) {
778 table['A' + i] = i+10;
779 table['a' + i] = i+10;
782 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
784 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
785 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
786 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
787 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
789 /* these are just sequential bytes */
790 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
791 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
792 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
793 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
794 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
795 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
796 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
797 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
802 /*****************************************************************************/
804 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
809 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
810 return CO_E_CLASSSTRING;
813 ret = __CLSIDFromStringA(xid,id);
814 if(ret != S_OK) { /* It appears a ProgID is also valid */
815 ret = CLSIDFromProgID(idstr, id);
820 /* Converts a GUID into the respective string representation. */
821 HRESULT WINE_StringFromCLSID(
822 const CLSID *id, /* [in] GUID to be converted */
823 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
825 static const char *hex = "0123456789ABCDEF";
830 { ERR("called with id=Null\n");
835 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
836 id->Data1, id->Data2, id->Data3,
837 id->Data4[0], id->Data4[1]);
841 for (i = 2; i < 8; i++) {
842 *s++ = hex[id->Data4[i]>>4];
843 *s++ = hex[id->Data4[i] & 0xf];
849 TRACE("%p->%s\n", id, idstr);
855 /******************************************************************************
856 * StringFromCLSID [OLE32.@]
857 * StringFromIID [OLE32.@]
859 * Converts a GUID into the respective string representation.
860 * The target string is allocated using the OLE IMalloc.
863 * id [I] the GUID to be converted.
864 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
871 * StringFromGUID2, CLSIDFromString
873 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
879 if ((ret = CoGetMalloc(0,&mllc)))
882 ret=WINE_StringFromCLSID(id,buf);
884 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
885 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
886 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
891 /******************************************************************************
892 * StringFromGUID2 [OLE32.@]
893 * StringFromGUID2 [COMPOBJ.76]
895 * Modified version of StringFromCLSID that allows you to specify max
899 * id [I] GUID to convert to string.
900 * str [O] Buffer where the result will be stored.
901 * cmax [I] Size of the buffer in characters.
904 * Success: The length of the resulting string in characters.
907 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
911 if (WINE_StringFromCLSID(id,xguid))
913 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
916 /******************************************************************************
917 * ProgIDFromCLSID [OLE32.@]
919 * Converts a class id into the respective program ID.
922 * clsid [I] Class ID, as found in registry.
923 * lplpszProgID [O] Associated ProgID.
928 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
930 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
932 char strCLSID[50], *buf, *buf2;
938 WINE_StringFromCLSID(clsid, strCLSID);
940 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
941 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
942 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
943 ret = REGDB_E_CLASSNOTREG;
945 HeapFree(GetProcessHeap(), 0, buf);
949 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
951 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
952 ret = REGDB_E_CLASSNOTREG;
956 if (CoGetMalloc(0,&mllc))
960 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
961 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
962 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
965 HeapFree(GetProcessHeap(), 0, buf2);
972 HRESULT WINAPI CLSIDFromProgID16(
973 LPCOLESTR16 progid, /* [in] program id as found in registry */
974 LPCLSID riid /* [out] associated CLSID */
981 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
982 sprintf(buf,"%s\\CLSID",progid);
983 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
984 HeapFree(GetProcessHeap(),0,buf);
985 return CO_E_CLASSSTRING;
987 HeapFree(GetProcessHeap(),0,buf);
988 buf2len = sizeof(buf2);
989 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
991 return CO_E_CLASSSTRING;
994 return __CLSIDFromStringA(buf2,riid);
997 /******************************************************************************
998 * CLSIDFromProgID [OLE32.@]
999 * CLSIDFromProgID [COMPOBJ.61]
1001 * Converts a program id into the respective GUID.
1004 * progid [I] Unicode program ID, as found in registry.
1005 * riid [O] Associated CLSID.
1009 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1011 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1013 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1015 DWORD buf2len = sizeof(buf2);
1018 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1019 strcpyW( buf, progid );
1020 strcatW( buf, clsidW );
1021 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1023 HeapFree(GetProcessHeap(),0,buf);
1024 return CO_E_CLASSSTRING;
1026 HeapFree(GetProcessHeap(),0,buf);
1028 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1031 return CO_E_CLASSSTRING;
1034 return __CLSIDFromStringA(buf2,riid);
1039 /*****************************************************************************
1040 * CoGetPSClsid [OLE32.@]
1042 * This function returns the CLSID of the proxy/stub factory that
1043 * implements IPSFactoryBuffer for the specified interface.
1046 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1047 * pclsid [O] Where to store returned proxy/stub CLSID.
1052 * E_INVALIDARG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1056 * The standard marshaller activates the object with the CLSID
1057 * returned and uses the CreateProxy and CreateStub methods on its
1058 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1061 * CoGetPSClsid determines this CLSID by searching the
1062 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1063 * in the registry and any interface id registered by
1064 * CoRegisterPSClsid within the current process.
1068 * We only search the registry, not ids registered with
1069 * CoRegisterPSClsid.
1071 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1073 char *buf, buf2[40];
1077 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1079 /* Get the input iid as a string */
1080 WINE_StringFromCLSID(riid, buf2);
1081 /* Allocate memory for the registry key we will construct.
1082 (length of iid string plus constant length of static text */
1083 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1086 return (E_OUTOFMEMORY);
1089 /* Construct the registry key we want */
1090 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1092 /* Open the key.. */
1093 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1095 WARN("No PSFactoryBuffer object is registered for this IID\n");
1096 HeapFree(GetProcessHeap(),0,buf);
1097 return (E_INVALIDARG);
1099 HeapFree(GetProcessHeap(),0,buf);
1101 /* ... Once we have the key, query the registry to get the
1102 value of CLSID as a string, and convert it into a
1103 proper CLSID structure to be passed back to the app */
1104 buf2len = sizeof(buf2);
1105 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1108 return E_INVALIDARG;
1112 /* We have the CLSid we want back from the registry as a string, so
1113 lets convert it into a CLSID structure */
1114 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
1115 return E_INVALIDARG;
1118 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1124 /***********************************************************************
1125 * WriteClassStm (OLE32.@)
1127 * Writes a CLSID to a stream.
1130 * pStm [I] Stream to write to.
1131 * rclsid [I] CLSID to write.
1135 * Failure: HRESULT code.
1137 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1139 TRACE("(%p,%p)\n",pStm,rclsid);
1142 return E_INVALIDARG;
1144 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1147 /***********************************************************************
1148 * ReadClassStm (OLE32.@)
1150 * Reads a CLSID from a stream.
1153 * pStm [I] Stream to read from.
1154 * rclsid [O] CLSID to read.
1158 * Failure: HRESULT code.
1160 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1165 TRACE("(%p,%p)\n",pStm,pclsid);
1168 return E_INVALIDARG;
1170 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1175 if (nbByte != sizeof(CLSID))
1183 * COM_GetRegisteredClassObject
1185 * This internal method is used to scan the registered class list to
1186 * find a class object.
1189 * rclsid Class ID of the class to find.
1190 * dwClsContext Class context to match.
1191 * ppv [out] returns a pointer to the class object. Complying
1192 * to normal COM usage, this method will increase the
1193 * reference count on this object.
1195 static HRESULT COM_GetRegisteredClassObject(
1200 HRESULT hr = S_FALSE;
1201 RegisteredClass* curClass;
1203 EnterCriticalSection( &csRegisteredClassList );
1211 * Iterate through the whole list and try to match the class ID.
1213 curClass = firstRegisteredClass;
1215 while (curClass != 0)
1218 * Check if we have a match on the class ID.
1220 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1223 * Since we don't do out-of process or DCOM just right away, let's ignore the
1228 * We have a match, return the pointer to the class object.
1230 *ppUnk = curClass->classObject;
1232 IUnknown_AddRef(curClass->classObject);
1239 * Step to the next class in the list.
1241 curClass = curClass->nextClass;
1245 LeaveCriticalSection( &csRegisteredClassList );
1247 * If we get to here, we haven't found our class.
1252 /******************************************************************************
1253 * CoRegisterClassObject [OLE32.@]
1255 * Registers the class object for a given class ID. Servers housed in EXE
1256 * files use this method instead of exporting DllGetClassObject to allow
1257 * other code to connect to their objects.
1260 * rclsid [I] CLSID of the object to register.
1261 * pUnk [I] IUnknown of the object.
1262 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1263 * flags [I] REGCLS flags indicating how connections are made.
1264 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1268 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1269 * CO_E_OBJISREG if the object is already registered. We should not return this.
1272 * CoRevokeClassObject, CoGetClassObject
1275 * MSDN claims that multiple interface registrations are legal, but we
1276 * can't do that with our current implementation.
1278 HRESULT WINAPI CoRegisterClassObject(
1283 LPDWORD lpdwRegister)
1285 RegisteredClass* newClass;
1286 LPUNKNOWN foundObject;
1289 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1290 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1292 if ( (lpdwRegister==0) || (pUnk==0) )
1293 return E_INVALIDARG;
1295 if (!COM_CurrentApt())
1297 ERR("COM was not initialized\n");
1298 return CO_E_NOTINITIALIZED;
1304 * First, check if the class is already registered.
1305 * If it is, this should cause an error.
1307 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1309 IUnknown_Release(foundObject);
1310 return CO_E_OBJISREG;
1313 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1314 if ( newClass == NULL )
1315 return E_OUTOFMEMORY;
1317 EnterCriticalSection( &csRegisteredClassList );
1319 newClass->classIdentifier = *rclsid;
1320 newClass->runContext = dwClsContext;
1321 newClass->connectFlags = flags;
1323 * Use the address of the chain node as the cookie since we are sure it's
1324 * unique. FIXME: not on 64-bit platforms.
1326 newClass->dwCookie = (DWORD)newClass;
1327 newClass->nextClass = firstRegisteredClass;
1330 * Since we're making a copy of the object pointer, we have to increase its
1333 newClass->classObject = pUnk;
1334 IUnknown_AddRef(newClass->classObject);
1336 firstRegisteredClass = newClass;
1337 LeaveCriticalSection( &csRegisteredClassList );
1339 *lpdwRegister = newClass->dwCookie;
1341 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1342 IClassFactory *classfac;
1344 hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1345 (LPVOID*)&classfac);
1348 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1350 FIXME("Failed to create stream on hglobal, %lx\n", hr);
1351 IUnknown_Release(classfac);
1354 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1355 (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1356 MSHLFLAGS_TABLESTRONG);
1358 FIXME("CoMarshalInterface failed, %lx!\n",hr);
1359 IUnknown_Release(classfac);
1363 IUnknown_Release(classfac);
1365 RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1370 /***********************************************************************
1371 * CoRevokeClassObject [OLE32.@]
1373 * Removes a class object from the class registry.
1376 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1380 * Failure: HRESULT code.
1383 * CoRegisterClassObject
1385 HRESULT WINAPI CoRevokeClassObject(
1388 HRESULT hr = E_INVALIDARG;
1389 RegisteredClass** prevClassLink;
1390 RegisteredClass* curClass;
1392 TRACE("(%08lx)\n",dwRegister);
1394 EnterCriticalSection( &csRegisteredClassList );
1397 * Iterate through the whole list and try to match the cookie.
1399 curClass = firstRegisteredClass;
1400 prevClassLink = &firstRegisteredClass;
1402 while (curClass != 0)
1405 * Check if we have a match on the cookie.
1407 if (curClass->dwCookie == dwRegister)
1410 * Remove the class from the chain.
1412 *prevClassLink = curClass->nextClass;
1415 * Release the reference to the class object.
1417 IUnknown_Release(curClass->classObject);
1419 if (curClass->pMarshaledData)
1422 memset(&zero, 0, sizeof(zero));
1423 /* FIXME: stop local server thread */
1424 IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1425 CoReleaseMarshalData(curClass->pMarshaledData);
1429 * Free the memory used by the chain node.
1431 HeapFree(GetProcessHeap(), 0, curClass);
1438 * Step to the next class in the list.
1440 prevClassLink = &(curClass->nextClass);
1441 curClass = curClass->nextClass;
1445 LeaveCriticalSection( &csRegisteredClassList );
1447 * If we get to here, we haven't found our class.
1452 /***********************************************************************
1453 * compobj_RegReadPath [internal]
1455 * Reads a registry value and expands it when necessary
1457 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1463 DWORD dwLength = dstlen;
1465 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1466 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1467 if (keytype == REG_EXPAND_SZ) {
1468 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1470 lstrcpynA(dst, src, dstlen);
1478 /***********************************************************************
1479 * CoGetClassObject [COMPOBJ.7]
1480 * CoGetClassObject [OLE32.@]
1482 * FIXME. If request allows of several options and there is a failure
1483 * with one (other than not being registered) do we try the
1484 * others or return failure? (E.g. inprocess is registered but
1485 * the DLL is not found but the server version works)
1487 HRESULT WINAPI CoGetClassObject(
1488 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1489 REFIID iid, LPVOID *ppv
1491 LPUNKNOWN regClassObject;
1492 HRESULT hres = E_UNEXPECTED;
1495 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1496 DllGetClassObjectFunc DllGetClassObject;
1498 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1500 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1503 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1504 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1508 * First, try and see if we can't match the class ID with one of the
1509 * registered classes.
1511 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
1514 * Get the required interface from the retrieved pointer.
1516 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1519 * Since QI got another reference on the pointer, we want to release the
1520 * one we already have. If QI was unsuccessful, this will release the object. This
1521 * is good since we are not returning it in the "out" parameter.
1523 IUnknown_Release(regClassObject);
1528 /* first try: in-process */
1529 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1530 char keyname[MAX_PATH];
1531 char dllpath[MAX_PATH+1];
1533 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1535 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1536 /* failure: CLSID is not found in registry */
1537 WARN("class %s not registered inproc\n", xclsid);
1538 hres = REGDB_E_CLASSNOTREG;
1540 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1541 /* failure: DLL could not be loaded */
1542 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1543 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1544 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1545 /* failure: the dll did not export DllGetClassObject */
1546 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1547 FreeLibrary( hLibrary );
1548 hres = CO_E_DLLNOTFOUND;
1550 /* OK: get the ClassObject */
1551 COMPOBJ_DLLList_Add( hLibrary );
1552 return DllGetClassObject(rclsid, iid, ppv);
1557 /* Next try out of process */
1558 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1560 return create_marshalled_proxy(rclsid,iid,ppv);
1563 /* Finally try remote: this requires networked DCOM (a lot of work) */
1564 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1566 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1567 hres = E_NOINTERFACE;
1572 /***********************************************************************
1573 * CoResumeClassObjects (OLE32.@)
1575 * Resumes all class objects registered with REGCLS_SUSPENDED.
1579 * Failure: HRESULT code.
1581 HRESULT WINAPI CoResumeClassObjects(void)
1587 /***********************************************************************
1588 * GetClassFile (OLE32.@)
1590 * This function supplies the CLSID associated with the given filename.
1592 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1596 int nbElm, length, i;
1598 LPOLESTR *pathDec=0,absFile=0,progId=0;
1600 static const WCHAR bkslashW[] = {'\\',0};
1601 static const WCHAR dotW[] = {'.',0};
1603 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1605 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1606 if((StgIsStorageFile(filePathName))==S_OK){
1608 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1611 res=ReadClassStg(pstg,pclsid);
1613 IStorage_Release(pstg);
1617 /* if the file is not a storage object then attemps to match various bits in the file against a
1618 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1621 for(i=0;i<nFileTypes;i++)
1623 for(i=0;j<nPatternsForType;j++){
1628 pat=ReadPatternFromRegistry(i,j);
1629 hFile=CreateFileW(filePathName,,,,,,hFile);
1630 SetFilePosition(hFile,pat.offset);
1631 ReadFile(hFile,buf,pat.size,&r,NULL);
1632 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1634 *pclsid=ReadCLSIDFromRegistry(i);
1640 /* if the above strategies fail then search for the extension key in the registry */
1642 /* get the last element (absolute file) in the path name */
1643 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1644 absFile=pathDec[nbElm-1];
1646 /* failed if the path represente a directory and not an absolute file name*/
1647 if (!lstrcmpW(absFile, bkslashW))
1648 return MK_E_INVALIDEXTENSION;
1650 /* get the extension of the file */
1652 length=lstrlenW(absFile);
1653 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1656 if (!extension || !lstrcmpW(extension, dotW))
1657 return MK_E_INVALIDEXTENSION;
1659 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1661 /* get the progId associated to the extension */
1662 progId = CoTaskMemAlloc(sizeProgId);
1663 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1665 if (res==ERROR_SUCCESS)
1666 /* return the clsid associated to the progId */
1667 res= CLSIDFromProgID(progId,pclsid);
1669 for(i=0; pathDec[i]!=NULL;i++)
1670 CoTaskMemFree(pathDec[i]);
1671 CoTaskMemFree(pathDec);
1673 CoTaskMemFree(progId);
1675 if (res==ERROR_SUCCESS)
1678 return MK_E_INVALIDEXTENSION;
1680 /***********************************************************************
1681 * CoCreateInstance [COMPOBJ.13]
1682 * CoCreateInstance [OLE32.@]
1684 HRESULT WINAPI CoCreateInstance(
1686 LPUNKNOWN pUnkOuter,
1692 LPCLASSFACTORY lpclf = 0;
1694 if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1703 * Initialize the "out" parameter
1708 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1709 * Rather than create a class factory, we can just check for it here
1711 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1712 if (StdGlobalInterfaceTableInstance == NULL)
1713 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1714 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1715 if (hres) return hres;
1717 TRACE("Retrieved GIT (%p)\n", *ppv);
1722 * Get a class factory to construct the object we want.
1724 hres = CoGetClassObject(rclsid,
1731 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1732 debugstr_guid(rclsid),hres);
1737 * Create the object and don't forget to release the factory
1739 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1740 IClassFactory_Release(lpclf);
1742 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1743 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1748 /***********************************************************************
1749 * CoCreateInstanceEx [OLE32.@]
1751 HRESULT WINAPI CoCreateInstanceEx(
1753 LPUNKNOWN pUnkOuter,
1755 COSERVERINFO* pServerInfo,
1759 IUnknown* pUnk = NULL;
1762 ULONG successCount = 0;
1767 if ( (cmq==0) || (pResults==NULL))
1768 return E_INVALIDARG;
1770 if (pServerInfo!=NULL)
1771 FIXME("() non-NULL pServerInfo not supported!\n");
1774 * Initialize all the "out" parameters.
1776 for (index = 0; index < cmq; index++)
1778 pResults[index].pItf = NULL;
1779 pResults[index].hr = E_NOINTERFACE;
1783 * Get the object and get its IUnknown pointer.
1785 hr = CoCreateInstance(rclsid,
1795 * Then, query for all the interfaces requested.
1797 for (index = 0; index < cmq; index++)
1799 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1800 pResults[index].pIID,
1801 (VOID**)&(pResults[index].pItf));
1803 if (pResults[index].hr == S_OK)
1808 * Release our temporary unknown pointer.
1810 IUnknown_Release(pUnk);
1812 if (successCount == 0)
1813 return E_NOINTERFACE;
1815 if (successCount!=cmq)
1816 return CO_S_NOTALLINTERFACES;
1821 /***********************************************************************
1822 * CoLoadLibrary (OLE32.@)
1827 * lpszLibName [I] Path to library.
1828 * bAutoFree [I] Whether the library should automatically be freed.
1831 * Success: Handle to loaded library.
1835 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1837 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1839 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1841 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1844 /***********************************************************************
1845 * CoFreeLibrary [OLE32.@]
1847 * Unloads a library from memory.
1850 * hLibrary [I] Handle to library to unload.
1856 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1858 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1860 FreeLibrary(hLibrary);
1864 /***********************************************************************
1865 * CoFreeAllLibraries [OLE32.@]
1867 * Function for backwards compatibility only. Does nothing.
1873 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1875 void WINAPI CoFreeAllLibraries(void)
1881 /***********************************************************************
1882 * CoFreeUnusedLibraries [OLE32.@]
1883 * CoFreeUnusedLibraries [COMPOBJ.17]
1885 * Frees any unused libraries. Unused are identified as those that return
1886 * S_OK from their DllCanUnloadNow function.
1892 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1894 void WINAPI CoFreeUnusedLibraries(void)
1896 /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1897 * through the main apartment's thread to call DllCanUnloadNow */
1898 COMPOBJ_DllList_FreeUnused(0);
1901 /***********************************************************************
1902 * CoFileTimeNow [OLE32.@]
1903 * CoFileTimeNow [COMPOBJ.82]
1905 * Retrieves the current time in FILETIME format.
1908 * lpFileTime [O] The current time.
1913 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1915 GetSystemTimeAsFileTime( lpFileTime );
1919 static void COM_RevokeAllClasses()
1921 EnterCriticalSection( &csRegisteredClassList );
1923 while (firstRegisteredClass!=0)
1925 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1928 LeaveCriticalSection( &csRegisteredClassList );
1931 /****************************************************************************
1932 * COM External Lock methods implementation
1934 * This api provides a linked list to managed external references to
1937 * The public interface consists of three calls:
1938 * COM_ExternalLockAddRef
1939 * COM_ExternalLockRelease
1940 * COM_ExternalLockFreeList
1943 #define EL_END_OF_LIST 0
1944 #define EL_NOT_FOUND 0
1947 * Declaration of the static structure that manage the
1948 * external lock to COM objects.
1950 typedef struct COM_ExternalLock COM_ExternalLock;
1951 typedef struct COM_ExternalLockList COM_ExternalLockList;
1953 struct COM_ExternalLock
1955 IUnknown *pUnk; /* IUnknown referenced */
1956 ULONG uRefCount; /* external lock counter to IUnknown object*/
1957 COM_ExternalLock *next; /* Pointer to next element in list */
1960 struct COM_ExternalLockList
1962 COM_ExternalLock *head; /* head of list */
1966 * Declaration and initialization of the static structure that manages
1967 * the external lock to COM objects.
1969 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1972 * Private methods used to managed the linked list
1976 static COM_ExternalLock* COM_ExternalLockLocate(
1977 COM_ExternalLock *element,
1980 /****************************************************************************
1981 * Internal - Insert a new IUnknown* to the linked list
1983 static BOOL COM_ExternalLockInsert(
1986 COM_ExternalLock *newLock = NULL;
1987 COM_ExternalLock *previousHead = NULL;
1990 * Allocate space for the new storage object
1992 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1994 if (newLock!=NULL) {
1995 if ( elList.head == EL_END_OF_LIST ) {
1996 elList.head = newLock; /* The list is empty */
1998 /* insert does it at the head */
1999 previousHead = elList.head;
2000 elList.head = newLock;
2003 /* Set new list item data member */
2004 newLock->pUnk = pUnk;
2005 newLock->uRefCount = 1;
2006 newLock->next = previousHead;
2013 /****************************************************************************
2014 * Internal - Method that removes an item from the linked list.
2016 static void COM_ExternalLockDelete(
2017 COM_ExternalLock *itemList)
2019 COM_ExternalLock *current = elList.head;
2021 if ( current == itemList ) {
2022 /* this section handles the deletion of the first node */
2023 elList.head = itemList->next;
2024 HeapFree( GetProcessHeap(), 0, itemList);
2027 if ( current->next == itemList ){ /* We found the item to free */
2028 current->next = itemList->next; /* readjust the list pointers */
2029 HeapFree( GetProcessHeap(), 0, itemList);
2033 /* Skip to the next item */
2034 current = current->next;
2036 } while ( current != EL_END_OF_LIST );
2040 /****************************************************************************
2041 * Internal - Recursivity agent for IUnknownExternalLockList_Find
2043 * NOTES: how long can the list be ?? (recursive!!!)
2045 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
2047 if ( element == EL_END_OF_LIST )
2048 return EL_NOT_FOUND;
2049 else if ( element->pUnk == pUnk ) /* We found it */
2051 else /* Not the right guy, keep on looking */
2052 return COM_ExternalLockLocate( element->next, pUnk);
2055 /****************************************************************************
2056 * Public - Method that increments the count for a IUnknown* in the linked
2057 * list. The item is inserted if not already in the list.
2059 static void COM_ExternalLockAddRef(IUnknown *pUnk)
2061 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2064 * Add an external lock to the object. If it was already externally
2065 * locked, just increase the reference count. If it was not.
2066 * add the item to the list.
2068 if ( externalLock == EL_NOT_FOUND )
2069 COM_ExternalLockInsert(pUnk);
2071 externalLock->uRefCount++;
2074 * Add an internal lock to the object
2076 IUnknown_AddRef(pUnk);
2079 /****************************************************************************
2080 * Public - Method that decrements the count for a IUnknown* in the linked
2081 * list. The item is removed from the list if its count end up at zero or if
2084 static void COM_ExternalLockRelease(
2088 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
2090 if ( externalLock != EL_NOT_FOUND ) {
2092 externalLock->uRefCount--; /* release external locks */
2093 IUnknown_Release(pUnk); /* release local locks as well */
2095 if ( bRelAll == FALSE ) break; /* perform single release */
2097 } while ( externalLock->uRefCount > 0 );
2099 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
2100 COM_ExternalLockDelete(externalLock);
2103 /****************************************************************************
2104 * Public - Method that frees the content of the list.
2106 static void COM_ExternalLockFreeList()
2108 COM_ExternalLock *head;
2110 head = elList.head; /* grab it by the head */
2111 while ( head != EL_END_OF_LIST ) {
2112 COM_ExternalLockDelete(head); /* get rid of the head stuff */
2113 head = elList.head; /* get the new head... */
2117 /****************************************************************************
2118 * Public - Method that dump the content of the list.
2120 void COM_ExternalLockDump()
2122 COM_ExternalLock *current = elList.head;
2124 DPRINTF("\nExternal lock list contains:\n");
2126 while ( current != EL_END_OF_LIST ) {
2127 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
2129 /* Skip to the next item */
2130 current = current->next;
2134 /******************************************************************************
2135 * CoLockObjectExternal [OLE32.@]
2137 * Increments or decrements the external reference count of a stub object.
2140 * pUnk [I] Stub object.
2141 * fLock [I] If TRUE then increments the external ref-count,
2142 * otherwise decrements.
2143 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2144 * calling CoDisconnectObject.
2148 * Failure: HRESULT code.
2150 HRESULT WINAPI CoLockObjectExternal(
2151 LPUNKNOWN pUnk, /* */
2152 BOOL fLock, /* [in] do lock */
2153 BOOL fLastUnlockReleases) /* [in] unlock all */
2155 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2156 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2160 * Increment the external lock coutner, COM_ExternalLockAddRef also
2161 * increment the object's internal lock counter.
2163 COM_ExternalLockAddRef( pUnk);
2166 * Decrement the external lock coutner, COM_ExternalLockRelease also
2167 * decrement the object's internal lock counter.
2169 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
2175 /***********************************************************************
2176 * CoInitializeWOW (OLE32.@)
2178 * WOW equivalent of CoInitialize?
2187 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2189 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2193 /***********************************************************************
2194 * CoGetState [OLE32.@]
2196 * Retrieves the thread state object previously stored by CoSetState().
2199 * ppv [I] Address where pointer to object will be stored.
2203 * Failure: E_OUTOFMEMORY.
2206 * Crashes on all invalid ppv addresses, including NULL.
2207 * If the function returns a non-NULL object then the caller must release its
2208 * reference on the object when the object is no longer required.
2213 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2215 struct oletls *info = COM_CurrentInfo();
2216 if (!info) return E_OUTOFMEMORY;
2222 IUnknown_AddRef(info->state);
2224 TRACE("apt->state=%p\n", info->state);
2230 /***********************************************************************
2231 * CoSetState [OLE32.@]
2233 * Sets the thread state object.
2236 * pv [I] Pointer to state object to be stored.
2239 * The system keeps a reference on the object while the object stored.
2243 * Failure: E_OUTOFMEMORY.
2245 HRESULT WINAPI CoSetState(IUnknown * pv)
2247 struct oletls *info = COM_CurrentInfo();
2248 if (!info) return E_OUTOFMEMORY;
2250 if (pv) IUnknown_AddRef(pv);
2254 TRACE("-- release %p now\n", info->state);
2255 IUnknown_Release(info->state);
2264 /******************************************************************************
2265 * OleGetAutoConvert [OLE32.@]
2267 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2275 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2276 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2278 res = REGDB_E_CLASSNOTREG;
2282 /* we can just query for the default value of AutoConvertTo key like that,
2283 without opening the AutoConvertTo key and querying for NULL (default) */
2284 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2286 res = REGDB_E_KEYMISSING;
2289 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2290 CLSIDFromString(wbuf,pClsidNew);
2292 if (hkey) RegCloseKey(hkey);
2296 /******************************************************************************
2297 * CoTreatAsClass [OLE32.@]
2299 * Sets the TreatAs value of a class.
2302 * clsidOld [I] Class to set TreatAs value on.
2303 * clsidNew [I] The class the clsidOld should be treated as.
2307 * Failure: HRESULT code.
2312 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2316 char szClsidNew[39];
2318 char auto_treat_as[39];
2319 LONG auto_treat_as_size = sizeof(auto_treat_as);
2322 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2323 WINE_StringFromCLSID(clsidNew, szClsidNew);
2324 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2326 res = REGDB_E_CLASSNOTREG;
2329 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2331 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2332 !__CLSIDFromStringA(auto_treat_as, &id))
2334 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2336 res = REGDB_E_WRITEREGDB;
2342 RegDeleteKeyA(hkey, "TreatAs");
2346 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2348 res = REGDB_E_WRITEREGDB;
2353 if (hkey) RegCloseKey(hkey);
2357 /******************************************************************************
2358 * CoGetTreatAsClass [OLE32.@]
2360 * Gets the TreatAs value of a class.
2363 * clsidOld [I] Class to get the TreatAs value of.
2364 * clsidNew [I] The class the clsidOld should be treated as.
2368 * Failure: HRESULT code.
2373 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2376 char buf[200], szClsidNew[200];
2378 LONG len = sizeof(szClsidNew);
2380 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2381 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2382 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2384 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2386 res = REGDB_E_CLASSNOTREG;
2389 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2394 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2396 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2398 if (hkey) RegCloseKey(hkey);
2403 /******************************************************************************
2404 * CoGetCurrentProcess [OLE32.@]
2405 * CoGetCurrentProcess [COMPOBJ.34]
2407 * Gets the current process ID.
2410 * The current process ID.
2413 * Is DWORD really the correct return type for this function?
2415 DWORD WINAPI CoGetCurrentProcess(void)
2417 return GetCurrentProcessId();
2420 /******************************************************************************
2421 * CoRegisterMessageFilter [OLE32.@]
2423 * Registers a message filter.
2426 * lpMessageFilter [I] Pointer to interface.
2427 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2431 * Failure: HRESULT code.
2433 HRESULT WINAPI CoRegisterMessageFilter(
2434 LPMESSAGEFILTER lpMessageFilter,
2435 LPMESSAGEFILTER *lplpMessageFilter)
2438 if (lplpMessageFilter) {
2439 *lplpMessageFilter = NULL;
2444 /***********************************************************************
2445 * CoIsOle1Class [OLE32.@]
2447 * Determines whether the specified class an OLE v1 class.
2450 * clsid [I] Class to test.
2453 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2455 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2457 FIXME("%s\n", debugstr_guid(clsid));
2461 /***********************************************************************
2462 * IsEqualGUID [OLE32.@]
2464 * Compares two Unique Identifiers.
2467 * rguid1 [I] The first GUID to compare.
2468 * rguid2 [I] The other GUID to compare.
2474 BOOL WINAPI IsEqualGUID(
2478 return !memcmp(rguid1,rguid2,sizeof(GUID));
2481 /***********************************************************************
2482 * CoInitializeSecurity [OLE32.@]
2484 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2485 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2486 void* pReserved1, DWORD dwAuthnLevel,
2487 DWORD dwImpLevel, void* pReserved2,
2488 DWORD dwCapabilities, void* pReserved3)
2490 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2491 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2492 dwCapabilities, pReserved3);
2496 /***********************************************************************
2497 * CoSuspendClassObjects [OLE32.@]
2499 * Suspends all registered class objects to prevent further requests coming in
2500 * for those objects.
2504 * Failure: HRESULT code.
2506 HRESULT WINAPI CoSuspendClassObjects(void)
2512 /***********************************************************************
2513 * CoAddRefServerProcess [OLE32.@]
2515 * Helper function for incrementing the reference count of a local-server
2519 * New reference count.
2521 ULONG WINAPI CoAddRefServerProcess(void)
2527 /***********************************************************************
2528 * CoReleaseServerProcess [OLE32.@]
2530 * Helper function for decrementing the reference count of a local-server
2534 * New reference count.
2536 ULONG WINAPI CoReleaseServerProcess(void)