Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1092 lines
27 KiB

  1. /*
  2. * U N K O B J . C
  3. *
  4. * This is a generic implementation of the IUnknown plus GetLastError)
  5. * "IMAPIUnknown" part of objects that are derived from IUnknown with
  6. * GetLastError.
  7. *
  8. * This also implements several useful utility functions based on
  9. * IMAPIUnknown.
  10. *
  11. * To use this, you must implement your own init function.
  12. *
  13. * Used in:
  14. * IPROP
  15. * ITABLE
  16. *
  17. */
  18. #include "_apipch.h"
  19. /*
  20. * Per-instance global data for the UNKOBJ Class
  21. */
  22. typedef struct
  23. {
  24. int cRef; // reference count for instance data
  25. HLH hlh; // Single heap used by UNKOBJ_ScCOxxx
  26. // allocators for all Unkobj's
  27. CRITICAL_SECTION cs; // critical section for data access
  28. } UNKOBJCLASSINST, FAR *LPUNKOBJCLASSINST;
  29. #if defined (WIN32) && !defined (MAC)
  30. CRITICAL_SECTION csUnkobjInit;
  31. extern BOOL fGlobalCSValid;
  32. #endif
  33. // $MAC - Use Mac specific instance global handlers
  34. #ifndef MAC
  35. DefineInstList(UNKOBJ);
  36. #undef PvGetInstanceGlobals
  37. #define PvGetInstanceGlobals() PvGetInstanceGlobalsEx(UNKOBJ)
  38. #undef ScSetInstanceGlobals
  39. #define ScSetInstanceGlobals(pinst) ScSetInstanceGlobalsEx(pinst, UNKOBJ)
  40. #else // MAC
  41. #include <utilmac.h>
  42. #define PvGetInstanceGlobals() PvGetInstanceGlobalsMac(kInstMAPIU)
  43. #define PvGetInstanceGlobalsEx(_x) PvGetInstanceGlobalsMac(kInstMAPIU)
  44. #define ScSetInstanceGlobals(a) ScSetInstanceGlobalsMac(a, kInstMAPIU)
  45. #define ScSetInstanceGlobalsEx(_pinst, _x) ScSetInstanceGlobalsMac(_pinst, kInstMAPIU)
  46. #endif // MAC
  47. // #pragma SEGMENT(Common)
  48. /*============================================================================
  49. * UNKOBJ (IMAPIUnknown) Class
  50. *
  51. * Routines for handling per-process global data for the UNKOBJ Class
  52. *
  53. */
  54. /*============================================================================
  55. *
  56. * Initializes per-process global data for the UNKOBJ Class
  57. *
  58. */
  59. IF_WIN32(__inline) SCODE
  60. ScGetUnkClassInst(LPUNKOBJCLASSINST FAR *ppinst)
  61. {
  62. SCODE sc = S_OK;
  63. LPUNKOBJCLASSINST pinst = NULL;
  64. #if defined (WIN32) && !defined (MAC)
  65. if (fGlobalCSValid)
  66. EnterCriticalSection(&csUnkobjInit);
  67. #endif
  68. pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
  69. if (pinst)
  70. {
  71. EnterCriticalSection(&pinst->cs);
  72. pinst->cRef++;
  73. LeaveCriticalSection(&pinst->cs);
  74. goto ret;
  75. }
  76. if (!(pinst = (LPUNKOBJCLASSINST) GlobalAllocPtr(GPTR, sizeof(UNKOBJCLASSINST))))
  77. {
  78. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  79. goto ret;
  80. }
  81. // Initialize the instance structure
  82. // DebugTrace( TEXT("Creating UnkObj Inst: %8x"), pinst);
  83. InitializeCriticalSection(&pinst->cs);
  84. pinst->cRef = 1;
  85. // (the heap will be created when the first allocation is done) ....
  86. pinst->hlh = NULL;
  87. #ifdef NEVER
  88. // Create a Heap for the UNKOBJ Class that will be used by
  89. // all unkobjs in this process.
  90. //$ NOTE: The heap creation can be removed from here and the
  91. //$ code to fault the heap in in UNKOBJ_ScCO(Re)Allocate()
  92. //$ enabled instead - that would *require* users of CreateIProp,
  93. //$ CreateITable etc not to do LH_SetHeapName().
  94. pinst->hlh = LH_Open(0);
  95. if (!pinst->hlh)
  96. {
  97. DebugTrace( TEXT("ScGetUnkClassInst():: Can't create Local Heap\n"));
  98. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  99. goto ret;
  100. }
  101. #endif
  102. // ... and install the instance globals.
  103. if (FAILED(sc = ScSetInstanceGlobals(pinst)))
  104. {
  105. DebugTrace( TEXT("ScGetUnkClassInst():: Failed to install instance globals\n"));
  106. goto ret;
  107. }
  108. ret:
  109. if (FAILED(sc))
  110. {
  111. if (pinst)
  112. {
  113. DeleteCriticalSection(&pinst->cs);
  114. if (pinst->hlh)
  115. LH_Close(pinst->hlh);
  116. GlobalFreePtr(pinst);
  117. pinst = NULL;
  118. }
  119. }
  120. *ppinst = pinst;
  121. #if defined (WIN32) && !defined (MAC)
  122. if (fGlobalCSValid)
  123. LeaveCriticalSection(&csUnkobjInit);
  124. #endif
  125. DebugTraceSc(ScInitInstance, sc);
  126. return sc;
  127. }
  128. /*============================================================================
  129. *
  130. * Cleans up per-process global data for the UNKOBJ Class
  131. *
  132. */
  133. IF_WIN32(__inline) void
  134. ReleaseUnkClassInst()
  135. {
  136. LPUNKOBJCLASSINST pinst = NULL;
  137. #if defined (WIN32) && !defined (MAC)
  138. if (fGlobalCSValid)
  139. EnterCriticalSection(&csUnkobjInit);
  140. #endif
  141. pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
  142. if (!pinst)
  143. goto out;
  144. EnterCriticalSection(&pinst->cs);
  145. if (--(pinst->cRef) > 0)
  146. {
  147. LeaveCriticalSection(&pinst->cs);
  148. goto out;
  149. }
  150. // The last Unkobj for this process is going away, hence close
  151. // our heap.
  152. // DebugTrace( TEXT("Deleting UnkObj Inst: %8x"), pinst);
  153. if (pinst->hlh)
  154. {
  155. // DebugTrace( TEXT("Destroying hlh (%8x) for Inst: %8x"), pinst->hlh, pinst);
  156. LH_Close(pinst->hlh);
  157. }
  158. pinst->hlh = 0;
  159. LeaveCriticalSection(&pinst->cs);
  160. DeleteCriticalSection(&pinst->cs);
  161. GlobalFreePtr(pinst);
  162. (void)ScSetInstanceGlobals(NULL);
  163. out:
  164. #if defined (WIN32) && !defined (MAC)
  165. if (fGlobalCSValid)
  166. LeaveCriticalSection(&csUnkobjInit);
  167. #endif
  168. return;
  169. }
  170. /*============================================================================
  171. * UNKOBJ (IMAPIUnknown) Class
  172. *
  173. * Object methods.
  174. */
  175. /*============================================================================
  176. - UNKOBJ::QueryInterface()
  177. -
  178. */
  179. STDMETHODIMP
  180. UNKOBJ_QueryInterface (LPUNKOBJ lpunkobj,
  181. REFIID riid,
  182. LPVOID FAR * lppUnk)
  183. {
  184. LPIID FAR * lppiidSupported;
  185. ULONG ulcIID;
  186. SCODE sc;
  187. #if !defined(NO_VALIDATION)
  188. /* Validate the object.
  189. */
  190. if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, QueryInterface, lpvtbl))
  191. {
  192. DebugTrace( TEXT("UNKOBJ::QueryInterface() - Bad object passed\n") );
  193. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  194. }
  195. Validate_IUnknown_QueryInterface(lpunkobj, riid, lppUnk);
  196. #endif
  197. for ( lppiidSupported = lpunkobj->rgpiidList, ulcIID = lpunkobj->ulcIID
  198. ; ulcIID
  199. ; lppiidSupported++, ulcIID--)
  200. {
  201. if (IsEqualGUID(riid, *lppiidSupported))
  202. {
  203. /* We support the interface so break out of the search loop.
  204. */
  205. break;
  206. }
  207. }
  208. /* Return error if the requested interface was not in our list of
  209. * supported interfaces.
  210. */
  211. if (!ulcIID)
  212. {
  213. *lppUnk = NULL; // OLE requires zeroing [out] parameters
  214. sc = E_NOINTERFACE;
  215. goto error;
  216. }
  217. /* We found the requested interface so increment the reference count.
  218. */
  219. UNKOBJ_EnterCriticalSection(lpunkobj);
  220. lpunkobj->ulcRef++;
  221. UNKOBJ_LeaveCriticalSection(lpunkobj);
  222. *lppUnk = lpunkobj;
  223. return hrSuccess;
  224. error:
  225. UNKOBJ_EnterCriticalSection(lpunkobj);
  226. UNKOBJ_SetLastError(lpunkobj, E_NOINTERFACE, 0);
  227. UNKOBJ_LeaveCriticalSection(lpunkobj);
  228. return ResultFromScode(sc);
  229. }
  230. /*============================================================================
  231. - UNKOBJ::AddRef()
  232. -
  233. */
  234. STDMETHODIMP_(ULONG)
  235. UNKOBJ_AddRef( LPUNKOBJ lpunkobj )
  236. {
  237. ULONG ulcRef;
  238. #if !defined(NO_VALIDATION)
  239. if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, AddRef, lpvtbl))
  240. {
  241. DebugTrace( TEXT("UNKOBJ::AddRef() - Bad object passed\n") );
  242. return 42;
  243. }
  244. #endif
  245. UNKOBJ_EnterCriticalSection(lpunkobj);
  246. ulcRef = ++lpunkobj->ulcRef;
  247. UNKOBJ_LeaveCriticalSection(lpunkobj);
  248. return ulcRef;
  249. }
  250. /*============================================================================
  251. - UNKOBJ::GetLastError()
  252. -
  253. * NOTE!
  254. * An error in GetLastError will NOT cause the objects last error to be
  255. * set again. This will allow the caller to retry the call.
  256. */
  257. STDMETHODIMP
  258. UNKOBJ_GetLastError( LPUNKOBJ lpunkobj,
  259. HRESULT hrError,
  260. ULONG ulFlags,
  261. LPMAPIERROR FAR * lppMAPIError)
  262. {
  263. SCODE sc = S_OK;
  264. HRESULT hrLastError;
  265. IDS idsLastError;
  266. LPTSTR lpszMessage = NULL;
  267. LPMAPIERROR lpMAPIError = NULL;
  268. #if !defined(NO_VALIDATION)
  269. if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, GetLastError, lpvtbl))
  270. {
  271. DebugTrace( TEXT("UNKOBJ::GetLastError() - Bad object passed\n") );
  272. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  273. }
  274. Validate_IMAPIProp_GetLastError(lpunkobj, hrError, ulFlags, lppMAPIError);
  275. #endif
  276. /* Verify flags.
  277. */
  278. if (ulFlags & ~(MAPI_UNICODE))
  279. {
  280. return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  281. }
  282. *lppMAPIError = NULL;
  283. /* Get a snapshot of the last error.
  284. */
  285. UNKOBJ_EnterCriticalSection(lpunkobj);
  286. idsLastError = lpunkobj->idsLastError;
  287. hrLastError = lpunkobj->hrLastError;
  288. UNKOBJ_LeaveCriticalSection(lpunkobj);
  289. /* If last error doesn't match parameter or there is no
  290. * provider-context specific error string then just succeed.
  291. */
  292. if ((hrError != hrLastError) || !idsLastError)
  293. goto out;
  294. /* Generate new lpMAPIError
  295. */
  296. sc = UNKOBJ_ScAllocate(lpunkobj,
  297. sizeof(MAPIERROR),
  298. &lpMAPIError);
  299. if (FAILED(sc))
  300. {
  301. DebugTrace( TEXT("UNKOBJ::GetLastError() - Unable to allocate memory\n"));
  302. goto err;
  303. }
  304. FillMemory(lpMAPIError, sizeof(MAPIERROR), 0x00);
  305. lpMAPIError->ulVersion = MAPI_ERROR_VERSION;
  306. /* Load a copy of the error string.
  307. */
  308. if ( FAILED(sc = UNKOBJ_ScSzFromIdsAllocMore(lpunkobj,
  309. idsLastError,
  310. ulFlags,
  311. lpMAPIError,
  312. cchLastError,
  313. &lpszMessage)) )
  314. {
  315. DebugTrace( TEXT("UNKOBJ::GetLastError() - WARNING: Unable to load error string (SCODE = 0x%08lX). Returning hrSuccess.\n"), sc );
  316. return ResultFromScode(sc);
  317. }
  318. lpMAPIError->lpszError = lpszMessage;
  319. *lppMAPIError = lpMAPIError;
  320. out:
  321. DebugTraceSc(UNKOBJ_GetLastError, sc);
  322. return ResultFromScode(sc);
  323. err:
  324. UNKOBJ_Free( lpunkobj, lpMAPIError );
  325. goto out;
  326. }
  327. /*
  328. * UNKOBJ utility functions.
  329. */
  330. /*============================================================================
  331. - UNKOBJ::ScAllocate()
  332. -
  333. * Utility function to allocate memory using MAPI linked memory.
  334. *
  335. *
  336. * Parameters:
  337. * lpunkobj in UNKOBJ with instance variable containing
  338. * allocators.
  339. * ulcb in Count of bytes to allocate.
  340. * lplpv out MAPI-Allocated buffer.
  341. */
  342. STDAPI_(SCODE)
  343. UNKOBJ_ScAllocate( LPUNKOBJ lpunkobj,
  344. ULONG ulcb,
  345. LPVOID FAR * lplpv )
  346. {
  347. // parameter validation
  348. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  349. AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
  350. TEXT("lplpv fails address check") );
  351. return lpunkobj->pinst->lpfAllocateBuffer(ulcb, lplpv);
  352. }
  353. /*============================================================================
  354. - UNKOBJ::ScAllocateMore()
  355. -
  356. * Utility function to allocate more memory using MAPI linked memory.
  357. * If the link buffer is null, this function just does a MAPI allocate.
  358. *
  359. *
  360. * Parameters:
  361. * lpunkobj in UNKOBJ with instance variable containing
  362. * allocators.
  363. * ulcb in Count of bytes to allocate.
  364. * lpv in Buffer to link to.
  365. * lplpv out New buffer
  366. */
  367. STDAPI_(SCODE)
  368. UNKOBJ_ScAllocateMore( LPUNKOBJ lpunkobj,
  369. ULONG ulcb,
  370. LPVOID lpv,
  371. LPVOID FAR * lplpv )
  372. {
  373. // validate parameters
  374. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  375. AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
  376. TEXT("lplpv fails address check") );
  377. return lpv ?
  378. lpunkobj->pinst->lpfAllocateMore(ulcb, lpv, lplpv) :
  379. lpunkobj->pinst->lpfAllocateBuffer(ulcb, lplpv) ;
  380. }
  381. /*============================================================================
  382. - UNKOBJ::Free()
  383. -
  384. * Utility function to free MAPI linked memory. NULL buffers are ignored.
  385. *
  386. *
  387. * Parameters:
  388. * lpunkobj in UNKOBJ with instance variable containing
  389. * allocators.
  390. * lpv in Buffer to free.
  391. */
  392. STDAPI_(VOID)
  393. UNKOBJ_Free( LPUNKOBJ lpunkobj,
  394. LPVOID lpv )
  395. {
  396. // parameter validation
  397. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  398. if (lpv)
  399. {
  400. if (lpv == lpunkobj)
  401. lpunkobj->lpvtbl = NULL;
  402. (void) lpunkobj->pinst->lpfFreeBuffer(lpv);
  403. }
  404. }
  405. /*============================================================================
  406. - UNKOBJ::FreeRows()
  407. -
  408. * Frees a row set of the form returned from IMAPITable::QueryRows
  409. * (i.e. where the row set and each individual *prop value array*
  410. * in that row set are individually allocated with MAPI linked memory.)
  411. * NULL row sets are ignored.
  412. *
  413. *
  414. * Parameters:
  415. * lpunkobj in UNKOBJ with instance variable containing
  416. * allocators.
  417. * lprows in Row set to free.
  418. */
  419. STDAPI_(VOID)
  420. UNKOBJ_FreeRows( LPUNKOBJ lpunkobj,
  421. LPSRowSet lprows )
  422. {
  423. LPSRow lprow;
  424. // validate parameters
  425. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  426. AssertSz( !lprows || !FBadRowSet( lprows ), TEXT("lprows fails address check") );
  427. if ( !lprows )
  428. return;
  429. /* Free each row in the set from last to first. UNKOBJ_Free
  430. * handles NULL pointers.
  431. */
  432. lprow = lprows->aRow + lprows->cRows;
  433. while ( lprow-- > lprows->aRow )
  434. UNKOBJ_Free((LPUNKOBJ) lpunkobj, lprow->lpProps);
  435. UNKOBJ_Free(lpunkobj, lprows);
  436. }
  437. /*============================================================================
  438. - UNKOBJ::ScCOAllocate()
  439. -
  440. * Utility function to allocate memory using CO memory allocators.
  441. *
  442. *
  443. * Parameters:
  444. * lpunkobj in UNKOBJ with instance variable containing
  445. * allocators.
  446. * ulcb in Count of bytes to allocate.
  447. * lplpv out Pointer to allocated buffer.
  448. */
  449. STDAPI_(SCODE)
  450. UNKOBJ_ScCOAllocate( LPUNKOBJ lpunkobj,
  451. ULONG ulcb,
  452. LPVOID FAR * lplpv )
  453. {
  454. HLH lhHeap;
  455. // validate parameters
  456. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  457. AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
  458. TEXT("lplpv fails address check") );
  459. /* If caller _really_ wants a 0 byte allocation, warn
  460. * them and give them back a NULL pointer so that they
  461. * can't dereference it, but should be able to free it.
  462. */
  463. if ( ulcb == 0 )
  464. {
  465. DebugTrace( TEXT("LH_Alloc() - WARNING: Caller requested 0 bytes; returning NULL\n") );
  466. *lplpv = NULL;
  467. return S_OK;
  468. }
  469. lhHeap = lpunkobj->lhHeap;
  470. // Enable following section when we fault in the Heap - requires changes
  471. // throughout where CreateIProp/CreateITable calls are
  472. // done followed by LH_SetHeapName(). The LH_SetHeapName
  473. // calls have to be used since we may not have a heap
  474. // at the time. Furthermore, there is only 1 heap, so
  475. // they are unnecessary anyway.
  476. #if 1
  477. if (!lhHeap)
  478. {
  479. LPUNKOBJCLASSINST pinst;
  480. // The UNKOBJ heap *probably* does not exist, make sure
  481. // (to guard against a race) and create it if indeed so.
  482. pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
  483. Assert(pinst);
  484. EnterCriticalSection(&pinst->cs);
  485. if (!pinst->hlh)
  486. {
  487. lhHeap = LH_Open(0);
  488. if (!lhHeap)
  489. {
  490. DebugTrace( TEXT("UNKOBJ_ScCOAllocate() - Can't create Local Heap"));
  491. LeaveCriticalSection(&pinst->cs);
  492. return MAPI_E_NOT_ENOUGH_MEMORY;
  493. }
  494. // DebugTrace( TEXT("Faulting in heap (%8x). UnkObj Inst: %8x"), lhHeap, pinst);
  495. // Install the heap handle in the global data
  496. pinst->hlh = lhHeap;
  497. }
  498. else
  499. {
  500. // The rare event that the heap got created by some other
  501. // object between our UNKOBJ_Init and this (first) allocation ...
  502. // ... Take it and use it.
  503. lhHeap = pinst->hlh;
  504. }
  505. LeaveCriticalSection(&pinst->cs);
  506. // Install the heap handle in this object's internal data too
  507. // so we don't have to access the instance data for subsequent
  508. // allocations. This does not need to be crit-sectioned on lpunkobj
  509. // since an overwrite will be with the same heap!.
  510. lpunkobj->lhHeap = lhHeap;
  511. LH_SetHeapName(lhHeap, TEXT("UNKOBJ Internal Heap"));
  512. }
  513. #endif
  514. /* Allocate the buffer.
  515. */
  516. *lplpv = LH_Alloc( lhHeap,(UINT) ulcb );
  517. if (!*lplpv)
  518. {
  519. DebugTrace( TEXT("LH_Alloc() - OOM allocating *lppv\n") );
  520. return MAPI_E_NOT_ENOUGH_MEMORY;
  521. }
  522. LH_SetName1(lhHeap, *lplpv, TEXT("UNKOBJ::ScCOAllocate %ld"), *lplpv);
  523. return S_OK;
  524. }
  525. /*============================================================================
  526. - UNKOBJ::ScCOReallocate()
  527. -
  528. * Utility function to reallocate memory using CO memory allocators.
  529. *
  530. *
  531. * Parameters:
  532. * lpunkobj in UNKOBJ with instance variable containing
  533. * allocators.
  534. * ulcb in Count of bytes to allocate.
  535. * lplpv in Pointer to buffer to reallocate.
  536. * out Pointer to reallocated buffer.
  537. */
  538. STDAPI_(SCODE)
  539. UNKOBJ_ScCOReallocate( LPUNKOBJ lpunkobj,
  540. ULONG ulcb,
  541. LPVOID FAR * lplpv )
  542. {
  543. HLH lhHeap;
  544. SCODE sc = S_OK;
  545. LPVOID lpv = NULL;
  546. // validate parameters
  547. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  548. AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
  549. TEXT("lplpv fails address check") );
  550. lhHeap = lpunkobj->lhHeap;
  551. // Enable following section when we fault in the Heap - requires changes
  552. // throughout where CreateIProp/CreateITable calls are
  553. // done followed by LH_SetHeapName(). The LH_SetHeapName
  554. // calls have to be used since we may not have a heap
  555. // at the time. Furthermore, there is only 1 heap, so
  556. // they are unnecessary anyway.
  557. #if 1
  558. if (!lhHeap)
  559. {
  560. LPUNKOBJCLASSINST pinst;
  561. // The UNKOBJ heap *probably* does not exist, make sure
  562. // (to guard against a race) and create it if indeed so.
  563. pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
  564. Assert(pinst);
  565. EnterCriticalSection(&pinst->cs);
  566. if (!pinst->hlh)
  567. {
  568. lhHeap = LH_Open(0);
  569. if (!lhHeap)
  570. {
  571. DebugTrace( TEXT("UNKOBJ_ScCOReallocate() - Can't create Local Heap"));
  572. LeaveCriticalSection(&pinst->cs);
  573. return MAPI_E_NOT_ENOUGH_MEMORY;
  574. }
  575. // DebugTrace( TEXT("Faulting in heap (%8x). UnkObj Inst: %8x"), lhHeap, pinst);
  576. // Install the heap handle in the global data
  577. pinst->hlh = lhHeap;
  578. }
  579. else
  580. {
  581. // The rare event that the heap got created by some other
  582. // object between our UNKOBJ_Init and this (first) allocation ...
  583. // ... Take it and use it.
  584. lhHeap = pinst->hlh;
  585. }
  586. LeaveCriticalSection(&pinst->cs);
  587. // Install the heap handle in this object's internal data too
  588. // so we don't have to access the instance data for subsequent
  589. // allocations. This does not need to be crit-sectioned on lpunkobj
  590. // since an overwrite will be with the same heap!.
  591. lpunkobj->lhHeap = lhHeap;
  592. LH_SetHeapName(lhHeap, TEXT("UNKOBJ Internal Heap"));
  593. }
  594. #endif
  595. //$BUG Actually, the CO model is supposed do an Alloc() if
  596. //$BUG the pointer passed in is NULL, but it currently
  597. //$BUG doesn't seem to work that way....
  598. if ( *lplpv == NULL )
  599. {
  600. lpv = LH_Alloc(lhHeap, (UINT) ulcb);
  601. if (lpv)
  602. {
  603. *lplpv = lpv;
  604. LH_SetName1(lhHeap, lpv, TEXT("UNKOBJ::ScCOReallocate %ld"), lpv);
  605. }
  606. else
  607. sc = E_OUTOFMEMORY;
  608. goto out;
  609. }
  610. /* Reallocate the buffer.
  611. */
  612. lpv = LH_Realloc(lhHeap, *lplpv, (UINT) ulcb );
  613. if (!lpv)
  614. {
  615. DebugTrace( TEXT("UNKOBJ::ScCOReallocate() - OOM reallocating *lplpv\n") );
  616. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  617. goto out;
  618. }
  619. LH_SetName1(lhHeap, lpv, TEXT("UNKOBJ::ScCOReallocate %ld"), lpv);
  620. *lplpv = lpv;
  621. out:
  622. return sc;
  623. }
  624. /*============================================================================
  625. - UNKOBJ::COFree()
  626. -
  627. * Utility function to free memory using CO memory allocators.
  628. *
  629. *
  630. * Parameters:
  631. * lpunkobj in UNKOBJ with instance variable containing
  632. * allocators.
  633. * lpv in Buffer to free.
  634. */
  635. STDAPI_(VOID)
  636. UNKOBJ_COFree( LPUNKOBJ lpunkobj,
  637. LPVOID lpv )
  638. {
  639. HLH lhHeap;
  640. // validate parameters
  641. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  642. lhHeap = lpunkobj->lhHeap;
  643. /* Free the buffer.
  644. */
  645. //$??? Don't know if CO properly handles freeing NULL pointers,
  646. //$??? but I assume it doesn't....
  647. if ( lpv != NULL )
  648. LH_Free( lhHeap, lpv );
  649. }
  650. /*============================================================================
  651. - UNKOBJ::ScSzFromIdsAlloc()
  652. -
  653. * Utility function load a resource string into a MAPI-allocated buffer.
  654. *
  655. *
  656. * Parameters:
  657. * lpunkobj in UNKOBJ with instance variable containing
  658. * allocators.
  659. * ids in ID of resource string.
  660. * ulFlags in Flags (UNICODE or ANSI)
  661. * cchBuf in Max length, in characters, to read.
  662. * lpszBuf out Pointer to allocated buffer containing string.
  663. */
  664. STDAPI_(SCODE)
  665. UNKOBJ_ScSzFromIdsAlloc( LPUNKOBJ lpunkobj,
  666. IDS ids,
  667. ULONG ulFlags,
  668. int cchBuf,
  669. LPTSTR FAR * lppszBuf )
  670. {
  671. SCODE sc;
  672. ULONG ulStringMax;
  673. // validate parameters
  674. AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
  675. AssertSz( lppszBuf && !IsBadWritePtr( lppszBuf, sizeof( LPVOID ) ),
  676. TEXT("lppszBuf fails address check") );
  677. AssertSz( cchBuf > 0, TEXT("cchBuf can't be less than 1") );
  678. ulStringMax = cchBuf
  679. * ((ulFlags & MAPI_UNICODE) ? sizeof(TCHAR) : sizeof(CHAR));
  680. if ( FAILED(sc = UNKOBJ_ScAllocate(lpunkobj,
  681. ulStringMax,
  682. (LPVOID FAR *) lppszBuf)) )
  683. {
  684. DebugTrace( TEXT("UNKOBJ::ScSzFromIdsAlloc() - Error allocating string (SCODE = 0x%08lX)\n"), sc );
  685. return sc;
  686. }
  687. #if !defined(WIN16) && !defined(MAC)
  688. if ( ulFlags & MAPI_UNICODE )
  689. (void) LoadStringW(hinstMapiX,
  690. (UINT) ids,
  691. (LPWSTR) *lppszBuf,
  692. cchBuf);
  693. else
  694. #endif
  695. (void) LoadStringA(hinstMapiX,
  696. (UINT) ids,
  697. (LPSTR) *lppszBuf,
  698. cchBuf);
  699. return S_OK;
  700. }
  701. /*============================================================================
  702. - UNKOBJ::ScSzFromIdsAllocMore()
  703. -
  704. * Utility function load a resource string into a MAPI-allocated buffer.
  705. *
  706. *
  707. * Parameters:
  708. * lpunkobj in UNKOBJ with instance variable containing
  709. * allocators.
  710. * ids in ID of resource string.
  711. * ulFlags in Flags (UNICODE or ANSI)
  712. * lpvBase in Base allocation
  713. * cchBuf in Max length, in characters, to read.
  714. * lpszBuf out Pointer to allocated buffer containing string.
  715. */
  716. STDAPI_(SCODE)
  717. UNKOBJ_ScSzFromIdsAllocMore( LPUNKOBJ lpunkobj,
  718. IDS ids,
  719. ULONG ulFlags,
  720. LPVOID lpvBase,
  721. int cchBuf,
  722. LPTSTR FAR * lppszBuf )
  723. {
  724. SCODE sc;
  725. ULONG ulStringMax;
  726. ulStringMax = cchBuf
  727. * ((ulFlags & MAPI_UNICODE) ? sizeof(WCHAR) : sizeof(CHAR));
  728. if ( FAILED(sc = UNKOBJ_ScAllocateMore(lpunkobj,
  729. ulStringMax,
  730. lpvBase,
  731. (LPVOID FAR *) lppszBuf)) )
  732. {
  733. DebugTrace( TEXT("UNKOBJ::ScSzFromIdsAllocMore() - Error allocating string (SCODE = 0x%08lX)\n"), sc );
  734. return sc;
  735. }
  736. #if !defined(WIN16) && !defined(MAC)
  737. if ( ulFlags & MAPI_UNICODE )
  738. (void) LoadStringW(hinstMapiX,
  739. (UINT) ids,
  740. (LPWSTR) *lppszBuf,
  741. cchBuf);
  742. else
  743. #endif
  744. (void) LoadStringA(hinstMapiX,
  745. (UINT) ids,
  746. (LPSTR) *lppszBuf,
  747. cchBuf);
  748. return S_OK;
  749. }
  750. /*============================================================================
  751. - UNKOBJ::Init()
  752. -
  753. * Initialize an object of the UNKOBJ Class
  754. *
  755. *
  756. * Parameters:
  757. * lpunkobj in UNKOBJ with instance variable containing
  758. * allocators.
  759. * lpvtblUnkobj in the object v-table
  760. * ulcbVtbl in size of the object v-table
  761. * rgpiidList in list of iid's supported by this object
  762. * ulcIID in count of iid's in the list above
  763. * punkinst in pointer to object's private (instance) data
  764. */
  765. STDAPI_(SCODE)
  766. UNKOBJ_Init( LPUNKOBJ lpunkobj,
  767. UNKOBJ_Vtbl FAR * lpvtblUnkobj,
  768. ULONG ulcbVtbl,
  769. LPIID FAR * rgpiidList,
  770. ULONG ulcIID,
  771. PUNKINST punkinst )
  772. {
  773. SCODE sc = S_OK;
  774. LPUNKOBJCLASSINST pinst = NULL;
  775. // Create/Get per process global data for the Unkobj class
  776. // This gets faulted in the first time UNKOBJ_Init
  777. // is called by the process, i.e., when the process creates
  778. // its first Unkobj. Subsequent calls just Addref
  779. // the instance data. Note that this data is global to all
  780. // UNKOBJ objects (per process) and differs from the per object
  781. // data that *each* Unkobj keeps.
  782. sc = ScGetUnkClassInst(&pinst);
  783. if (FAILED(sc))
  784. {
  785. DebugTrace( TEXT("UNKOBJ_Init() - Can't create Instance Data"));
  786. goto ret;
  787. }
  788. Assert(pinst);
  789. lpunkobj->lpvtbl = lpvtblUnkobj;
  790. lpunkobj->ulcbVtbl = ulcbVtbl;
  791. lpunkobj->ulcRef = 1;
  792. lpunkobj->rgpiidList= rgpiidList;
  793. lpunkobj->ulcIID = ulcIID;
  794. lpunkobj->pinst = punkinst;
  795. lpunkobj->hrLastError = hrSuccess;
  796. lpunkobj->idsLastError = 0;
  797. InitializeCriticalSection(&lpunkobj->csid);
  798. // If we have a heap for this instance, use it;
  799. // otherwise, wait and it'll get faulted in the first time
  800. // and allocation is made on this object.
  801. lpunkobj->lhHeap = pinst->hlh ? pinst->hlh : NULL;
  802. ret:
  803. return sc;
  804. }
  805. /*============================================================================
  806. - UNKOBJ::Deinit()
  807. -
  808. * Deinitialize an object of the UNKOBJ Class
  809. *
  810. *
  811. * Parameters:
  812. * lpunkobj in UNKOBJ with instance variable containing
  813. * allocators.
  814. */
  815. STDAPI_(VOID)
  816. UNKOBJ_Deinit( LPUNKOBJ lpunkobj )
  817. {
  818. // Cleanup per process global data for the Unkobj class,
  819. // if necessary. Last one out will end up shutting off
  820. // the lights.
  821. ReleaseUnkClassInst();
  822. DeleteCriticalSection(&lpunkobj->csid);
  823. }
  824. #ifdef WIN16
  825. // Win16 version of inline function. These are no longer inline function because
  826. // Watcom WCC doesn't support inline. (WPP(C++ compiler) support inline.
  827. VOID
  828. UNKOBJ_EnterCriticalSection( LPUNKOBJ lpunkobj )
  829. {
  830. EnterCriticalSection(&lpunkobj->csid);
  831. }
  832. VOID
  833. UNKOBJ_LeaveCriticalSection( LPUNKOBJ lpunkobj )
  834. {
  835. LeaveCriticalSection(&lpunkobj->csid);
  836. }
  837. HRESULT
  838. UNKOBJ_HrSetLastResult( LPUNKOBJ lpunkobj,
  839. HRESULT hResult,
  840. IDS idsError )
  841. {
  842. UNKOBJ_EnterCriticalSection(lpunkobj);
  843. lpunkobj->idsLastError = idsError;
  844. lpunkobj->hrLastError = hResult;
  845. UNKOBJ_LeaveCriticalSection(lpunkobj);
  846. return hResult;
  847. }
  848. HRESULT
  849. UNKOBJ_HrSetLastError( LPUNKOBJ lpunkobj,
  850. SCODE sc,
  851. IDS idsError )
  852. {
  853. UNKOBJ_EnterCriticalSection(lpunkobj);
  854. lpunkobj->idsLastError = idsError;
  855. lpunkobj->hrLastError = ResultFromScode(sc);
  856. UNKOBJ_LeaveCriticalSection(lpunkobj);
  857. return ResultFromScode(sc);
  858. }
  859. VOID
  860. UNKOBJ_SetLastError( LPUNKOBJ lpunkobj,
  861. SCODE sc,
  862. IDS idsError )
  863. {
  864. lpunkobj->idsLastError = idsError;
  865. lpunkobj->hrLastError = ResultFromScode(sc);
  866. }
  867. VOID
  868. UNKOBJ_SetLastErrorSc( LPUNKOBJ lpunkobj,
  869. SCODE sc )
  870. {
  871. lpunkobj->hrLastError = ResultFromScode(sc);
  872. }
  873. VOID
  874. UNKOBJ_SetLastErrorIds( LPUNKOBJ lpunkobj,
  875. IDS ids )
  876. {
  877. lpunkobj->idsLastError = ids;
  878. }
  879. #endif // WIN16