Don't marshal IClassFactory into the local server pipe until we have
[wine.git] / dlls / ole32 / compobj.c
blob90c605bfeb9bdb8e0b514f40322575d7364c22ff
1 /*
2 * COMPOBJ library
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 #include "config.h"
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <assert.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "objbase.h"
40 #include "ole2.h"
41 #include "ole2ver.h"
42 #include "rpc.h"
43 #include "winerror.h"
44 #include "winreg.h"
45 #include "wownt32.h"
46 #include "wine/unicode.h"
47 #include "objbase.h"
48 #include "ole32_main.h"
49 #include "compobj_private.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
55 typedef LPCSTR LPCOLESTR16;
57 /****************************************************************************
58 * This section defines variables internal to the COM module.
60 * TODO: Most of these things will have to be made thread-safe.
62 HINSTANCE COMPOBJ_hInstance32 = 0;
64 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
65 static void COM_RevokeAllClasses();
66 static void COM_ExternalLockFreeList();
68 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
70 APARTMENT MTA, *apts;
72 static CRITICAL_SECTION csApartment;
73 static CRITICAL_SECTION_DEBUG critsect_debug =
75 0, 0, &csApartment,
76 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
77 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
79 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
82 * This lock count counts the number of times CoInitialize is called. It is
83 * decreased every time CoUninitialize is called. When it hits 0, the COM
84 * libraries are freed
86 static LONG s_COMLockCount = 0;
89 * This linked list contains the list of registered class objects. These
90 * are mostly used to register the factories for out-of-proc servers of OLE
91 * objects.
93 * TODO: Make this data structure aware of inter-process communication. This
94 * means that parts of this will be exported to the Wine Server.
96 typedef struct tagRegisteredClass
98 CLSID classIdentifier;
99 LPUNKNOWN classObject;
100 DWORD runContext;
101 DWORD connectFlags;
102 DWORD dwCookie;
103 HANDLE hThread; /* only for localserver */
104 struct tagRegisteredClass* nextClass;
105 } RegisteredClass;
107 static RegisteredClass* firstRegisteredClass = NULL;
109 static CRITICAL_SECTION csRegisteredClassList;
110 static CRITICAL_SECTION_DEBUG class_cs_debug =
112 0, 0, &csRegisteredClassList,
113 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
114 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
116 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
118 /*****************************************************************************
119 * This section contains OpenDllList definitions
121 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
122 * other functions that do LoadLibrary _without_ giving back a HMODULE.
123 * Without this list these handles would never be freed.
125 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
126 * next unload-call but not before 600 sec.
129 typedef struct tagOpenDll {
130 HINSTANCE hLibrary;
131 struct tagOpenDll *next;
132 } OpenDll;
134 static OpenDll *openDllList = NULL; /* linked list of open dlls */
136 static CRITICAL_SECTION csOpenDllList;
137 static CRITICAL_SECTION_DEBUG dll_cs_debug =
139 0, 0, &csOpenDllList,
140 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
141 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
143 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
145 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
146 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
148 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
149 static void COMPOBJ_DllList_FreeUnused(int Timeout);
151 void COMPOBJ_InitProcess( void )
153 WNDCLASSA wclass;
155 /* Dispatching to the correct thread in an apartment is done through
156 * window messages rather than RPC transports. When an interface is
157 * marshalled into another apartment in the same process, a window of the
158 * following class is created. The *caller* of CoMarshalInterface (ie the
159 * application) is responsible for pumping the message loop in that thread.
160 * The WM_USER messages which point to the RPCs are then dispatched to
161 * COM_AptWndProc by the user's code.
163 memset(&wclass, 0, sizeof(wclass));
164 wclass.lpfnWndProc = &COM_AptWndProc;
165 wclass.hInstance = OLE32_hInstance;
166 wclass.lpszClassName = aptWinClass;
167 RegisterClassA(&wclass);
170 void COMPOBJ_UninitProcess( void )
172 UnregisterClassA(aptWinClass, OLE32_hInstance);
175 /******************************************************************************
176 * Manage apartments.
180 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
181 with free threaded (ie thread safe) COM objects. There is only ever one MTA
182 in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
184 static void COM_InitMTA(void)
186 /* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
187 within a network. That is, two different MTAs on different machines will have
188 different OXIDs.
190 This method of generating an OXID is therefore wrong as it doesn't work across
191 a network, but for local RPC only it's OK. We can distinguish between MTAs and
192 STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
194 MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
195 InitializeCriticalSection(&MTA.cs);
198 static void COM_UninitMTA(void)
200 DeleteCriticalSection(&MTA.cs);
201 MTA.oxid = 0;
204 /* creates an apartment structure which stores OLE thread-local
205 * information. Call with COINIT_UNINITIALIZED to create an apartment
206 * that will be initialized with a model later. Note: do not call
207 * with COINIT_UNINITIALIZED if the apartment has already been initialized
208 * with a different COINIT value */
209 APARTMENT* COM_CreateApartment(DWORD model)
211 APARTMENT *apt;
212 BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
214 if (create)
216 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
217 apt->tid = GetCurrentThreadId();
218 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
219 GetCurrentProcess(), &apt->thread,
220 THREAD_ALL_ACCESS, FALSE, 0);
222 else
223 apt = NtCurrentTeb()->ReservedForOle;
225 apt->model = model;
226 if (model & COINIT_APARTMENTTHREADED) {
227 /* FIXME: how does windoze create OXIDs? */
228 apt->oxid = MTA.oxid | GetCurrentThreadId();
229 apt->win = CreateWindowA(aptWinClass, NULL, 0,
230 0, 0, 0, 0,
231 0, 0, OLE32_hInstance, NULL);
232 InitializeCriticalSection(&apt->cs);
234 else if (!(model & COINIT_UNINITIALIZED)) {
235 apt->parent = &MTA;
236 apt->oxid = MTA.oxid;
238 EnterCriticalSection(&csApartment);
239 if (create)
241 if (apts) apts->prev = apt;
242 apt->next = apts;
243 apts = apt;
245 LeaveCriticalSection(&csApartment);
246 NtCurrentTeb()->ReservedForOle = apt;
247 return apt;
250 static void COM_DestroyApartment(APARTMENT *apt)
252 EnterCriticalSection(&csApartment);
253 if (apt->prev) apt->prev->next = apt->next;
254 if (apt->next) apt->next->prev = apt->prev;
255 if (apts == apt) apts = apt->next;
256 apt->prev = NULL; apt->next = NULL;
257 LeaveCriticalSection(&csApartment);
258 if (apt->model & COINIT_APARTMENTTHREADED) {
259 if (apt->win) DestroyWindow(apt->win);
260 DeleteCriticalSection(&apt->cs);
262 CloseHandle(apt->thread);
263 HeapFree(GetProcessHeap(), 0, apt);
266 /* The given OXID must be local to this process: you cannot use apartment
267 windows to send RPCs to other processes */
268 HWND COM_GetApartmentWin(OXID oxid)
270 APARTMENT *apt;
271 HWND win = 0;
273 EnterCriticalSection(&csApartment);
274 apt = apts;
275 while (apt && apt->oxid != oxid) apt = apt->next;
276 if (apt) win = apt->win;
277 LeaveCriticalSection(&csApartment);
278 return win;
281 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
282 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
284 return DefWindowProcA(hWnd, msg, wParam, lParam);
287 /*****************************************************************************
288 * This section contains OpenDllList implemantation
291 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
293 OpenDll *ptr;
294 OpenDll *tmp;
296 TRACE("\n");
298 EnterCriticalSection( &csOpenDllList );
300 if (openDllList == NULL) {
301 /* empty list -- add first node */
302 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
303 openDllList->hLibrary=hLibrary;
304 openDllList->next = NULL;
305 } else {
306 /* search for this dll */
307 int found = FALSE;
308 for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
309 if (ptr->hLibrary == hLibrary) {
310 found = TRUE;
311 break;
314 if (!found) {
315 /* dll not found, add it */
316 tmp = openDllList;
317 openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
318 openDllList->hLibrary = hLibrary;
319 openDllList->next = tmp;
323 LeaveCriticalSection( &csOpenDllList );
326 static void COMPOBJ_DllList_FreeUnused(int Timeout)
328 OpenDll *curr, *next, *prev = NULL;
329 typedef HRESULT(*DllCanUnloadNowFunc)(void);
330 DllCanUnloadNowFunc DllCanUnloadNow;
332 TRACE("\n");
334 EnterCriticalSection( &csOpenDllList );
336 for (curr = openDllList; curr != NULL; ) {
337 DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
339 if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
340 next = curr->next;
342 TRACE("freeing %p\n", curr->hLibrary);
343 FreeLibrary(curr->hLibrary);
345 HeapFree(GetProcessHeap(), 0, curr);
346 if (curr == openDllList) {
347 openDllList = next;
348 } else {
349 prev->next = next;
352 curr = next;
353 } else {
354 prev = curr;
355 curr = curr->next;
359 LeaveCriticalSection( &csOpenDllList );
362 /******************************************************************************
363 * CoBuildVersion [COMPOBJ.1]
364 * CoBuildVersion [OLE32.@]
366 * RETURNS
367 * Current build version, hiword is majornumber, loword is minornumber
369 DWORD WINAPI CoBuildVersion(void)
371 TRACE("Returning version %d, build %d.\n", rmm, rup);
372 return (rmm<<16)+rup;
375 /******************************************************************************
376 * CoInitialize [OLE32.@]
378 * Initializes the COM libraries.
380 * See CoInitializeEx
382 HRESULT WINAPI CoInitialize(
383 LPVOID lpReserved /* [in] pointer to win32 malloc interface
384 (obsolete, should be NULL) */
388 * Just delegate to the newer method.
390 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
393 /******************************************************************************
394 * CoInitializeEx [OLE32.@]
396 * Initializes the COM libraries. The behavior used to set the win32 IMalloc
397 * used for memory management is obsolete.
399 * RETURNS
400 * S_OK if successful,
401 * S_FALSE if this function was called already.
402 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
403 * threading model.
405 HRESULT WINAPI CoInitializeEx(
406 LPVOID lpReserved, /* [in] pointer to win32 malloc interface
407 (obsolete, should be NULL) */
408 DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
411 HRESULT hr = S_OK;
412 APARTMENT *apt;
414 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
416 if (lpReserved!=NULL)
418 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
421 apt = NtCurrentTeb()->ReservedForOle;
422 if (apt && !(apt->model == COINIT_UNINITIALIZED))
424 if (dwCoInit != apt->model)
426 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
427 code then we are probably using the wrong threading model to implement that API. */
428 WARN("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
429 return RPC_E_CHANGED_MODE;
431 hr = S_FALSE;
433 else
434 hr = S_OK;
437 * Check the lock count. If this is the first time going through the initialize
438 * process, we have to initialize the libraries.
440 * And crank-up that lock count.
442 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
445 * Initialize the various COM libraries and data structures.
447 TRACE("() - Initializing the COM libraries\n");
449 COM_InitMTA();
451 RunningObjectTableImpl_Initialize();
454 if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
456 InterlockedIncrement(&apt->inits);
457 if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
459 return hr;
462 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
463 pending RPCs are ignored. Non-COM messages are discarded at this point.
465 void COM_FlushMessageQueue(void)
467 MSG message;
468 APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
470 if (!apt || !apt->win) return;
472 TRACE("Flushing STA message queue\n");
474 while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
475 if (message.hwnd != apt->win) continue;
476 TranslateMessage(&message);
477 DispatchMessageA(&message);
481 /***********************************************************************
482 * CoUninitialize [OLE32.@]
484 * This method will release the COM libraries.
486 * See the windows documentation for more details.
488 void WINAPI CoUninitialize(void)
490 LONG lCOMRefCnt;
491 APARTMENT *apt;
493 TRACE("()\n");
495 apt = NtCurrentTeb()->ReservedForOle;
496 if (!apt) return;
497 if (InterlockedDecrement(&apt->inits)==0) {
498 NtCurrentTeb()->ReservedForOle = NULL;
499 COM_DestroyApartment(apt);
500 apt = NULL;
504 * Decrease the reference count.
505 * If we are back to 0 locks on the COM library, make sure we free
506 * all the associated data structures.
508 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
509 if (lCOMRefCnt==1)
511 TRACE("() - Releasing the COM libraries\n");
513 RunningObjectTableImpl_UnInitialize();
515 /* Release the references to the registered class objects */
516 COM_RevokeAllClasses();
518 /* This will free the loaded COM Dlls */
519 CoFreeAllLibraries();
521 /* This will free list of external references to COM objects */
522 COM_ExternalLockFreeList();
524 /* This ensures we deal with any pending RPCs */
525 COM_FlushMessageQueue();
527 COM_UninitMTA();
529 else if (lCOMRefCnt<1) {
530 ERR( "CoUninitialize() - not CoInitialized.\n" );
531 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
535 /******************************************************************************
536 * CoDisconnectObject [COMPOBJ.15]
537 * CoDisconnectObject [OLE32.@]
539 * Disconnects all connections to this object from remote processes. Dispatches
540 * pending RPCs while blocking new RPCs from occurring, and then calls
541 * IMarshal::DisconnectObject on the given object.
543 * Typically called when the object server is forced to shut down, for instance by
544 * the user.
546 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
548 FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved);
549 return S_OK;
552 /******************************************************************************
553 * CoCreateGuid[OLE32.@]
556 HRESULT WINAPI CoCreateGuid(
557 GUID *pguid /* [out] points to the GUID to initialize */
559 return UuidCreate(pguid);
562 /******************************************************************************
563 * CLSIDFromString [OLE32.@]
564 * IIDFromString [OLE32.@]
565 * Converts a unique identifier from its string representation into
566 * the GUID struct.
568 * UNDOCUMENTED
569 * If idstr is not a valid CLSID string then it gets treated as a ProgID
571 * RETURNS
572 * the converted GUID
574 HRESULT WINAPI __CLSIDFromStringA(
575 LPCSTR idstr, /* [in] string representation of guid */
576 CLSID *id) /* [out] GUID converted from string */
578 const BYTE *s = (BYTE *) idstr;
579 int i;
580 BYTE table[256];
582 if (!s)
583 s = "{00000000-0000-0000-0000-000000000000}";
584 else { /* validate the CLSID string */
586 if (strlen(s) != 38)
587 return CO_E_CLASSSTRING;
589 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
590 return CO_E_CLASSSTRING;
592 for (i=1; i<37; i++) {
593 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
594 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
595 ((s[i] >= 'a') && (s[i] <= 'f')) ||
596 ((s[i] >= 'A') && (s[i] <= 'F'))))
597 return CO_E_CLASSSTRING;
601 TRACE("%s -> %p\n", s, id);
603 /* quick lookup table */
604 memset(table, 0, 256);
606 for (i = 0; i < 10; i++) {
607 table['0' + i] = i;
609 for (i = 0; i < 6; i++) {
610 table['A' + i] = i+10;
611 table['a' + i] = i+10;
614 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
616 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
617 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
618 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
619 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
621 /* these are just sequential bytes */
622 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
623 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
624 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
625 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
626 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
627 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
628 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
629 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
631 return S_OK;
634 /*****************************************************************************/
636 HRESULT WINAPI CLSIDFromString(
637 LPOLESTR idstr, /* [in] string representation of GUID */
638 CLSID *id ) /* [out] GUID represented by above string */
640 char xid[40];
641 HRESULT ret;
643 if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
644 return CO_E_CLASSSTRING;
647 ret = __CLSIDFromStringA(xid,id);
648 if(ret != S_OK) { /* It appears a ProgID is also valid */
649 ret = CLSIDFromProgID(idstr, id);
651 return ret;
654 /******************************************************************************
655 * WINE_StringFromCLSID [Internal]
656 * Converts a GUID into the respective string representation.
658 * NOTES
660 * RETURNS
661 * the string representation and HRESULT
663 HRESULT WINE_StringFromCLSID(
664 const CLSID *id, /* [in] GUID to be converted */
665 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
667 static const char *hex = "0123456789ABCDEF";
668 char *s;
669 int i;
671 if (!id)
672 { ERR("called with id=Null\n");
673 *idstr = 0x00;
674 return E_FAIL;
677 sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
678 id->Data1, id->Data2, id->Data3,
679 id->Data4[0], id->Data4[1]);
680 s = &idstr[25];
682 /* 6 hex bytes */
683 for (i = 2; i < 8; i++) {
684 *s++ = hex[id->Data4[i]>>4];
685 *s++ = hex[id->Data4[i] & 0xf];
688 *s++ = '}';
689 *s++ = '\0';
691 TRACE("%p->%s\n", id, idstr);
693 return S_OK;
697 /******************************************************************************
698 * StringFromCLSID [OLE32.@]
699 * StringFromIID [OLE32.@]
700 * Converts a GUID into the respective string representation.
701 * The target string is allocated using the OLE IMalloc.
702 * RETURNS
703 * the string representation and HRESULT
705 HRESULT WINAPI StringFromCLSID(
706 REFCLSID id, /* [in] the GUID to be converted */
707 LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
709 char buf[80];
710 HRESULT ret;
711 LPMALLOC mllc;
713 if ((ret=CoGetMalloc(0,&mllc)))
714 return ret;
716 ret=WINE_StringFromCLSID(id,buf);
717 if (!ret) {
718 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
719 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
720 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
722 return ret;
725 /******************************************************************************
726 * StringFromGUID2 [COMPOBJ.76]
727 * StringFromGUID2 [OLE32.@]
729 * Converts a global unique identifier into a string of an API-
730 * specified fixed format. (The usual {.....} stuff.)
732 * RETURNS
733 * The (UNICODE) string representation of the GUID in 'str'
734 * The length of the resulting string, 0 if there was any problem.
736 INT WINAPI
737 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
739 char xguid[80];
741 if (WINE_StringFromCLSID(id,xguid))
742 return 0;
743 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
746 /******************************************************************************
747 * ProgIDFromCLSID [OLE32.@]
748 * Converts a class id into the respective Program ID. (By using a registry lookup)
749 * RETURNS S_OK on success
750 * riid associated with the progid
753 HRESULT WINAPI ProgIDFromCLSID(
754 REFCLSID clsid, /* [in] class id as found in registry */
755 LPOLESTR *lplpszProgID/* [out] associated Prog ID */
758 char strCLSID[50], *buf, *buf2;
759 DWORD buf2len;
760 HKEY xhkey;
761 LPMALLOC mllc;
762 HRESULT ret = S_OK;
764 WINE_StringFromCLSID(clsid, strCLSID);
766 buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
767 sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
768 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
769 ret = REGDB_E_CLASSNOTREG;
771 HeapFree(GetProcessHeap(), 0, buf);
773 if (ret == S_OK)
775 buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
776 buf2len = 255;
777 if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
778 ret = REGDB_E_CLASSNOTREG;
780 if (ret == S_OK)
782 if (CoGetMalloc(0,&mllc))
783 ret = E_OUTOFMEMORY;
784 else
786 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
787 *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
788 MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
791 HeapFree(GetProcessHeap(), 0, buf2);
794 RegCloseKey(xhkey);
795 return ret;
798 /******************************************************************************
799 * CLSIDFromProgID [COMPOBJ.61]
800 * Converts a program id into the respective GUID. (By using a registry lookup)
801 * RETURNS
802 * riid associated with the progid
804 HRESULT WINAPI CLSIDFromProgID16(
805 LPCOLESTR16 progid, /* [in] program id as found in registry */
806 LPCLSID riid /* [out] associated CLSID */
808 char *buf,buf2[80];
809 DWORD buf2len;
810 HRESULT err;
811 HKEY xhkey;
813 buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
814 sprintf(buf,"%s\\CLSID",progid);
815 if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
816 HeapFree(GetProcessHeap(),0,buf);
817 return CO_E_CLASSSTRING;
819 HeapFree(GetProcessHeap(),0,buf);
820 buf2len = sizeof(buf2);
821 if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
822 RegCloseKey(xhkey);
823 return CO_E_CLASSSTRING;
825 RegCloseKey(xhkey);
826 return __CLSIDFromStringA(buf2,riid);
829 /******************************************************************************
830 * CLSIDFromProgID [OLE32.@]
831 * Converts a program id into the respective GUID. (By using a registry lookup)
832 * RETURNS
833 * riid associated with the progid
835 HRESULT WINAPI CLSIDFromProgID(
836 LPCOLESTR progid, /* [in] program id as found in registry */
837 LPCLSID riid ) /* [out] associated CLSID */
839 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
840 char buf2[80];
841 DWORD buf2len = sizeof(buf2);
842 HKEY xhkey;
844 WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
845 strcpyW( buf, progid );
846 strcatW( buf, clsidW );
847 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
849 HeapFree(GetProcessHeap(),0,buf);
850 return CO_E_CLASSSTRING;
852 HeapFree(GetProcessHeap(),0,buf);
854 if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
856 RegCloseKey(xhkey);
857 return CO_E_CLASSSTRING;
859 RegCloseKey(xhkey);
860 return __CLSIDFromStringA(buf2,riid);
865 /*****************************************************************************
866 * CoGetPSClsid [OLE32.@]
868 * This function returns the CLSID of the proxy/stub factory that implements IPSFactoryBuffer
869 * for the specified interface.
871 * The standard marshaller activates the object with the CLSID returned and uses the
872 * CreateProxy and CreateStub methods on its IPSFactoryBuffer interface to construct
873 * the proxies and stubs for a given object.
875 * CoGetPSClsid determines this CLSID by searching the
876 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
877 * and any interface id registered by CoRegisterPSClsid within the current process.
879 * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
881 HRESULT WINAPI CoGetPSClsid(
882 REFIID riid, /* [in] Interface whose proxy/stub CLSID is to be returned */
883 CLSID *pclsid ) /* [out] Where to store returned proxy/stub CLSID */
885 char *buf, buf2[40];
886 DWORD buf2len;
887 HKEY xhkey;
889 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
891 /* Get the input iid as a string */
892 WINE_StringFromCLSID(riid, buf2);
893 /* Allocate memory for the registry key we will construct.
894 (length of iid string plus constant length of static text */
895 buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
896 if (buf == NULL)
898 return (E_OUTOFMEMORY);
901 /* Construct the registry key we want */
902 sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
904 /* Open the key.. */
905 if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
907 WARN("No PSFactoryBuffer object is registered for this IID\n");
908 HeapFree(GetProcessHeap(),0,buf);
909 return (E_INVALIDARG);
911 HeapFree(GetProcessHeap(),0,buf);
913 /* ... Once we have the key, query the registry to get the
914 value of CLSID as a string, and convert it into a
915 proper CLSID structure to be passed back to the app */
916 buf2len = sizeof(buf2);
917 if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
919 RegCloseKey(xhkey);
920 return E_INVALIDARG;
922 RegCloseKey(xhkey);
924 /* We have the CLSid we want back from the registry as a string, so
925 lets convert it into a CLSID structure */
926 if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) {
927 return E_INVALIDARG;
930 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
931 return (S_OK);
936 /***********************************************************************
937 * WriteClassStm (OLE32.@)
939 * This function write a CLSID on stream
941 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
943 TRACE("(%p,%p)\n",pStm,rclsid);
945 if (rclsid==NULL)
946 return E_INVALIDARG;
948 return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
951 /***********************************************************************
952 * ReadClassStm (OLE32.@)
954 * This function read a CLSID from a stream
956 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
958 ULONG nbByte;
959 HRESULT res;
961 TRACE("(%p,%p)\n",pStm,pclsid);
963 if (pclsid==NULL)
964 return E_INVALIDARG;
966 res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
968 if (FAILED(res))
969 return res;
971 if (nbByte != sizeof(CLSID))
972 return S_FALSE;
973 else
974 return S_OK;
978 /***
979 * COM_GetRegisteredClassObject
981 * This internal method is used to scan the registered class list to
982 * find a class object.
984 * Params:
985 * rclsid Class ID of the class to find.
986 * dwClsContext Class context to match.
987 * ppv [out] returns a pointer to the class object. Complying
988 * to normal COM usage, this method will increase the
989 * reference count on this object.
991 static HRESULT COM_GetRegisteredClassObject(
992 REFCLSID rclsid,
993 DWORD dwClsContext,
994 LPUNKNOWN* ppUnk)
996 HRESULT hr = S_FALSE;
997 RegisteredClass* curClass;
999 EnterCriticalSection( &csRegisteredClassList );
1002 * Sanity check
1004 assert(ppUnk!=0);
1007 * Iterate through the whole list and try to match the class ID.
1009 curClass = firstRegisteredClass;
1011 while (curClass != 0)
1014 * Check if we have a match on the class ID.
1016 if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1019 * Since we don't do out-of process or DCOM just right away, let's ignore the
1020 * class context.
1024 * We have a match, return the pointer to the class object.
1026 *ppUnk = curClass->classObject;
1028 IUnknown_AddRef(curClass->classObject);
1030 hr = S_OK;
1031 goto end;
1035 * Step to the next class in the list.
1037 curClass = curClass->nextClass;
1040 end:
1041 LeaveCriticalSection( &csRegisteredClassList );
1043 * If we get to here, we haven't found our class.
1045 return hr;
1048 static DWORD WINAPI
1049 _LocalServerThread(LPVOID param) {
1050 HANDLE hPipe;
1051 char pipefn[200];
1052 RegisteredClass *newClass = (RegisteredClass*)param;
1053 HRESULT hres;
1054 IStream *pStm;
1055 STATSTG ststg;
1056 unsigned char *buffer;
1057 int buflen;
1058 IClassFactory *classfac;
1059 LARGE_INTEGER seekto;
1060 ULARGE_INTEGER newpos;
1061 ULONG res;
1063 TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier));
1065 strcpy(pipefn,PIPEPREF);
1066 WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
1068 hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX,
1069 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1070 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL );
1071 if (hPipe == INVALID_HANDLE_VALUE) {
1072 FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError());
1073 return 1;
1075 while (1) {
1076 if (!ConnectNamedPipe(hPipe,NULL)) {
1077 ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
1078 break;
1081 TRACE("marshalling IClassFactory to client\n");
1083 hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac);
1084 if (hres) return hres;
1086 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1087 if (hres) {
1088 FIXME("Failed to create stream on hglobal.\n");
1089 return hres;
1091 hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0);
1092 if (hres) {
1093 FIXME("CoMarshalInterface failed, %lx!\n",hres);
1094 return hres;
1097 IUnknown_Release(classfac); /* is this right? */
1099 hres = IStream_Stat(pStm,&ststg,0);
1100 if (hres) return hres;
1102 buflen = ststg.cbSize.u.LowPart;
1103 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1104 seekto.u.LowPart = 0;
1105 seekto.u.HighPart = 0;
1106 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1107 if (hres) {
1108 FIXME("IStream_Seek failed, %lx\n",hres);
1109 return hres;
1112 hres = IStream_Read(pStm,buffer,buflen,&res);
1113 if (hres) {
1114 FIXME("Stream Read failed, %lx\n",hres);
1115 return hres;
1118 IStream_Release(pStm);
1120 WriteFile(hPipe,buffer,buflen,&res,NULL);
1121 FlushFileBuffers(hPipe);
1122 DisconnectNamedPipe(hPipe);
1124 TRACE("done marshalling IClassFactory\n");
1126 CloseHandle(hPipe);
1127 return 0;
1130 /******************************************************************************
1131 * CoRegisterClassObject [OLE32.@]
1133 * This method will register the class object for a given class ID. Servers housed
1134 * in EXE files use this method instead of exporting DllGetClassObject to allow other
1135 * code to connect to their objects.
1137 * When a class object (an object which implements IClassFactory) is registered in
1138 * this way, a new thread is started which listens for connections on a named pipe
1139 * specific to the registered CLSID. When something else connects to it, it writes
1140 * out the marshalled IClassFactory interface to the pipe. The code on the other end
1141 * uses this buffer to unmarshal the class factory, and can then call methods on it.
1143 * In Windows, such objects are registered with the RPC endpoint mapper, not with
1144 * a unique named pipe.
1146 * See the Windows documentation for more details.
1148 HRESULT WINAPI CoRegisterClassObject(
1149 REFCLSID rclsid,
1150 LPUNKNOWN pUnk,
1151 DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1152 DWORD flags, /* [in] REGCLS flags indicating how connections are made */
1153 LPDWORD lpdwRegister
1156 RegisteredClass* newClass;
1157 LPUNKNOWN foundObject;
1158 HRESULT hr;
1160 TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1161 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1163 if ( (lpdwRegister==0) || (pUnk==0) )
1164 return E_INVALIDARG;
1166 *lpdwRegister = 0;
1169 * First, check if the class is already registered.
1170 * If it is, this should cause an error.
1172 * MSDN claims that multiple interface registrations are legal, but we can't do that with
1173 * our current implementation.
1175 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1176 if (hr == S_OK) {
1177 IUnknown_Release(foundObject);
1178 return CO_E_OBJISREG;
1181 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1182 if ( newClass == NULL )
1183 return E_OUTOFMEMORY;
1185 EnterCriticalSection( &csRegisteredClassList );
1187 newClass->classIdentifier = *rclsid;
1188 newClass->runContext = dwClsContext;
1189 newClass->connectFlags = flags;
1191 * Use the address of the chain node as the cookie since we are sure it's
1192 * unique.
1194 newClass->dwCookie = (DWORD)newClass;
1195 newClass->nextClass = firstRegisteredClass;
1198 * Since we're making a copy of the object pointer, we have to increase its
1199 * reference count.
1201 newClass->classObject = pUnk;
1202 IUnknown_AddRef(newClass->classObject);
1204 firstRegisteredClass = newClass;
1205 LeaveCriticalSection( &csRegisteredClassList );
1207 *lpdwRegister = newClass->dwCookie;
1209 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1210 DWORD tid;
1212 STUBMGR_Start();
1213 newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
1215 return S_OK;
1218 /***********************************************************************
1219 * CoRevokeClassObject [OLE32.@]
1221 * This method will remove a class object from the class registry
1223 * See the Windows documentation for more details.
1225 HRESULT WINAPI CoRevokeClassObject(
1226 DWORD dwRegister)
1228 HRESULT hr = E_INVALIDARG;
1229 RegisteredClass** prevClassLink;
1230 RegisteredClass* curClass;
1232 TRACE("(%08lx)\n",dwRegister);
1234 EnterCriticalSection( &csRegisteredClassList );
1237 * Iterate through the whole list and try to match the cookie.
1239 curClass = firstRegisteredClass;
1240 prevClassLink = &firstRegisteredClass;
1242 while (curClass != 0)
1245 * Check if we have a match on the cookie.
1247 if (curClass->dwCookie == dwRegister)
1250 * Remove the class from the chain.
1252 *prevClassLink = curClass->nextClass;
1255 * Release the reference to the class object.
1257 IUnknown_Release(curClass->classObject);
1260 * Free the memory used by the chain node.
1262 HeapFree(GetProcessHeap(), 0, curClass);
1264 hr = S_OK;
1265 goto end;
1269 * Step to the next class in the list.
1271 prevClassLink = &(curClass->nextClass);
1272 curClass = curClass->nextClass;
1275 end:
1276 LeaveCriticalSection( &csRegisteredClassList );
1278 * If we get to here, we haven't found our class.
1280 return hr;
1283 /***********************************************************************
1284 * compobj_RegReadPath [internal]
1286 * Reads a registry value and expands it when necessary
1288 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, int dstlen)
1290 HRESULT hres;
1291 HKEY key;
1292 DWORD keytype;
1293 char src[MAX_PATH];
1294 DWORD dwLength = dstlen;
1296 if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1297 if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1298 if (keytype == REG_EXPAND_SZ) {
1299 if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1300 } else {
1301 strncpy(dst, src, dstlen);
1304 RegCloseKey (key);
1306 return hres;
1309 /***********************************************************************
1310 * CoGetClassObject [COMPOBJ.7]
1311 * CoGetClassObject [OLE32.@]
1313 * FIXME. If request allows of several options and there is a failure
1314 * with one (other than not being registered) do we try the
1315 * others or return failure? (E.g. inprocess is registered but
1316 * the DLL is not found but the server version works)
1318 HRESULT WINAPI CoGetClassObject(
1319 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1320 REFIID iid, LPVOID *ppv
1322 LPUNKNOWN regClassObject;
1323 HRESULT hres = E_UNEXPECTED;
1324 char xclsid[80];
1325 HINSTANCE hLibrary;
1326 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1327 DllGetClassObjectFunc DllGetClassObject;
1329 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1331 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1333 if (pServerInfo) {
1334 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1335 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1339 * First, try and see if we can't match the class ID with one of the
1340 * registered classes.
1342 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1345 * Get the required interface from the retrieved pointer.
1347 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1350 * Since QI got another reference on the pointer, we want to release the
1351 * one we already have. If QI was unsuccessful, this will release the object. This
1352 * is good since we are not returning it in the "out" parameter.
1354 IUnknown_Release(regClassObject);
1356 return hres;
1359 /* first try: in-process */
1360 if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1361 char keyname[MAX_PATH];
1362 char dllpath[MAX_PATH+1];
1364 sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1366 if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1367 /* failure: CLSID is not found in registry */
1368 WARN("class %s not registered inproc\n", xclsid);
1369 hres = REGDB_E_CLASSNOTREG;
1370 } else {
1371 if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1372 /* failure: DLL could not be loaded */
1373 ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1374 hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1375 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1376 /* failure: the dll did not export DllGetClassObject */
1377 ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1378 FreeLibrary( hLibrary );
1379 hres = CO_E_DLLNOTFOUND;
1380 } else {
1381 /* OK: get the ClassObject */
1382 COMPOBJ_DLLList_Add( hLibrary );
1383 return DllGetClassObject(rclsid, iid, ppv);
1388 /* Next try out of process */
1389 if (CLSCTX_LOCAL_SERVER & dwClsContext)
1391 return create_marshalled_proxy(rclsid,iid,ppv);
1394 /* Finally try remote: this requires networked DCOM (a lot of work) */
1395 if (CLSCTX_REMOTE_SERVER & dwClsContext)
1397 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1398 hres = E_NOINTERFACE;
1401 return hres;
1403 /***********************************************************************
1404 * CoResumeClassObjects (OLE32.@)
1406 * Resumes classobjects registered with REGCLS suspended
1408 HRESULT WINAPI CoResumeClassObjects(void)
1410 FIXME("stub\n");
1411 return S_OK;
1414 /***********************************************************************
1415 * GetClassFile (OLE32.@)
1417 * This function supplies the CLSID associated with the given filename.
1419 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1421 IStorage *pstg=0;
1422 HRESULT res;
1423 int nbElm, length, i;
1424 LONG sizeProgId;
1425 LPOLESTR *pathDec=0,absFile=0,progId=0;
1426 LPWSTR extension;
1427 static const WCHAR bkslashW[] = {'\\',0};
1428 static const WCHAR dotW[] = {'.',0};
1430 TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1432 /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1433 if((StgIsStorageFile(filePathName))==S_OK){
1435 res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1437 if (SUCCEEDED(res))
1438 res=ReadClassStg(pstg,pclsid);
1440 IStorage_Release(pstg);
1442 return res;
1444 /* if the file is not a storage object then attemps to match various bits in the file against a
1445 pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1446 this case
1448 for(i=0;i<nFileTypes;i++)
1450 for(i=0;j<nPatternsForType;j++){
1452 PATTERN pat;
1453 HANDLE hFile;
1455 pat=ReadPatternFromRegistry(i,j);
1456 hFile=CreateFileW(filePathName,,,,,,hFile);
1457 SetFilePosition(hFile,pat.offset);
1458 ReadFile(hFile,buf,pat.size,NULL,NULL);
1459 if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1461 *pclsid=ReadCLSIDFromRegistry(i);
1462 return S_OK;
1467 /* if the above strategies fail then search for the extension key in the registry */
1469 /* get the last element (absolute file) in the path name */
1470 nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1471 absFile=pathDec[nbElm-1];
1473 /* failed if the path represente a directory and not an absolute file name*/
1474 if (!lstrcmpW(absFile, bkslashW))
1475 return MK_E_INVALIDEXTENSION;
1477 /* get the extension of the file */
1478 extension = NULL;
1479 length=lstrlenW(absFile);
1480 for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1481 /* nothing */;
1483 if (!extension || !lstrcmpW(extension, dotW))
1484 return MK_E_INVALIDEXTENSION;
1486 res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1488 /* get the progId associated to the extension */
1489 progId = CoTaskMemAlloc(sizeProgId);
1490 res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1492 if (res==ERROR_SUCCESS)
1493 /* return the clsid associated to the progId */
1494 res= CLSIDFromProgID(progId,pclsid);
1496 for(i=0; pathDec[i]!=NULL;i++)
1497 CoTaskMemFree(pathDec[i]);
1498 CoTaskMemFree(pathDec);
1500 CoTaskMemFree(progId);
1502 if (res==ERROR_SUCCESS)
1503 return res;
1505 return MK_E_INVALIDEXTENSION;
1507 /***********************************************************************
1508 * CoCreateInstance [COMPOBJ.13]
1509 * CoCreateInstance [OLE32.@]
1511 HRESULT WINAPI CoCreateInstance(
1512 REFCLSID rclsid,
1513 LPUNKNOWN pUnkOuter,
1514 DWORD dwClsContext,
1515 REFIID iid,
1516 LPVOID *ppv)
1518 HRESULT hres;
1519 LPCLASSFACTORY lpclf = 0;
1522 * Sanity check
1524 if (ppv==0)
1525 return E_POINTER;
1528 * Initialize the "out" parameter
1530 *ppv = 0;
1533 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1534 * Rather than create a class factory, we can just check for it here
1536 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1537 if (StdGlobalInterfaceTableInstance == NULL)
1538 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1539 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1540 if (hres) return hres;
1542 TRACE("Retrieved GIT (%p)\n", *ppv);
1543 return S_OK;
1547 * Get a class factory to construct the object we want.
1549 hres = CoGetClassObject(rclsid,
1550 dwClsContext,
1551 NULL,
1552 &IID_IClassFactory,
1553 (LPVOID)&lpclf);
1555 if (FAILED(hres)) {
1556 FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1557 debugstr_guid(rclsid),hres);
1558 return hres;
1562 * Create the object and don't forget to release the factory
1564 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1565 IClassFactory_Release(lpclf);
1566 if(FAILED(hres))
1567 FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1568 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1570 return hres;
1573 /***********************************************************************
1574 * CoCreateInstanceEx [OLE32.@]
1576 HRESULT WINAPI CoCreateInstanceEx(
1577 REFCLSID rclsid,
1578 LPUNKNOWN pUnkOuter,
1579 DWORD dwClsContext,
1580 COSERVERINFO* pServerInfo,
1581 ULONG cmq,
1582 MULTI_QI* pResults)
1584 IUnknown* pUnk = NULL;
1585 HRESULT hr;
1586 ULONG index;
1587 int successCount = 0;
1590 * Sanity check
1592 if ( (cmq==0) || (pResults==NULL))
1593 return E_INVALIDARG;
1595 if (pServerInfo!=NULL)
1596 FIXME("() non-NULL pServerInfo not supported!\n");
1599 * Initialize all the "out" parameters.
1601 for (index = 0; index < cmq; index++)
1603 pResults[index].pItf = NULL;
1604 pResults[index].hr = E_NOINTERFACE;
1608 * Get the object and get its IUnknown pointer.
1610 hr = CoCreateInstance(rclsid,
1611 pUnkOuter,
1612 dwClsContext,
1613 &IID_IUnknown,
1614 (VOID**)&pUnk);
1616 if (hr)
1617 return hr;
1620 * Then, query for all the interfaces requested.
1622 for (index = 0; index < cmq; index++)
1624 pResults[index].hr = IUnknown_QueryInterface(pUnk,
1625 pResults[index].pIID,
1626 (VOID**)&(pResults[index].pItf));
1628 if (pResults[index].hr == S_OK)
1629 successCount++;
1633 * Release our temporary unknown pointer.
1635 IUnknown_Release(pUnk);
1637 if (successCount == 0)
1638 return E_NOINTERFACE;
1640 if (successCount!=cmq)
1641 return CO_S_NOTALLINTERFACES;
1643 return S_OK;
1646 /***********************************************************************
1647 * CoLoadLibrary (OLE32.@)
1649 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1651 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1653 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1656 /***********************************************************************
1657 * CoFreeLibrary [OLE32.@]
1659 * NOTES: don't believe the documentation
1661 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1663 FreeLibrary(hLibrary);
1667 /***********************************************************************
1668 * CoFreeAllLibraries [OLE32.@]
1670 * NOTES: don't believe the documentation
1672 void WINAPI CoFreeAllLibraries(void)
1674 /* NOP */
1678 /***********************************************************************
1679 * CoFreeUnusedLibraries [COMPOBJ.17]
1680 * CoFreeUnusedLibraries [OLE32.@]
1682 * FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1683 * through the main apartment's thread to call DllCanUnloadNow
1685 void WINAPI CoFreeUnusedLibraries(void)
1687 COMPOBJ_DllList_FreeUnused(0);
1690 /***********************************************************************
1691 * CoFileTimeNow [COMPOBJ.82]
1692 * CoFileTimeNow [OLE32.@]
1694 * RETURNS
1695 * the current system time in lpFileTime
1697 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1699 GetSystemTimeAsFileTime( lpFileTime );
1700 return S_OK;
1703 /***********************************************************************
1704 * CoLoadLibrary (OLE32.@)
1706 static void COM_RevokeAllClasses()
1708 EnterCriticalSection( &csRegisteredClassList );
1710 while (firstRegisteredClass!=0)
1712 CoRevokeClassObject(firstRegisteredClass->dwCookie);
1715 LeaveCriticalSection( &csRegisteredClassList );
1718 /****************************************************************************
1719 * COM External Lock methods implementation
1721 * This api provides a linked list to managed external references to
1722 * COM objects.
1724 * The public interface consists of three calls:
1725 * COM_ExternalLockAddRef
1726 * COM_ExternalLockRelease
1727 * COM_ExternalLockFreeList
1730 #define EL_END_OF_LIST 0
1731 #define EL_NOT_FOUND 0
1734 * Declaration of the static structure that manage the
1735 * external lock to COM objects.
1737 typedef struct COM_ExternalLock COM_ExternalLock;
1738 typedef struct COM_ExternalLockList COM_ExternalLockList;
1740 struct COM_ExternalLock
1742 IUnknown *pUnk; /* IUnknown referenced */
1743 ULONG uRefCount; /* external lock counter to IUnknown object*/
1744 COM_ExternalLock *next; /* Pointer to next element in list */
1747 struct COM_ExternalLockList
1749 COM_ExternalLock *head; /* head of list */
1753 * Declaration and initialization of the static structure that manages
1754 * the external lock to COM objects.
1756 static COM_ExternalLockList elList = { EL_END_OF_LIST };
1759 * Private methods used to managed the linked list
1763 static COM_ExternalLock* COM_ExternalLockLocate(
1764 COM_ExternalLock *element,
1765 IUnknown *pUnk);
1767 /****************************************************************************
1768 * Internal - Insert a new IUnknown* to the linked list
1770 static BOOL COM_ExternalLockInsert(
1771 IUnknown *pUnk)
1773 COM_ExternalLock *newLock = NULL;
1774 COM_ExternalLock *previousHead = NULL;
1777 * Allocate space for the new storage object
1779 newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1781 if (newLock!=NULL) {
1782 if ( elList.head == EL_END_OF_LIST ) {
1783 elList.head = newLock; /* The list is empty */
1784 } else {
1785 /* insert does it at the head */
1786 previousHead = elList.head;
1787 elList.head = newLock;
1790 /* Set new list item data member */
1791 newLock->pUnk = pUnk;
1792 newLock->uRefCount = 1;
1793 newLock->next = previousHead;
1795 return TRUE;
1797 return FALSE;
1800 /****************************************************************************
1801 * Internal - Method that removes an item from the linked list.
1803 static void COM_ExternalLockDelete(
1804 COM_ExternalLock *itemList)
1806 COM_ExternalLock *current = elList.head;
1808 if ( current == itemList ) {
1809 /* this section handles the deletion of the first node */
1810 elList.head = itemList->next;
1811 HeapFree( GetProcessHeap(), 0, itemList);
1812 } else {
1813 do {
1814 if ( current->next == itemList ){ /* We found the item to free */
1815 current->next = itemList->next; /* readjust the list pointers */
1816 HeapFree( GetProcessHeap(), 0, itemList);
1817 break;
1820 /* Skip to the next item */
1821 current = current->next;
1823 } while ( current != EL_END_OF_LIST );
1827 /****************************************************************************
1828 * Internal - Recursivity agent for IUnknownExternalLockList_Find
1830 * NOTES: how long can the list be ?? (recursive!!!)
1832 static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk)
1834 if ( element == EL_END_OF_LIST )
1835 return EL_NOT_FOUND;
1836 else if ( element->pUnk == pUnk ) /* We found it */
1837 return element;
1838 else /* Not the right guy, keep on looking */
1839 return COM_ExternalLockLocate( element->next, pUnk);
1842 /****************************************************************************
1843 * Public - Method that increments the count for a IUnknown* in the linked
1844 * list. The item is inserted if not already in the list.
1846 static void COM_ExternalLockAddRef(IUnknown *pUnk)
1848 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1851 * Add an external lock to the object. If it was already externally
1852 * locked, just increase the reference count. If it was not.
1853 * add the item to the list.
1855 if ( externalLock == EL_NOT_FOUND )
1856 COM_ExternalLockInsert(pUnk);
1857 else
1858 externalLock->uRefCount++;
1861 * Add an internal lock to the object
1863 IUnknown_AddRef(pUnk);
1866 /****************************************************************************
1867 * Public - Method that decrements the count for a IUnknown* in the linked
1868 * list. The item is removed from the list if its count end up at zero or if
1869 * bRelAll is TRUE.
1871 static void COM_ExternalLockRelease(
1872 IUnknown *pUnk,
1873 BOOL bRelAll)
1875 COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk);
1877 if ( externalLock != EL_NOT_FOUND ) {
1878 do {
1879 externalLock->uRefCount--; /* release external locks */
1880 IUnknown_Release(pUnk); /* release local locks as well */
1882 if ( bRelAll == FALSE ) break; /* perform single release */
1884 } while ( externalLock->uRefCount > 0 );
1886 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
1887 COM_ExternalLockDelete(externalLock);
1890 /****************************************************************************
1891 * Public - Method that frees the content of the list.
1893 static void COM_ExternalLockFreeList()
1895 COM_ExternalLock *head;
1897 head = elList.head; /* grab it by the head */
1898 while ( head != EL_END_OF_LIST ) {
1899 COM_ExternalLockDelete(head); /* get rid of the head stuff */
1900 head = elList.head; /* get the new head... */
1904 /****************************************************************************
1905 * Public - Method that dump the content of the list.
1907 void COM_ExternalLockDump()
1909 COM_ExternalLock *current = elList.head;
1911 DPRINTF("\nExternal lock list contains:\n");
1913 while ( current != EL_END_OF_LIST ) {
1914 DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount);
1916 /* Skip to the next item */
1917 current = current->next;
1921 /******************************************************************************
1922 * CoLockObjectExternal [OLE32.@]
1924 HRESULT WINAPI CoLockObjectExternal(
1925 LPUNKNOWN pUnk, /* [in] object to be locked */
1926 BOOL fLock, /* [in] do lock */
1927 BOOL fLastUnlockReleases) /* [in] unlock all */
1930 if (fLock) {
1932 * Increment the external lock coutner, COM_ExternalLockAddRef also
1933 * increment the object's internal lock counter.
1935 COM_ExternalLockAddRef( pUnk);
1936 } else {
1938 * Decrement the external lock coutner, COM_ExternalLockRelease also
1939 * decrement the object's internal lock counter.
1941 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1944 return S_OK;
1947 /***********************************************************************
1948 * CoInitializeWOW (OLE32.@)
1950 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1951 FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
1952 return 0;
1955 static int nStatCounter = 0; /* global */
1956 static HMODULE hOleAut32 = 0; /* global */
1958 /***********************************************************************
1959 * CoGetState [OLE32.@]
1961 * NOTES: might be incomplete
1963 HRESULT WINAPI CoGetState(IUnknown ** ppv)
1965 APARTMENT * apt = COM_CurrentInfo();
1967 FIXME("\n");
1969 if(apt && apt->state) {
1970 IUnknown_AddRef(apt->state);
1971 *ppv = apt->state;
1972 FIXME("-- %p\n", *ppv);
1973 return S_OK;
1975 *ppv = NULL;
1976 return E_FAIL;
1980 /***********************************************************************
1981 * CoSetState [OLE32.@]
1983 * NOTES: FIXME: protect this with a crst
1985 HRESULT WINAPI CoSetState(IUnknown * pv)
1987 APARTMENT * apt = COM_CurrentInfo();
1989 if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
1991 FIXME("(%p),stub!\n", pv);
1993 if (pv) {
1994 IUnknown_AddRef(pv);
1995 nStatCounter++;
1996 if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
1999 if (apt->state) {
2000 TRACE("-- release %p now\n", apt->state);
2001 IUnknown_Release(apt->state);
2002 nStatCounter--;
2003 if (!nStatCounter) FreeLibrary(hOleAut32);
2005 apt->state = pv;
2006 return S_OK;
2010 /******************************************************************************
2011 * OleGetAutoConvert [OLE32.@]
2013 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2015 HKEY hkey = 0;
2016 char buf[200];
2017 WCHAR wbuf[200];
2018 DWORD len;
2019 HRESULT res = S_OK;
2021 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2022 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2024 res = REGDB_E_CLASSNOTREG;
2025 goto done;
2027 len = 200;
2028 /* we can just query for the default value of AutoConvertTo key like that,
2029 without opening the AutoConvertTo key and querying for NULL (default) */
2030 if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2032 res = REGDB_E_KEYMISSING;
2033 goto done;
2035 MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2036 CLSIDFromString(wbuf,pClsidNew);
2037 done:
2038 if (hkey) RegCloseKey(hkey);
2039 return res;
2042 /******************************************************************************
2043 * OleSetAutoConvert [OLE32.@]
2045 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2047 HKEY hkey = 0;
2048 char buf[200], szClsidNew[200];
2049 HRESULT res = S_OK;
2051 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2052 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2053 WINE_StringFromCLSID(clsidNew, szClsidNew);
2054 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2056 res = REGDB_E_CLASSNOTREG;
2057 goto done;
2059 if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2061 res = REGDB_E_WRITEREGDB;
2062 goto done;
2065 done:
2066 if (hkey) RegCloseKey(hkey);
2067 return res;
2070 /******************************************************************************
2071 * OleDoAutoConvert [OLE32.@]
2073 HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
2075 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2076 return E_NOTIMPL;
2079 /******************************************************************************
2080 * CoTreatAsClass [OLE32.@]
2082 * Sets TreatAs value of a class
2084 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2086 HKEY hkey = 0;
2087 char buf[47];
2088 char szClsidNew[39];
2089 HRESULT res = S_OK;
2090 char auto_treat_as[39];
2091 LONG auto_treat_as_size = sizeof(auto_treat_as);
2092 CLSID id;
2094 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2095 WINE_StringFromCLSID(clsidNew, szClsidNew);
2096 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2098 res = REGDB_E_CLASSNOTREG;
2099 goto done;
2101 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2103 if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2104 !__CLSIDFromStringA(auto_treat_as, &id))
2106 if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2108 res = REGDB_E_WRITEREGDB;
2109 goto done;
2112 else
2114 RegDeleteKeyA(hkey, "TreatAs");
2115 goto done;
2118 else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2120 res = REGDB_E_WRITEREGDB;
2121 goto done;
2124 done:
2125 if (hkey) RegCloseKey(hkey);
2126 return res;
2129 /******************************************************************************
2130 * CoGetTreatAsClass [OLE32.@]
2132 * Reads the TreatAs value from a class.
2134 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2136 HKEY hkey = 0;
2137 char buf[200], szClsidNew[200];
2138 HRESULT res = S_OK;
2139 LONG len = sizeof(szClsidNew);
2141 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2142 sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2143 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2145 if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2147 res = REGDB_E_CLASSNOTREG;
2148 goto done;
2150 if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2152 res = S_FALSE;
2153 goto done;
2155 res = __CLSIDFromStringA(szClsidNew,clsidNew);
2156 if (FAILED(res))
2157 FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2158 done:
2159 if (hkey) RegCloseKey(hkey);
2160 return res;
2164 /***********************************************************************
2165 * IsEqualGUID [OLE32.@]
2167 * Compares two Unique Identifiers.
2169 * RETURNS
2170 * TRUE if equal
2172 #undef IsEqualGUID
2173 BOOL WINAPI IsEqualGUID(
2174 REFGUID rguid1, /* [in] unique id 1 */
2175 REFGUID rguid2 /* [in] unique id 2 */
2178 return !memcmp(rguid1,rguid2,sizeof(GUID));
2181 /***********************************************************************
2182 * CoInitializeSecurity [OLE32.@]
2184 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2185 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2186 void* pReserved1, DWORD dwAuthnLevel,
2187 DWORD dwImpLevel, void* pReserved2,
2188 DWORD dwCapabilities, void* pReserved3)
2190 FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2191 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2192 dwCapabilities, pReserved3);
2193 return S_OK;