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

Last change on this file since 1036 was 1033, checked in by davidr, 26 years ago

Ported remaining files pertaining to OLE32 from WINE

File size: 26.2 KB
Line 
1/* $Id: ole32.cpp,v 1.11 1999-09-24 21:49:43 davidr Exp $ */
2/*
3 *
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 */
7/*
8 * COM/OLE misc. functions.
9 *
10 * 1/7/99
11 *
12 * Copyright 1999 David J. Raison
13 *
14 * Some portions from Wine Implementation
15 * Copyright 1995 Martin von Loewis
16 * Copyright 1998 Justin Bradford
17 * Copyright 1999 Francis Beaudet
18 * Copyright 1999 Sylvain St-Germain
19 */
20
21#include "ole32.h"
22
23#include "oString.h"
24#include "moniker.h" // RunningObjectTableImpl_***
25#include "filemoniker.h" // FileMonikerImpl_***
26
27// ======================================================================
28// Local Data
29// ======================================================================
30typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
31
32/*
33 * This linked list contains the list of registered class objects. These
34 * are mostly used to register the factories for out-of-proc servers of OLE
35 * objects.
36 */
37typedef struct tagRegisteredClass
38{
39 CLSID classIdentifier;
40 LPUNKNOWN classObject;
41 DWORD runContext;
42 DWORD connectFlags;
43 DWORD dwCookie;
44 struct tagRegisteredClass* nextClass;
45} RegisteredClass;
46
47static RegisteredClass* firstRegisteredClass = NULL;
48
49/*
50 * COM External Lock structures and methods declaration
51 *
52 * This api provides a linked list to managed external references to
53 * COM objects.
54 *
55 */
56
57#define EL_END_OF_LIST 0
58#define EL_NOT_FOUND 0
59
60/*
61 * Declaration of the static structure that manage the
62 * external lock to COM objects.
63 */
64typedef struct COM_ExternalLock COM_ExternalLock;
65typedef struct COM_ExternalLockList COM_ExternalLockList;
66
67struct COM_ExternalLock
68{
69 IUnknown *pUnk; /* IUnknown referenced */
70 ULONG uRefCount; /* external lock counter to IUnknown object*/
71 COM_ExternalLock *next; /* Pointer to next element in list */
72};
73
74struct COM_ExternalLockList
75{
76 COM_ExternalLock *head; /* head of list */
77};
78
79/*
80 * Declaration and initialization of the static structure that manages
81 * the external lock to COM objects.
82 */
83static COM_ExternalLockList elList = { EL_END_OF_LIST };
84
85/*
86 * Com Library reference count...
87 *
88 * Used to control loading / unloading of Library resources,
89 * Runnng object table, DLL's etc...
90 */
91static LONG COM_ref = 0;
92
93// ======================================================================
94// Prototypes.
95// ======================================================================
96static HRESULT COM_GetRegisteredClassObject(
97 REFCLSID rclsid,
98 DWORD dwClsContext,
99 LPUNKNOWN * ppUnk);
100
101static void COM_RevokeAllClasses();
102
103static void COM_ExternalLockFreeList();
104
105static void COM_ExternalLockAddRef(
106 IUnknown * pUnk);
107
108static void COM_ExternalLockRelease(
109 IUnknown * pUnk,
110 BOOL bRelAll);
111
112static BOOL COM_ExternalLockInsert(
113 IUnknown * pUnk);
114
115static void COM_ExternalLockDelete(
116 COM_ExternalLock * element);
117
118static COM_ExternalLock * COM_ExternalLockFind(
119 IUnknown * pUnk);
120
121static COM_ExternalLock * COM_ExternalLockLocate(
122 COM_ExternalLock * element,
123 IUnknown * pUnk);
124
125// ======================================================================
126// Public API's
127// ======================================================================
128
129// ----------------------------------------------------------------------
130// CoBuildVersion()
131// ----------------------------------------------------------------------
132DWORD WIN32API CoBuildVersion()
133{
134 dprintf(("OLE32.CoBuildVersion"));
135 return (rmm << 16) + rup;
136}
137
138// ----------------------------------------------------------------------
139// CoDosDateTimeToFileTime
140// ----------------------------------------------------------------------
141BOOL WIN32API CoDosDateTimeToFileTime(WORD nDosDate, WORD nDosTime,
142 FILETIME *lpFileTime)
143{
144 dprintf(("OLE32: CoDosDateTimeToFileTime"));
145
146 return DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
147}
148
149// ----------------------------------------------------------------------
150// CoDosDateTimeToFileTime
151// ----------------------------------------------------------------------
152HRESULT WIN32API CoFileTimeNow(FILETIME *lpFileTime)
153{
154 SYSTEMTIME systime;
155
156 dprintf(("OLE32: CoFileTimeNow"));
157
158 GetSystemTime(&systime);
159 return SystemTimeToFileTime(&systime, lpFileTime);
160}
161
162// ----------------------------------------------------------------------
163// CoDosDateTimeToFileTime
164// ----------------------------------------------------------------------
165BOOL WIN32API CoFileTimeToDosDateTime(FILETIME *lpFileTime, LPWORD lpDosDate,
166 LPWORD lpDosTime)
167{
168 dprintf(("OLE32: CoFileTimeToDosDateTime"));
169
170 return FileTimeToDosDateTime(lpFileTime, lpDosDate, lpDosTime);
171}
172
173// ----------------------------------------------------------------------
174// CoInitialize()
175// ----------------------------------------------------------------------
176HRESULT WIN32API CoInitialize(LPVOID lpReserved)
177{
178 dprintf(("OLE32: CoInitialize\n"));
179
180 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
181}
182
183// ----------------------------------------------------------------------
184// CoInitializeEx()
185// ----------------------------------------------------------------------
186HRESULT WIN32API CoInitializeEx(
187 LPVOID lpReserved, // [in] pointer to win32 malloc interface
188 DWORD dwCoInit) // [in] A value from COINIT specifies the thread
189{
190 HRESULT hr;
191
192 dprintf(("OLE32: CoInitializeEx(%p, %lx)\n", lpReserved, dwCoInit));
193
194 if (lpReserved != NULL)
195 {
196 dprintf(("Warning: Bad parameter %p, must be an old Windows Application", lpReserved));
197 }
198
199 /*
200 * Check for unsupported features.
201 */
202 if (dwCoInit != COINIT_APARTMENTTHREADED)
203 {
204 dprintf(("Warning: Unsupported flag %lx", dwCoInit));
205 /* Hope for the best and continue anyway */
206 }
207
208 /*
209 * Initialise the Running Object Table
210 */
211 hr = S_FALSE;
212 if (++COM_ref == 1)
213 {
214 hr = RunningObjectTableImpl_Initialize();
215 if (hr != S_OK)
216 --COM_ref;
217 }
218
219 return hr;
220}
221
222// ----------------------------------------------------------------------
223// CoUninitialize()
224// ----------------------------------------------------------------------
225void WIN32API CoUninitialize(void)
226{
227 dprintf(("OLE32: CoUninitialize"));
228
229 if (--COM_ref == 0)
230 {
231 dprintf(("OLE32: Releasing COM libraries"));
232
233 RunningObjectTableImpl_UnInitialize();
234
235 COM_RevokeAllClasses();
236
237 CoFreeAllLibraries();
238
239 COM_ExternalLockFreeList();
240 }
241}
242
243// ----------------------------------------------------------------------
244// CoCreateInstance
245// ----------------------------------------------------------------------
246HRESULT WIN32API CoCreateInstance
247 (REFCLSID rclsid,
248 LPUNKNOWN pUnkOuter,
249 DWORD dwClsContext,
250 REFIID iid,
251 LPVOID * ppv)
252{
253 HRESULT hres;
254 LPCLASSFACTORY lpclf = 0;
255
256 oStringA tCLSID(rclsid);
257 oStringA tIId(iid);
258
259 dprintf(("OLE32: CoCreateInstance"));
260 dprintf((" CLSID:%s", (char *)tCLSID));
261 dprintf((" IID :%s", (char *)tIId));
262
263 // Sanity check
264 if (ppv == 0)
265 return E_POINTER;
266
267 *ppv = 0;
268
269 // Get a class factory to construct the object we want.
270 hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID *)&lpclf);
271
272 if (FAILED(hres))
273 return hres;
274
275 // Create the object and don't forget to release the factory
276 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
277 IClassFactory_Release(lpclf);
278
279 return hres;
280}
281
282// ----------------------------------------------------------------------
283// CoCreateInstanceEx
284// ----------------------------------------------------------------------
285HRESULT WIN32API CoCreateInstanceEx
286 (REFCLSID rclsid,
287 LPUNKNOWN pUnkOuter,
288 DWORD dwClsContext,
289 COSERVERINFO * pServerInfo,
290 ULONG cmq,
291 MULTI_QI * pResults)
292{
293 IUnknown * pUnk = NULL;
294 HRESULT hr;
295 ULONG index;
296 int successCount = 0;
297
298 oStringA tCLSID(rclsid);
299
300 dprintf(("OLE32: CoCreateInstanceEx"));
301 dprintf((" CLSID:%s", (char *)tCLSID));
302
303 // Sanity check
304 if ( (cmq == 0) || (pResults == NULL))
305 return E_INVALIDARG;
306
307 if (pServerInfo != NULL)
308 dprintf(("OLE32: CoCreateInstanceEx - pServerInfo not supported!"));
309
310 // Initialize all the "out" parameters.
311 for (index = 0; index < cmq; index++)
312 {
313 pResults[index].pItf = NULL;
314 pResults[index].hr = E_NOINTERFACE;
315 }
316
317 /*
318 * Get the object and get it's IUnknown pointer.
319 */
320 hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, &IID_IUnknown, (VOID**)&pUnk);
321
322 if (hr)
323 return hr;
324
325 /*
326 * Then, query for all the interfaces requested.
327 */
328 for (index = 0; index < cmq; index++)
329 {
330 pResults[index].hr = IUnknown_QueryInterface(pUnk, pResults[index].pIID, (VOID**)&(pResults[index].pItf));
331
332 if (pResults[index].hr == S_OK)
333 successCount++;
334 }
335
336 /*
337 * Release our temporary unknown pointer.
338 */
339 IUnknown_Release(pUnk);
340
341 if (successCount == 0)
342 return E_NOINTERFACE;
343
344 if (successCount != cmq)
345 return CO_S_NOTALLINTERFACES;
346
347 return S_OK;
348}
349
350// ----------------------------------------------------------------------
351// CoGetClassObject
352// ----------------------------------------------------------------------
353HRESULT WIN32API CoGetClassObject
354 (REFCLSID rclsid,
355 DWORD dwClsContext,
356 LPVOID pvReserved,
357 REFIID iid,
358 LPVOID * ppv)
359{
360 LPUNKNOWN regClassObject;
361 HRESULT hres = E_UNEXPECTED;
362
363 char dllName[MAX_PATH+1];
364 LONG dllNameLen = sizeof(dllName);
365 HINSTANCE hLibrary;
366
367 DllGetClassObjectFunc DllGetClassObject;
368 oStringA tCLSID(rclsid);
369
370#ifdef DEBUG
371 oStringA tIId(iid);
372 dprintf(("OLE32: CoGetClassObject"));
373 dprintf((" CLSID:%s", (char *)tCLSID));
374 dprintf((" IID :%s", (char *)tIId));
375#endif
376
377 // First, try and see if we can't match the class ID with one of the
378 // registered classes.
379 if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
380 {
381 // Get the required interface from the retrieved pointer.
382 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
383
384 // Since QI got another reference on the pointer, we want to release the
385 // one we already have. If QI was unsuccessful, this will release the object. This
386 // is good since we are not returning it in the "out" parameter.
387 IUnknown_Release(regClassObject);
388
389 return hres;
390 }
391
392 // out of process and remote servers not supported yet...
393 if (dwClsContext & CLSCTX_LOCAL_SERVER)
394 {
395 dprintf(("OLE32: CoGetClassObject - CLSCTX_LOCAL_SERVER not supported!\n"));
396 return E_ACCESSDENIED;
397 }
398
399 if (dwClsContext & CLSCTX_REMOTE_SERVER)
400 {
401 dprintf(("OLE32: CoGetClassObject - CLSCTX_REMOTE_SERVER not supported!\n"));
402 return E_ACCESSDENIED;
403 }
404
405 // Get down to the biz..
406 if (dwClsContext & (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER))
407 {
408 HKEY CLSIDkey;
409 HKEY key;
410
411 /* lookup CLSID in registry key HKCR/CLSID */
412 hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &CLSIDkey);
413 if (hres != ERROR_SUCCESS)
414 return REGDB_E_READREGDB;
415
416 hres = RegOpenKeyExA(CLSIDkey, tCLSID, 0, KEY_QUERY_VALUE, &key);
417 if (hres != ERROR_SUCCESS)
418 {
419 RegCloseKey(CLSIDkey);
420 return REGDB_E_CLASSNOTREG;
421 }
422
423 hres = RegQueryValueA(key, "InprocServer32", dllName, &dllNameLen);
424 RegCloseKey(key);
425 RegCloseKey(CLSIDkey);
426 if (hres != ERROR_SUCCESS)
427 {
428 dprintf(("OLE32: CoGetClassObject - InprocServer32 not found in registry"));
429 return REGDB_E_READREGDB;
430 }
431
432 dprintf(("OLE32: CoGetClassObject - Registry reports InprocServer32 dll as %s\n", dllName));
433
434 /* open dll, call DllGetClassFactory */
435 hLibrary = CoLoadLibrary(dllName, TRUE);
436 if (hLibrary == 0)
437 {
438 dprintf(("OLE32: CoGetClassObject - couldn't load %s\n", dllName));
439 return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
440 }
441
442 DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
443 if (!DllGetClassObject)
444 {
445 dprintf(("OLE32: CoGetClassObject - couldn't function DllGetClassObject in %s\n", dllName));
446 /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
447 return E_ACCESSDENIED;
448 }
449
450 // Ask the DLL for it's class object. (there was a note here about class
451 // factories but this is good.
452 return DllGetClassObject(rclsid, iid, ppv);
453 }
454 return hres;
455}
456
457// ----------------------------------------------------------------------
458// CoLockObjectExternal
459// ----------------------------------------------------------------------
460HRESULT WIN32API CoLockObjectExternal(IUnknown *pUnk, BOOL fLock, BOOL fLastUnlockReleases)
461{
462 dprintf(("OLE32: CoLockObjectExternal"));
463
464 if (fLock)
465 {
466 /*
467 * Increment the external lock coutner, COM_ExternalLockAddRef also
468 * increment the object's internal lock counter.
469 */
470 COM_ExternalLockAddRef( pUnk);
471 }
472 else
473 {
474 /*
475 * Decrement the external lock coutner, COM_ExternalLockRelease also
476 * decrement the object's internal lock counter.
477 */
478 COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
479 }
480
481 return S_OK;
482}
483
484// ----------------------------------------------------------------------
485// CoRegisterClassObject
486// ----------------------------------------------------------------------
487HRESULT WIN32API CoRegisterClassObject(
488 REFCLSID rclsid,
489 LPUNKNOWN pUnk,
490 DWORD dwClsContext, // Context in which to run the executable
491 DWORD flags, // how connections are made
492 LPDWORD lpdwRegister)
493{
494 RegisteredClass * newClass;
495 LPUNKNOWN foundObject;
496 HRESULT hr;
497 oStringA tClsid(rclsid);
498
499 dprintf(("OLE32: CoRegisterClassObject(%s)", (char *)tClsid));
500
501 // Perform a sanity check on the parameters
502 if ((lpdwRegister == 0) || (pUnk == 0))
503 return E_INVALIDARG;
504
505 // Initialize the cookie (out parameter)
506 *lpdwRegister = 0;
507
508 // First, check if the class is already registered.
509 // If it is, this should cause an error.
510 hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
511 if (hr == S_OK)
512 {
513 // The COM_GetRegisteredClassObject increased the reference count on the
514 // object so it has to be released.
515 IUnknown_Release(foundObject);
516
517 return CO_E_OBJISREG;
518 }
519
520 // If it is not registered, we must create a new entry for this class and
521 // append it to the registered class list.
522 // We use the address of the chain node as the cookie since we are sure it's
523 // unique.
524 newClass = (RegisteredClass *)HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
525
526 // Initialize the node.
527 newClass->classIdentifier = *rclsid;
528 newClass->runContext = dwClsContext;
529 newClass->connectFlags = flags;
530 newClass->dwCookie = (DWORD)newClass;
531 newClass->nextClass = firstRegisteredClass;
532
533 // Since we're making a copy of the object pointer, we have to increase it's
534 // reference count.
535 newClass->classObject = pUnk;
536 IUnknown_AddRef(newClass->classObject);
537
538 firstRegisteredClass = newClass;
539
540 // Assign the out parameter (cookie)
541 *lpdwRegister = newClass->dwCookie;
542
543 return S_OK;
544}
545
546// ----------------------------------------------------------------------
547// CoRegisterClassObject
548// ----------------------------------------------------------------------
549// This method will remove a class object from the class registry
550HRESULT WIN32API CoRevokeClassObject(DWORD dwRegister)
551{
552 RegisteredClass * * prevClassLink;
553 RegisteredClass * curClass;
554
555 dprintf(("OLE32: CoRegisterClassObject"));
556
557 // Iterate through the whole list and try to match the cookie.
558 curClass = firstRegisteredClass;
559 prevClassLink = &firstRegisteredClass;
560
561 while (curClass != 0)
562 {
563 // Check if we have a match on the cookie.
564 if (curClass->dwCookie == dwRegister)
565 {
566 // Remove the class from the chain.
567 *prevClassLink = curClass->nextClass;
568
569 // Release the reference to the class object.
570 IUnknown_Release(curClass->classObject);
571
572 // Free the memory used by the chain node.
573 HeapFree(GetProcessHeap(), 0, curClass);
574
575 return S_OK;
576 }
577
578 // Step to the next class in the list.
579 prevClassLink = &(curClass->nextClass);
580 curClass = curClass->nextClass;
581 }
582
583 return E_INVALIDARG;
584}
585
586// ----------------------------------------------------------------------
587// GetClassFile
588// ----------------------------------------------------------------------
589// This function supplies the CLSID associated with the given filename.
590HRESULT WIN32API GetClassFile(LPOLESTR filePathName, CLSID *pclsid)
591{
592 IStorage * pstg = 0;
593 HRESULT res;
594 int nbElm = 0;
595 int length = 0;
596 int i = 0;
597 LONG sizeProgId = 20;
598 LPOLESTR * pathDec = 0;
599 LPOLESTR absFile = 0;
600 LPOLESTR progId = 0;
601 WCHAR extention[100] = {0};
602
603 dprintf(("OLE32: GetClassFile"));
604
605 // if the file contain a storage object the return the CLSID
606 // writen by IStorage_SetClass method
607
608 if((StgIsStorageFile(filePathName)) == S_OK)
609 {
610 res = StgOpenStorage(filePathName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pstg);
611
612 if (SUCCEEDED(res))
613 res = ReadClassStg(pstg, pclsid);
614
615 IStorage_Release(pstg);
616
617 return res;
618 }
619
620 /* if the obove strategies fail then search for the extension key in the registry */
621
622 /* get the last element (absolute file) in the path name */
623 nbElm = FileMonikerImpl_DecomposePath(filePathName, &pathDec);
624 absFile = pathDec[nbElm-1];
625
626 /* failed if the path represente a directory and not an absolute file name*/
627 if (lstrcmpW(absFile, (LPOLESTR)"\\"))
628 return MK_E_INVALIDEXTENSION;
629
630 /* get the extension of the file */
631 length = lstrlenW(absFile);
632 for(i = length-1; ( (i >= 0) && (extention[i] = absFile[i]) ); i--);
633
634 /* get the progId associated to the extension */
635 progId = (WCHAR *)CoTaskMemAlloc(sizeProgId);
636
637 res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
638
639 if (res == ERROR_MORE_DATA)
640 {
641 CoTaskMemRealloc(progId,sizeProgId);
642
643 res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
644 }
645 if (res == ERROR_SUCCESS)
646 /* return the clsid associated to the progId */
647 res = CLSIDFromProgID(progId, pclsid);
648
649 for(i = 0; pathDec[i] != NULL; i++)
650 CoTaskMemFree(pathDec[i]);
651
652 CoTaskMemFree(pathDec);
653
654 CoTaskMemFree(progId);
655
656 if (res == ERROR_SUCCESS)
657 return res;
658
659 return MK_E_INVALIDEXTENSION;
660}
661// ======================================================================
662// Private functions.
663// ======================================================================
664
665// ----------------------------------------------------------------------
666// COM_GetRegisteredClassObject
667// ----------------------------------------------------------------------
668// This internal method is used to scan the registered class list to
669// find a class object.
670//
671// Params:
672// rclsid Class ID of the class to find.
673// dwClsContext Class context to match.
674// ppv [out] returns a pointer to the class object. Complying
675// to normal COM usage, this method will increase the
676// reference count on this object.
677static HRESULT COM_GetRegisteredClassObject
678 (REFCLSID rclsid,
679 DWORD dwClsContext,
680 LPUNKNOWN * ppUnk)
681{
682 RegisteredClass* curClass;
683
684 oStringA tCLSID(rclsid);
685
686 dprintf(("OLE32: COM_GetRegisteredClassObject"));
687 dprintf((" CLSID:%s", (char *)tCLSID));
688
689 // Sanity check
690 if (ppUnk == 0)
691 return E_POINTER;
692
693 // Iterate through the whole list and try to match the class ID.
694 curClass = firstRegisteredClass;
695
696 while (curClass != 0)
697 {
698 // Check if we have a match on the class ID.
699 if (IsEqualGUID(&curClass->classIdentifier, &rclsid))
700 {
701 // Since we don't do out-of process or DCOM just right away,
702 // let's ignore the class context.
703
704 // We have a match, return the pointer to the class object.
705 *ppUnk = curClass->classObject;
706
707 IUnknown_AddRef(curClass->classObject);
708
709 return S_OK;
710 }
711
712 // Step to the next class in the list.
713 curClass = curClass->nextClass;
714 }
715
716 // If we get to here, we haven't found our class.
717 return S_FALSE;
718}
719
720// ----------------------------------------------------------------------
721// COM_RevokeAllClasses
722// ----------------------------------------------------------------------
723// This method is called when the COM libraries are uninitialized to
724// release all the references to the class objects registered with
725// the library
726static void COM_RevokeAllClasses()
727{
728 dprintf(("OLE32: COM_RevokeAllClasses"));
729
730 while (firstRegisteredClass != 0)
731 {
732 CoRevokeClassObject(firstRegisteredClass->dwCookie);
733 }
734}
735
736// ----------------------------------------------------------------------
737// COM_ExternalLockAddRef
738// ----------------------------------------------------------------------
739// Method that increments the count for a IUnknown* in the linked
740// list. The item is inserted if not already in the list.
741static void COM_ExternalLockAddRef(IUnknown * pUnk)
742{
743 dprintf(("OLE32: COM_ExternalLockAddRef"));
744
745 COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
746
747 /*
748 * Add an external lock to the object. If it was already externally
749 * locked, just increase the reference count. If it was not.
750 * add the item to the list.
751 */
752 if ( externalLock == EL_NOT_FOUND )
753 COM_ExternalLockInsert(pUnk);
754 else
755 externalLock->uRefCount++;
756
757 /*
758 * Add an internal lock to the object
759 */
760 IUnknown_AddRef(pUnk);
761}
762
763// ----------------------------------------------------------------------
764// COM_ExternalLockRelease
765// ----------------------------------------------------------------------
766// Method that decrements the count for a IUnknown* in the linked
767// list. The item is removed from the list if its count end up at zero or if
768// bRelAll is TRUE.
769static void COM_ExternalLockRelease(IUnknown * pUnk, BOOL bRelAll)
770{
771 dprintf(("OLE32: COM_ExternalLockRelease"));
772
773 COM_ExternalLock * externalLock = COM_ExternalLockFind(pUnk);
774
775 if ( externalLock != EL_NOT_FOUND )
776 {
777 do
778 {
779 externalLock->uRefCount--; /* release external locks */
780 IUnknown_Release(pUnk); /* release local locks as well */
781
782 if ( bRelAll == FALSE )
783 break; /* perform single release */
784
785 } while ( externalLock->uRefCount > 0 );
786
787 if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */
788 COM_ExternalLockDelete(externalLock);
789 }
790}
791
792// ----------------------------------------------------------------------
793// COM_ExternalLockFreeList
794// ----------------------------------------------------------------------
795// Method that frees the content of the list.
796static void COM_ExternalLockFreeList()
797{
798 dprintf(("OLE32: COM_ExternalLockFreeList"));
799
800 COM_ExternalLock *head;
801
802 head = elList.head; /* grab it by the head */
803 while (head != EL_END_OF_LIST)
804 {
805 COM_ExternalLockDelete(head); /* get rid of the head stuff */
806
807 head = elList.head; /* get the new head... */
808 }
809}
810
811// ----------------------------------------------------------------------
812// COM_ExternalLockDump
813// ----------------------------------------------------------------------
814// Method that dump the content of the list.
815void COM_ExternalLockDump()
816{
817 dprintf(("OLE32: COM_ExternalLockDump"));
818
819 COM_ExternalLock *current = elList.head;
820
821 printf("External lock list:");
822
823 while ( current != EL_END_OF_LIST )
824 {
825 dprintf((" %p with %lu references count.\n", current->pUnk, current->uRefCount));
826
827 /* Skip to the next item */
828 current = current->next;
829 }
830}
831
832// ----------------------------------------------------------------------
833// COM_ExternalLockFind
834// ----------------------------------------------------------------------
835// Find a IUnknown* in the linked list
836static COM_ExternalLock * COM_ExternalLockFind(IUnknown *pUnk)
837{
838 dprintf(("OLE32: COM_ExternalLockFind"));
839
840 return COM_ExternalLockLocate(elList.head, pUnk);
841}
842
843// ----------------------------------------------------------------------
844// COM_ExternalLockLocate
845// ----------------------------------------------------------------------
846// Recursivity agent for IUnknownExternalLockList_Find
847static COM_ExternalLock * COM_ExternalLockLocate( COM_ExternalLock * element, IUnknown * pUnk)
848{
849 if ( element == EL_END_OF_LIST )
850 return EL_NOT_FOUND;
851
852 else if ( element->pUnk == pUnk ) /* We found it */
853 return element;
854
855 else /* Not the right guy, keep on looking */
856 return COM_ExternalLockLocate( element->next, pUnk);
857}
858
859// ----------------------------------------------------------------------
860// COM_ExternalLockInsert
861// ----------------------------------------------------------------------
862// Insert a new IUnknown* to the linked list
863static BOOL COM_ExternalLockInsert(IUnknown * pUnk)
864{
865 dprintf(("OLE32: COM_ExternalLockInsert"));
866
867 COM_ExternalLock * newLock = NULL;
868 COM_ExternalLock * previousHead = NULL;
869
870 // Allocate space for the new storage object
871 newLock = (COM_ExternalLock *)HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
872
873 if (newLock != NULL)
874 {
875 if ( elList.head == EL_END_OF_LIST )
876 elList.head = newLock; /* The list is empty */
877 else
878 {
879 // insert does it at the head
880 previousHead = elList.head;
881 elList.head = newLock;
882 }
883
884 /*
885 * Set new list item data member
886 */
887 newLock->pUnk = pUnk;
888 newLock->uRefCount = 1;
889 newLock->next = previousHead;
890
891 return TRUE;
892 }
893
894 return FALSE;
895}
896
897// ----------------------------------------------------------------------
898// ExternalLockDelete
899// ----------------------------------------------------------------------
900// Method that removes an item from the linked list.
901static void COM_ExternalLockDelete(COM_ExternalLock * itemList)
902{
903 dprintf(("OLE32: ExternalLockDelete"));
904
905 COM_ExternalLock *current = elList.head;
906
907 if ( current == itemList )
908 {
909 // this section handles the deletion of the first node
910 elList.head = itemList->next;
911 HeapFree( GetProcessHeap(), 0, itemList);
912 }
913 else
914 {
915 do
916 {
917 if ( current->next == itemList ) /* We found the item to free */
918 {
919 current->next = itemList->next; /* readjust the list pointers */
920
921 HeapFree( GetProcessHeap(), 0, itemList);
922 break;
923 }
924
925 /* Skip to the next item */
926 current = current->next;
927
928 } while ( current != EL_END_OF_LIST );
929 }
930}
Note: See TracBrowser for help on using the repository browser.