source: trunk/src/ole32/ole32.cpp@ 633

Last change on this file since 633 was 633, checked in by sandervl, 26 years ago

Changes for updated Wine headers (NOT TESTED..)

File size: 20.6 KB
Line 
1/*
2 *
3 * Project Odin Software License can be found in LICENSE.TXT
4 *
5 */
6/*
7 * COM/OLE misc. functions.
8 *
9 * 1/7/99
10 *
11 * Copyright 1999 David J. Raison
12 *
13 * Some portions from Wine Implementation
14 * Copyright 1995 Martin von Loewis
15 * Copyright 1998 Justin Bradford
16 * Copyright 1999 Francis Beaudet
17 * Copyright 1999 Sylvain St-Germain
18 */
19
20#include "ole32.h"
21
22#include "oString.h"
23#include "moniker.h" // RunningObjectTableImpl_***
24
25// ======================================================================
26// Local Data
27// ======================================================================
28typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
29
30/*
31 * This linked list contains the list of registered class objects. These
32 * are mostly used to register the factories for out-of-proc servers of OLE
33 * objects.
34 */
35typedef struct tagRegisteredClass
36{
37 CLSID classIdentifier;
38 LPUNKNOWN classObject;
39 DWORD runContext;
40 DWORD connectFlags;
41 DWORD dwCookie;
42 struct tagRegisteredClass* nextClass;
43} RegisteredClass;
44
45static RegisteredClass* firstRegisteredClass = NULL;
46
47/*
48 * COM External Lock structures and methods declaration
49 *
50 * This api provides a linked list to managed external references to
51 * COM objects.
52 *
53 */
54
55#define EL_END_OF_LIST 0
56#define EL_NOT_FOUND 0
57
58/*
59 * Declaration of the static structure that manage the
60 * external lock to COM objects.
61 */
62typedef struct COM_ExternalLock COM_ExternalLock;
63typedef struct COM_ExternalLockList COM_ExternalLockList;
64
65struct COM_ExternalLock
66{
67 IUnknown *pUnk; /* IUnknown referenced */
68 ULONG uRefCount; /* external lock counter to IUnknown object*/
69 COM_ExternalLock *next; /* Pointer to next element in list */
70};
71
72struct COM_ExternalLockList
73{
74 COM_ExternalLock *head; /* head of list */
75};
76
77/*
78 * Declaration and initialization of the static structure that manages
79 * the external lock to COM objects.
80 */
81static COM_ExternalLockList elList = { EL_END_OF_LIST };
82
83/*
84 * This open DLL table belongs in a per process table, but my guess is that
85 * it shouldn't live in the kernel, so I'll put them out here in DLL
86 * space assuming that there is one OLE32 per process.
87 */
88typedef struct tagOpenDll
89{
90 char * DllName; /* really only needed for debugging */
91 HINSTANCE hLibrary;
92 struct tagOpenDll * next;
93} OpenDll;
94
95static OpenDll * openDllList = NULL; /* linked list of open dlls */
96
97/*
98 * Com Library reference count...
99 *
100 * Used to control loading / unloading of Library resources,
101 * Runnng object table, DLL's etc...
102 */
103static LONG COM_ref = 0;
104
105// ======================================================================
106// Prototypes.
107// ======================================================================
108static HRESULT COM_GetRegisteredClassObject(
109 REFCLSID rclsid,
110 DWORD dwClsContext,
111 LPUNKNOWN * ppUnk);
112
113static void COM_RevokeAllClasses();
114
115static void COM_ExternalLockFreeList();
116
117static void COM_ExternalLockAddRef(
118 IUnknown * pUnk);
119
120static void COM_ExternalLockRelease(
121 IUnknown * pUnk,
122 BOOL bRelAll);
123
124static BOOL COM_ExternalLockInsert(
125 IUnknown * pUnk);
126
127static void COM_ExternalLockDelete(
128 COM_ExternalLock * element);
129
130static COM_ExternalLock * COM_ExternalLockFind(
131 IUnknown * pUnk);
132
133static COM_ExternalLock * COM_ExternalLockLocate(
134 COM_ExternalLock * element,
135 IUnknown * pUnk);
136
137// ======================================================================
138// Public API's
139// ======================================================================
140
141// ----------------------------------------------------------------------
142// CoBuildVersion()
143// ----------------------------------------------------------------------
144DWORD WIN32API CoBuildVersion()
145{
146 dprintf(("OLE32.CoBuildVersion\n"));
147 return (rmm << 16) + rup;
148}
149
150// ----------------------------------------------------------------------
151// CoDosDateTimeToFileTime
152// ----------------------------------------------------------------------
153BOOL WIN32API CoDosDateTimeToFileTime(WORD nDosDate, WORD nDosTime,
154 FILETIME *lpFileTime)
155{
156 dprintf(("OLE32: CoDosDateTimeToFileTime"));
157
158 return DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
159}
160
161// ----------------------------------------------------------------------
162// CoDosDateTimeToFileTime
163// ----------------------------------------------------------------------
164HRESULT WIN32API CoFileTimeNow(FILETIME *lpFileTime)
165{
166 SYSTEMTIME systime;
167
168 dprintf(("OLE32: CoFileTimeNow"));
169
170 GetSystemTime(&systime);
171 return SystemTimeToFileTime(&systime, lpFileTime);
172}
173
174// ----------------------------------------------------------------------
175// CoDosDateTimeToFileTime
176// ----------------------------------------------------------------------
177BOOL WIN32API CoFileTimeToDosDateTime(FILETIME *lpFileTime, LPWORD lpDosDate,
178 LPWORD lpDosTime)
179{
180 dprintf(("OLE32: CoFileTimeToDosDateTime"));
181
182 return FileTimeToDosDateTime(lpFileTime, lpDosDate, lpDosTime);
183}
184
185// ----------------------------------------------------------------------
186// CoInitialize()
187// ----------------------------------------------------------------------
188HRESULT WIN32API CoInitialize(LPVOID lpReserved)
189{
190 dprintf(("OLE32: CoInitialize\n"));
191
192 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
193}
194
195// ----------------------------------------------------------------------
196// CoInitializeEx()
197// ----------------------------------------------------------------------
198HRESULT WIN32API CoInitializeEx(
199 LPVOID lpReserved, // [in] pointer to win32 malloc interface
200 DWORD dwCoInit) // [in] A value from COINIT specifies the thread
201{
202 HRESULT hr;
203
204 dprintf(("OLE32: CoInitializeEx(%p, %lx)\n", lpReserved, dwCoInit));
205
206 if (lpReserved != NULL)
207 {
208 dprintf(("Warning: Bad parameter %p, must be an old Windows Application", lpReserved));
209 }
210
211 /*
212 * Check for unsupported features.
213 */
214 if (dwCoInit != COINIT_APARTMENTTHREADED)
215 {
216 dprintf(("Warning: Unsupported flag %lx", dwCoInit));
217 /* Hope for the best and continue anyway */
218 }
219
220 /*
221 * Initialise the Running Object Table
222 */
223 hr = S_FALSE;
224 if (++COM_ref == 1)
225 {
226 hr = RunningObjectTableImpl_Initialize();
227 if (hr != S_OK)
228 --COM_ref;
229 }
230
231 return hr;
232}
233
234// ----------------------------------------------------------------------
235// CoUninitialize()
236// ----------------------------------------------------------------------
237void WIN32API CoUninitialize(void)
238{
239 dprintf(("OLE32: CoUninitialize"));
240
241 if (--COM_ref == 0)
242 {
243 dprintf(("OLE32: Releasing COM libraries"));
244
245 RunningObjectTableImpl_UnInitialize();
246
247 COM_RevokeAllClasses();
248
249 CoFreeAllLibraries();
250
251 COM_ExternalLockFreeList();
252 }
253}
254
255// ----------------------------------------------------------------------
256// CoCreateInstance
257// ----------------------------------------------------------------------
258HRESULT WIN32API CoCreateInstance
259 (REFCLSID rclsid,
260 LPUNKNOWN pUnkOuter,
261 DWORD dwClsContext,
262 REFIID iid,
263 LPVOID * ppv)
264{
265 HRESULT hres;
266 LPCLASSFACTORY lpclf = 0;
267
268 oStringA tCLSID(rclsid);
269 oStringA tIId(iid);
270
271 dprintf(("OLE32: CoCreateInstance"));
272 dprintf((" CLSID:%s", (char *)tCLSID));
273 dprintf((" IID :%s", (char *)tIId));
274
275 // Sanity check
276 if (ppv == 0)
277 return E_POINTER;
278
279 *ppv = 0;
280
281 // Get a class factory to construct the object we want.
282 hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID *)&lpclf);
283
284 if (FAILED(hres))
285 return hres;
286
287 // Create the object and don't forget to release the factory
288 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
289 IClassFactory_Release(lpclf);
290
291 return hres;
292}
293
294// ----------------------------------------------------------------------
295// CoCreateInstanceEx
296// ----------------------------------------------------------------------
297HRESULT WIN32API CoCreateInstanceEx
298 (REFCLSID rclsid,
299 LPUNKNOWN pUnkOuter,
300 DWORD dwClsContext,
301 COSERVERINFO * pServerInfo,
302 ULONG cmq,
303 MULTI_QI * pResults)
304{
305 IUnknown * pUnk = NULL;
306 HRESULT hr;
307 ULONG index;
308 int successCount = 0;
309
310 oStringA tCLSID(rclsid);
311
312 dprintf(("OLE32: CoCreateInstanceEx"));
313 dprintf((" CLSID:%s", (char *)tCLSID));
314
315 // Sanity check
316 if ( (cmq == 0) || (pResults == NULL))
317 return E_INVALIDARG;
318
319 if (pServerInfo != NULL)
320 dprintf(("OLE32: CoCreateInstanceEx - pServerInfo not supported!"));
321
322 // Initialize all the "out" parameters.
323 for (index = 0; index < cmq; index++)
324 {
325 pResults[index].pItf = NULL;
326 pResults[index].hr = E_NOINTERFACE;
327 }
328
329 /*
330 * Get the object and get it's IUnknown pointer.
331 */
332 hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, &IID_IUnknown, (VOID**)&pUnk);
333
334 if (hr)
335 return hr;
336
337 /*
338 * Then, query for all the interfaces requested.
339 */
340 for (index = 0; index < cmq; index++)
341 {
342 pResults[index].hr = IUnknown_QueryInterface(pUnk, pResults[index].pIID, (VOID**)&(pResults[index].pItf));
343
344 if (pResults[index].hr == S_OK)
345 successCount++;
346 }
347
348 /*
349 * Release our temporary unknown pointer.
350 */
351 IUnknown_Release(pUnk);
352
353 if (successCount == 0)
354 return E_NOINTERFACE;
355
356 if (successCount != cmq)
357 return CO_S_NOTALLINTERFACES;
358
359 return S_OK;
360}
361
362// ----------------------------------------------------------------------
363// CoGetClassObject
364// ----------------------------------------------------------------------
365HRESULT WIN32API CoGetClassObject
366 (REFCLSID rclsid,
367 DWORD dwClsContext,
368 LPVOID pvReserved,
369 REFIID iid,
370 LPVOID * ppv)
371{
372 LPUNKNOWN regClassObject;
373 HRESULT hres = E_UNEXPECTED;
374
375 char dllName[MAX_PATH+1];
376 LONG dllNameLen = sizeof(dllName);
377 HINSTANCE hLibrary;
378
379 DllGetClassObjectFunc DllGetClassObject;
380 oStringA tCLSID(rclsid);
381
382#ifdef DEBUG
383 oStringA tIId(iid);
384 dprintf(("OLE32: CoGetClassObject"));
385 dprintf((" CLSID:%s", (char *)tCLSID));
386 dprintf((" IID :%s", (char *)tIId));
387#endif
388
389 // First, try and see if we can't match the class ID with one of the
390 // registered classes.
391 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
392 {
393 // Get the required interface from the retrieved pointer.
394 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
395
396 // Since QI got another reference on the pointer, we want to release the
397 // one we already have. If QI was unsuccessful, this will release the object. This
398 // is good since we are not returning it in the "out" parameter.
399 IUnknown_Release(regClassObject);
400
401 return hres;
402 }
403
404 // out of process and remote servers not supported yet...
405 if (dwClsContext & CLSCTX_LOCAL_SERVER)
406 {
407 dprintf(("OLE32: CoGetClassObject - CLSCTX_LOCAL_SERVER not supported!\n"));
408 return E_ACCESSDENIED;
409 }
410
411 if (dwClsContext & CLSCTX_REMOTE_SERVER)
412 {
413 dprintf(("OLE32: CoGetClassObject - CLSCTX_REMOTE_SERVER not supported!\n"));
414 return E_ACCESSDENIED;
415 }
416
417 // Get down to the biz..
418 if (dwClsContext & (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER))
419 {
420 HKEY CLSIDkey;
421 HKEY key;
422
423 /* lookup CLSID in registry key HKCR/CLSID */
424 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &CLSIDkey);
425 if (hres != ERROR_SUCCESS)
426 return REGDB_E_READREGDB;
427
428 hres = RegOpenKeyExA(CLSIDkey, tCLSID, 0, KEY_QUERY_VALUE, &key);
429 if (hres != ERROR_SUCCESS)
430 {
431 RegCloseKey(CLSIDkey);
432 return REGDB_E_CLASSNOTREG;
433 }
434
435 hres = RegQueryValueA(key, "InprocServer32", dllName, &dllNameLen);
436 RegCloseKey(key);
437 RegCloseKey(CLSIDkey);
438 if (hres != ERROR_SUCCESS)
439 {
440 dprintf(("OLE32: CoGetClassObject - InprocServer32 not found in registry"));
441 return REGDB_E_READREGDB;
442 }
443
444 dprintf(("OLE32: CoGetClassObject - Registry reports InprocServer32 dll as %s\n", dllName));
445
446 /* open dll, call DllGetClassFactory */
447 hLibrary = CoLoadLibrary(dllName, TRUE);
448 if (hLibrary == 0)
449 {
450 dprintf(("OLE32: CoGetClassObject - couldn't load %s\n", dllName));
451 return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
452 }
453
454 DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
455 if (!DllGetClassObject)
456 {
457 dprintf(("OLE32: CoGetClassObject - couldn't function DllGetClassObject in %s\n", dllName));
458 /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
459 return E_ACCESSDENIED;
460 }
461
462 // Ask the DLL for it's class object. (there was a note here about class
463 // factories but this is good.
464 return DllGetClassObject(rclsid, iid, ppv);
465 }
466 return hres;
467}
468
469// ======================================================================
470// Private functions.
471// ======================================================================
472
473// ----------------------------------------------------------------------
474// COM_GetRegisteredClassObject
475// ----------------------------------------------------------------------
476// This internal method is used to scan the registered class list to
477// find a class object.
478//
479// Params:
480// rclsid Class ID of the class to find.
481// dwClsContext Class context to match.
482// ppv [out] returns a pointer to the class object. Complying
483// to normal COM usage, this method will increase the
484// reference count on this object.
485static HRESULT COM_GetRegisteredClassObject
486 (REFCLSID rclsid,
487 DWORD dwClsContext,
488 LPUNKNOWN * ppUnk)
489{
490 RegisteredClass* curClass;
491
492 oStringA tCLSID(rclsid);
493
494 dprintf(("OLE32: COM_GetRegisteredClassObject"));
495 dprintf((" CLSID:%s", (char *)tCLSID));
496
497 // Sanity check
498 if (ppUnk == 0)
499 return E_POINTER;
500
501 // Iterate through the whole list and try to match the class ID.
502 curClass = firstRegisteredClass;
503
504 while (curClass != 0)
505 {
506 // Check if we have a match on the class ID.
507 if (IsEqualGUID(&curClass->classIdentifier, &rclsid))
508 {
509 // Since we don't do out-of process or DCOM just right away,
510 // let's ignore the class context.
511
512 // We have a match, return the pointer to the class object.
513 *ppUnk = curClass->classObject;
514
515 IUnknown_AddRef(curClass->classObject);
516
517 return S_OK;
518 }
519
520 // Step to the next class in the list.
521 curClass = curClass->nextClass;
522 }
523
524 // If we get to here, we haven't found our class.
525 return S_FALSE;
526}
527
528// ----------------------------------------------------------------------
529// COM_RevokeAllClasses
530// ----------------------------------------------------------------------
531// This method is called when the COM libraries are uninitialized to
532// release all the references to the class objects registered with
533// the library
534static void COM_RevokeAllClasses()
535{
536 dprintf(("OLE32: COM_RevokeAllClasses"));
537
538 while (firstRegisteredClass != 0)
539 {
540 CoRevokeClassObject(firstRegisteredClass->dwCookie);
541 }
542}
543
544// ----------------------------------------------------------------------
545// COM_ExternalLockAddRef
546// ----------------------------------------------------------------------
547// Method that increments the count for a IUnknown* in the linked
548// list. The item is inserted if not already in the list.
549static void COM_ExternalLockAddRef(IUnknown * pUnk)
550{
551 dprintf(("OLE32: COM_ExternalLockAddRef"));
552
553 COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
554
555 /*
556 * Add an external lock to the object. If it was already externally
557 * locked, just increase the reference count. If it was not.
558 * add the item to the list.
559 */
560 if ( externalLock == EL_NOT_FOUND )
561 COM_ExternalLockInsert(pUnk);
562 else
563 externalLock->uRefCount++;
564
565 /*
566 * Add an internal lock to the object
567 */
568 IUnknown_AddRef(pUnk);
569}
570
571// ----------------------------------------------------------------------
572// COM_ExternalLockRelease
573// ----------------------------------------------------------------------
574// Method that decrements the count for a IUnknown* in the linked
575// list. The item is removed from the list if its count end up at zero or if
576// bRelAll is TRUE.
577static void COM_ExternalLockRelease(IUnknown * pUnk, BOOL bRelAll)
578{
579 dprintf(("OLE32: COM_ExternalLockRelease"));
580
581 COM_ExternalLock * externalLock = COM_ExternalLockFind(pUnk);
582
583 if ( externalLock != EL_NOT_FOUND )
584 {
585 do
586 {
587 externalLock->uRefCount--; /* release external locks */
588 IUnknown_Release(pUnk); /* release local locks as well */
589
590 if ( bRelAll == FALSE )
591 break; /* perform single release */
592
593 } while ( externalLock->uRefCount > 0 );
594
595 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
596 COM_ExternalLockDelete(externalLock);
597 }
598}
599
600// ----------------------------------------------------------------------
601// COM_ExternalLockFreeList
602// ----------------------------------------------------------------------
603// Method that frees the content of the list.
604static void COM_ExternalLockFreeList()
605{
606 dprintf(("OLE32: COM_ExternalLockFreeList"));
607
608 COM_ExternalLock *head;
609
610 head = elList.head; /* grab it by the head */
611 while (head != EL_END_OF_LIST)
612 {
613 COM_ExternalLockDelete(head); /* get rid of the head stuff */
614
615 head = elList.head; /* get the new head... */
616 }
617}
618
619// ----------------------------------------------------------------------
620// COM_ExternalLockDump
621// ----------------------------------------------------------------------
622// Method that dump the content of the list.
623void COM_ExternalLockDump()
624{
625 dprintf(("OLE32: COM_ExternalLockDump"));
626
627 COM_ExternalLock *current = elList.head;
628
629 printf("External lock list:");
630
631 while ( current != EL_END_OF_LIST )
632 {
633 dprintf((" %p with %lu references count.\n", current->pUnk, current->uRefCount));
634
635 /* Skip to the next item */
636 current = current->next;
637 }
638}
639
640// ----------------------------------------------------------------------
641// COM_ExternalLockFind
642// ----------------------------------------------------------------------
643// Find a IUnknown* in the linked list
644static COM_ExternalLock * COM_ExternalLockFind(IUnknown *pUnk)
645{
646 dprintf(("OLE32: COM_ExternalLockFind"));
647
648 return COM_ExternalLockLocate(elList.head, pUnk);
649}
650
651// ----------------------------------------------------------------------
652// COM_ExternalLockLocate
653// ----------------------------------------------------------------------
654// Recursivity agent for IUnknownExternalLockList_Find
655static COM_ExternalLock * COM_ExternalLockLocate( COM_ExternalLock * element, IUnknown * pUnk)
656{
657 if ( element == EL_END_OF_LIST )
658 return EL_NOT_FOUND;
659
660 else if ( element->pUnk == pUnk ) /* We found it */
661 return element;
662
663 else /* Not the right guy, keep on looking */
664 return COM_ExternalLockLocate( element->next, pUnk);
665}
666
667// ----------------------------------------------------------------------
668// COM_ExternalLockInsert
669// ----------------------------------------------------------------------
670// Insert a new IUnknown* to the linked list
671static BOOL COM_ExternalLockInsert(IUnknown * pUnk)
672{
673 dprintf(("OLE32: COM_ExternalLockInsert"));
674
675 COM_ExternalLock * newLock = NULL;
676 COM_ExternalLock * previousHead = NULL;
677
678 // Allocate space for the new storage object
679 newLock = (COM_ExternalLock *)HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
680
681 if (newLock != NULL)
682 {
683 if ( elList.head == EL_END_OF_LIST )
684 elList.head = newLock; /* The list is empty */
685 else
686 {
687 // insert does it at the head
688 previousHead = elList.head;
689 elList.head = newLock;
690 }
691
692 /*
693 * Set new list item data member
694 */
695 newLock->pUnk = pUnk;
696 newLock->uRefCount = 1;
697 newLock->next = previousHead;
698
699 return TRUE;
700 }
701
702 return FALSE;
703}
704
705// ----------------------------------------------------------------------
706// ExternalLockDelete
707// ----------------------------------------------------------------------
708// Method that removes an item from the linked list.
709static void COM_ExternalLockDelete(COM_ExternalLock * itemList)
710{
711 dprintf(("OLE32: ExternalLockDelete"));
712
713 COM_ExternalLock *current = elList.head;
714
715 if ( current == itemList )
716 {
717 // this section handles the deletion of the first node
718 elList.head = itemList->next;
719 HeapFree( GetProcessHeap(), 0, itemList);
720 }
721 else
722 {
723 do
724 {
725 if ( current->next == itemList ) /* We found the item to free */
726 {
727 current->next = itemList->next; /* readjust the list pointers */
728
729 HeapFree( GetProcessHeap(), 0, itemList);
730 break;
731 }
732
733 /* Skip to the next item */
734 current = current->next;
735
736 } while ( current != EL_END_OF_LIST );
737 }
738}
Note: See TracBrowser for help on using the repository browser.