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.

721 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: hglobal.cxx
  7. //
  8. // Contents: Support for Windows/OLE data types for oleprx32.dll.
  9. // Used to be transmit_as routines, now user_marshal routines.
  10. //
  11. // This file contains support for HGLOBAL.
  12. //
  13. // Functions:
  14. // HGLOBAL_UserSize
  15. // HGLOBAL_UserMarshal
  16. // HGLOBAL_UserUnmarshal
  17. // HGLOBAL_UserFree
  18. // HGLOBAL_UserSize64
  19. // HGLOBAL_UserMarshal64
  20. // HGLOBAL_UserUnmarshal64
  21. // HGLOBAL_UserFree64
  22. //
  23. // History: 13-Dec-00 JohnDoty Migrated from transmit.cxx
  24. //
  25. //--------------------------------------------------------------------------
  26. #include "stdrpc.hxx"
  27. #pragma hdrstop
  28. #include <oleauto.h>
  29. #include <objbase.h>
  30. #include "transmit.hxx"
  31. #include <rpcwdt.h>
  32. #include <storext.h>
  33. #include <valid.h>
  34. #include <obase.h>
  35. #include <stream.hxx>
  36. #include "carefulreader.hxx"
  37. //+-------------------------------------------------------------------------
  38. //
  39. // Function: HGLOBAL_UserSize
  40. //
  41. // Synopsis: Get the wire size the HGLOBAL handle and data.
  42. //
  43. // Derivation: Conformant struct with a flag field:
  44. // align + 12 + data size.
  45. //
  46. // history: May-95 Ryszardk Created.
  47. // Dec-98 Ryszardk Ported to 64b.
  48. //
  49. //--------------------------------------------------------------------------
  50. unsigned long __RPC_USER
  51. HGLOBAL_UserSize (
  52. unsigned long * pFlags,
  53. unsigned long Offset,
  54. HGLOBAL * pGlobal)
  55. {
  56. if ( !pGlobal )
  57. return Offset;
  58. // userHGLOBAL: the encapsulated union.
  59. // Discriminant and then handle or pointer from the union arm.
  60. LENGTH_ALIGN( Offset, 3 );
  61. // Union discriminent is 4 bytes
  62. Offset += sizeof( long );
  63. // Handle represented by a polymorphic type - for inproc case only!
  64. if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
  65. {
  66. LENGTH_ALIGN( Offset, sizeof( HGLOBAL )-1 );
  67. Offset += sizeof( HGLOBAL );
  68. }
  69. else
  70. Offset += ( sizeof(long) + sizeof(HGLOBAL) );
  71. if ( ! *pGlobal )
  72. return Offset;
  73. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  74. {
  75. unsigned long ulDataSize = (ULONG) GlobalSize( *pGlobal );
  76. Offset += 3 * sizeof(long) + ulDataSize;
  77. }
  78. return( Offset );
  79. }
  80. //+-------------------------------------------------------------------------
  81. //
  82. // Function: HGLOBAL_UserMarshall
  83. //
  84. // Synopsis: Marshalls an HGLOBAL object into the RPC buffer.
  85. //
  86. // Derivation: Conformant struct with a flag field:
  87. // align, size, null flag, size, data (bytes, if any)
  88. //
  89. // history: May-95 Ryszardk Created.
  90. // Dec-98 Ryszardk Ported to 64b.
  91. //
  92. //--------------------------------------------------------------------------
  93. unsigned char __RPC_FAR * __RPC_USER
  94. HGLOBAL_UserMarshal (
  95. unsigned long * pFlags,
  96. unsigned char * pBuffer,
  97. HGLOBAL * pGlobal)
  98. {
  99. if ( !pGlobal )
  100. return pBuffer;
  101. // We marshal a null handle, too.
  102. UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n"));
  103. ALIGN( pBuffer, 3 );
  104. // Discriminant of the encapsulated union and union arm.
  105. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  106. {
  107. unsigned long ulDataSize;
  108. // userHGLOBAL
  109. *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
  110. *( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
  111. if ( ! *pGlobal )
  112. return pBuffer;
  113. // FLAGGED_BYTE_BLOB
  114. ulDataSize = (ULONG) GlobalSize( *pGlobal );
  115. *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
  116. // Handle is the non-null flag
  117. *( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
  118. *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
  119. if( ulDataSize )
  120. {
  121. void * pData = GlobalLock( *pGlobal);
  122. memcpy( pBuffer, pData, ulDataSize );
  123. GlobalUnlock( *pGlobal);
  124. }
  125. pBuffer += ulDataSize;
  126. }
  127. else
  128. {
  129. // Sending a handle.
  130. // For WIN64 HGLOBALs, 64 bits may by significant (e.i. GPTR).
  131. #if defined(_WIN64)
  132. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE64_MARKER;
  133. ALIGN( pBuffer, 7 );
  134. *( PHYPER_LV_CAST pBuffer)++ = *(__int64 *)pGlobal;
  135. #else
  136. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
  137. *( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
  138. #endif
  139. }
  140. return( pBuffer );
  141. }
  142. //+-------------------------------------------------------------------------
  143. //
  144. // Function: WdtpGlobalUnmarshal
  145. //
  146. // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
  147. //
  148. // Derivation: Conformant struct with a flag field:
  149. // align, size, null flag, size, data (bytes, if any)
  150. //
  151. // Note: Reallocation is forbidden when the hglobal is part of
  152. // an [in,out] STGMEDIUM in IDataObject::GetDataHere.
  153. // This affects only data passing with old handles being
  154. // non null.
  155. //
  156. // history: May-95 Ryszardk Created.
  157. //
  158. //--------------------------------------------------------------------------
  159. unsigned char __RPC_FAR * __RPC_USER
  160. WdtpGlobalUnmarshal (
  161. unsigned long * pFlags,
  162. unsigned char * pBuffer,
  163. HGLOBAL * pGlobal,
  164. BOOL fCanReallocate,
  165. ULONG_PTR BufferSize )
  166. {
  167. unsigned long ulDataSize, fHandle, UnionDisc;
  168. HGLOBAL hGlobal;
  169. // Align the buffer and save the fixup size.
  170. UCHAR* pBufferStart = pBuffer;
  171. ALIGN( pBuffer, 3 );
  172. ULONG_PTR cbFixup = (ULONG_PTR)(pBuffer - pBufferStart);
  173. // Check for EOB before accessing discriminant and handle.
  174. CHECK_BUFFER_SIZE( BufferSize, cbFixup + (2 * sizeof( ULONG )) );
  175. // Get the tag from buffer.
  176. UnionDisc = *( PULONG_LV_CAST pBuffer)++;
  177. if ( IS_DATA_MARKER( UnionDisc) )
  178. {
  179. if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
  180. {
  181. // Hey, you can't send us one of these!
  182. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  183. }
  184. // Get the marker from the buffer.
  185. hGlobal = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
  186. // If handle is NULL, we are done.
  187. if ( ! hGlobal )
  188. {
  189. if ( *pGlobal )
  190. GlobalFree( *pGlobal );
  191. *pGlobal = NULL;
  192. return pBuffer;
  193. }
  194. // Check for EOB before accessing header.
  195. CHECK_BUFFER_SIZE( BufferSize, cbFixup + (5 * sizeof( ULONG )) );
  196. // Get the rest of the header from the buffer.
  197. ulDataSize = *( PULONG_LV_CAST pBuffer)++;
  198. HGLOBAL hGlobalDup = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
  199. ULONG ulDataSizeDup = *( PULONG_LV_CAST pBuffer)++;
  200. // Validate the header: handle and size are put on wire twice, make
  201. // sure both instances of each are the same.
  202. if ( (hGlobalDup != hGlobal) ||
  203. (ulDataSizeDup != ulDataSize) )
  204. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  205. if ( *pGlobal )
  206. {
  207. // Check for reallocation
  208. if ( GlobalSize( *pGlobal ) == ulDataSize )
  209. hGlobal = *pGlobal;
  210. else
  211. {
  212. if ( fCanReallocate )
  213. {
  214. GlobalFree( *pGlobal );
  215. hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
  216. }
  217. else
  218. {
  219. if ( GlobalSize(*pGlobal) < ulDataSize )
  220. {
  221. RAISE_RPC_EXCEPTION( STG_E_MEDIUMFULL );
  222. }
  223. else
  224. hGlobal = *pGlobal;
  225. }
  226. }
  227. }
  228. else
  229. {
  230. // allocate a new block
  231. hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
  232. }
  233. if ( hGlobal == NULL )
  234. {
  235. RAISE_RPC_EXCEPTION(E_OUTOFMEMORY);
  236. }
  237. else
  238. {
  239. // Check for EOB before accessing data.
  240. CHECK_BUFFER_SIZE( BufferSize,
  241. cbFixup + (5 * sizeof( ULONG )) + ulDataSize );
  242. // Get the data from the buffer.
  243. void * pData = GlobalLock( hGlobal);
  244. memcpy( pData, pBuffer, ulDataSize );
  245. pBuffer += ulDataSize;
  246. GlobalUnlock( hGlobal);
  247. }
  248. }
  249. else
  250. {
  251. // Sending a handle only.
  252. // Reallocation problem doesn't apply to handle passing.
  253. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  254. {
  255. // Hey, you can't send us one of these!
  256. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  257. }
  258. if ( IS_HANDLE_MARKER( UnionDisc ) )
  259. {
  260. hGlobal = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
  261. }
  262. else if (IS_HANDLE64_MARKER( UnionDisc ) )
  263. {
  264. ALIGN( pBuffer, 7 );
  265. // Must be enough buffer to do alignment fixup.
  266. CHECK_BUFFER_SIZE( BufferSize, cbFixup +
  267. (ULONG_PTR) (pBuffer - pBufferStart) + sizeof( __int64 ));
  268. hGlobal = (HGLOBAL) ( *( PHYPER_LV_CAST pBuffer)++ );
  269. }
  270. else
  271. {
  272. RAISE_RPC_EXCEPTION( RPC_S_INVALID_TAG );
  273. }
  274. if ( *pGlobal != hGlobal && *pGlobal )
  275. GlobalFree( *pGlobal );
  276. }
  277. *pGlobal = hGlobal;
  278. return( pBuffer );
  279. }
  280. //+-------------------------------------------------------------------------
  281. //
  282. // Function: HGLOBAL_UserUnmarshall
  283. //
  284. // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
  285. //
  286. // Derivation: Conformant struct with a flag field:
  287. // align, size, null flag, size, data (bytes, if any)
  288. //
  289. // history: May-95 Ryszardk Created.
  290. //
  291. //--------------------------------------------------------------------------
  292. unsigned char __RPC_FAR * __RPC_USER
  293. HGLOBAL_UserUnmarshal (
  294. unsigned long * pFlags,
  295. unsigned char * pBuffer,
  296. HGLOBAL * pGlobal)
  297. {
  298. // Get the buffer size and the start of the buffer.
  299. CUserMarshalInfo MarshalInfo( pFlags, pBuffer );
  300. ULONG_PTR BufferSize = MarshalInfo.GetBufferSize();
  301. UCHAR* pBufferStart = MarshalInfo.GetBuffer();
  302. pBuffer = WdtpGlobalUnmarshal( pFlags,
  303. pBufferStart,
  304. pGlobal,
  305. TRUE, // reallocation possible
  306. BufferSize );
  307. return( pBuffer );
  308. }
  309. //+-------------------------------------------------------------------------
  310. //
  311. // Function: HGLOBAL_UserFree
  312. //
  313. // Synopsis: Free an HGLOBAL.
  314. //
  315. // history: May-95 Ryszardk Created.
  316. //
  317. //--------------------------------------------------------------------------
  318. void __RPC_USER
  319. HGLOBAL_UserFree(
  320. unsigned long * pFlags,
  321. HGLOBAL * pGlobal)
  322. {
  323. if( pGlobal && *pGlobal )
  324. {
  325. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  326. GlobalFree( *pGlobal);
  327. }
  328. }
  329. #if defined(_WIN64)
  330. //+-------------------------------------------------------------------------
  331. //
  332. // Function: HGLOBAL_UserSize64
  333. //
  334. // Synopsis: Get the wire size the HGLOBAL handle and data.
  335. //
  336. // Derivation: Union around a pointer to a conformant struct with a
  337. // flag field.
  338. //
  339. // history: Dec-00 JohnDoty Created from 32bit function
  340. //
  341. //--------------------------------------------------------------------------
  342. unsigned long __RPC_USER
  343. HGLOBAL_UserSize64 (
  344. unsigned long * pFlags,
  345. unsigned long Offset,
  346. HGLOBAL * pGlobal)
  347. {
  348. if ( !pGlobal )
  349. return Offset;
  350. // userHGLOBAL: the encapsulated union.
  351. // Discriminant and then handle or pointer from the union arm.
  352. // Union discriminent is 4 bytes, but it contains a pointer, so
  353. // align on union is 8 bytes.
  354. LENGTH_ALIGN( Offset, 7 );
  355. Offset += sizeof( long );
  356. LENGTH_ALIGN( Offset, 7 );
  357. // Handle represented by a polymorphic type - for inproc case only!
  358. if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
  359. {
  360. // Doesn't matter which arm we take inproc, it's size of native
  361. // HGLOBAL.
  362. Offset += sizeof( HGLOBAL );
  363. }
  364. else
  365. {
  366. // Pointer representation...
  367. Offset += 8;
  368. }
  369. if ( ! *pGlobal )
  370. return Offset;
  371. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  372. {
  373. // Struct must be aligned on 8, but already aligned on
  374. // 8...
  375. unsigned long ulDataSize = (ULONG) GlobalSize( *pGlobal );
  376. Offset += 8 + 2 * sizeof(long) + ulDataSize;
  377. }
  378. return( Offset );
  379. }
  380. //+-------------------------------------------------------------------------
  381. //
  382. // Function: HGLOBAL_UserMarshal64
  383. //
  384. // Synopsis: Marshalls an HGLOBAL object into the RPC buffer.
  385. //
  386. // Derivation: Conformant struct with a flag field:
  387. // align, size, null flag, size, data (bytes, if any)
  388. //
  389. // history: Dec-00 JohnDoty Created from 32bit function
  390. //
  391. //--------------------------------------------------------------------------
  392. unsigned char __RPC_FAR * __RPC_USER
  393. HGLOBAL_UserMarshal64 (
  394. unsigned long * pFlags,
  395. unsigned char * pBuffer,
  396. HGLOBAL * pGlobal)
  397. {
  398. if ( !pGlobal )
  399. return pBuffer;
  400. // We marshal a null handle, too.
  401. UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n"));
  402. ALIGN( pBuffer, 7 );
  403. // Discriminant of the encapsulated union and union arm.
  404. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  405. {
  406. unsigned long ulDataSize;
  407. // userHGLOBAL
  408. *( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
  409. ALIGN( pBuffer, 7 );
  410. *( PHYPER_LV_CAST pBuffer)++ = (hyper)*pGlobal;
  411. if ( ! *pGlobal )
  412. return pBuffer;
  413. // FLAGGED_BYTE_BLOB
  414. ulDataSize = (ULONG) GlobalSize( *pGlobal );
  415. *( PHYPER_LV_CAST pBuffer)++ = ulDataSize;
  416. // Handle is the non-null flag
  417. *( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
  418. *( PULONG_LV_CAST pBuffer)++ = ulDataSize;
  419. if( ulDataSize )
  420. {
  421. void * pData = GlobalLock( *pGlobal);
  422. memcpy( pBuffer, pData, ulDataSize );
  423. GlobalUnlock( *pGlobal);
  424. }
  425. pBuffer += ulDataSize;
  426. }
  427. else
  428. {
  429. // Sending a handle.
  430. // For WIN64 HGLOBALs, 64 bits may by significant (e.i. GPTR).
  431. *( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE64_MARKER;
  432. ALIGN( pBuffer, 7 );
  433. *( PHYPER_LV_CAST pBuffer)++ = *(__int64 *)pGlobal;
  434. }
  435. return( pBuffer );
  436. }
  437. //+-------------------------------------------------------------------------
  438. //
  439. // Function: WdtpGlobalUnmarshal64
  440. //
  441. // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
  442. //
  443. // Derivation: Conformant struct with a flag field:
  444. // align, size, null flag, size, data (bytes, if any)
  445. //
  446. // Note: Reallocation is forbidden when the hglobal is part of
  447. // an [in,out] STGMEDIUM in IDataObject::GetDataHere.
  448. // This affects only data passing with old handles being
  449. // non null.
  450. //
  451. // history: Dec-00 JohnDoty Created from 32bit function
  452. //
  453. //--------------------------------------------------------------------------
  454. unsigned char __RPC_FAR * __RPC_USER
  455. WdtpGlobalUnmarshal64 (
  456. unsigned long * pFlags,
  457. unsigned char * pBuffer,
  458. HGLOBAL * pGlobal,
  459. BOOL fCanReallocate,
  460. ULONG_PTR BufferSize )
  461. {
  462. CarefulBufferReader stream(pBuffer, BufferSize);
  463. unsigned long ulDataSize, fHandle, UnionDisc;
  464. HGLOBAL hGlobal;
  465. // Align the buffer and save the fixup size.
  466. stream.Align(8);
  467. // Get the tag from buffer.
  468. UnionDisc = stream.ReadULONGNA();
  469. // Get the marker from the buffer.
  470. hGlobal = (HGLOBAL)stream.ReadHYPER();
  471. if ( IS_DATA_MARKER(UnionDisc) )
  472. {
  473. if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
  474. {
  475. // Hey, you can't send us one of these!
  476. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  477. }
  478. // If the handle was NULL, return out now.
  479. if (!hGlobal)
  480. {
  481. if (*pGlobal)
  482. GlobalFree(*pGlobal);
  483. *pGlobal = NULL;
  484. return stream.GetBuffer();
  485. }
  486. // Get the rest of the header from the buffer.
  487. ulDataSize = (ULONG)stream.ReadHYPERNA();
  488. LONG hGlobalDup = stream.ReadLONGNA();
  489. ULONG ulDataSizeDup = stream.ReadULONGNA();
  490. // Validate the header: handle and size are put on wire twice, make
  491. // sure both instances of each are the same.
  492. if ( (hGlobalDup != HandleToLong(hGlobal)) ||
  493. (ulDataSizeDup != ulDataSize) )
  494. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  495. if ( *pGlobal )
  496. {
  497. // Check for reallocation
  498. if ( GlobalSize( *pGlobal ) == ulDataSize )
  499. hGlobal = *pGlobal;
  500. else
  501. {
  502. if ( fCanReallocate )
  503. {
  504. GlobalFree( *pGlobal );
  505. hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
  506. }
  507. else
  508. {
  509. if ( GlobalSize(*pGlobal) < ulDataSize )
  510. {
  511. RAISE_RPC_EXCEPTION( STG_E_MEDIUMFULL );
  512. }
  513. else
  514. hGlobal = *pGlobal;
  515. }
  516. }
  517. }
  518. else
  519. {
  520. // allocate a new block
  521. hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
  522. }
  523. if ( hGlobal == NULL )
  524. {
  525. RAISE_RPC_EXCEPTION(E_OUTOFMEMORY);
  526. }
  527. else
  528. {
  529. // Check for EOB before accessing data.
  530. stream.CheckSize(ulDataSize);
  531. // Get the data from the buffer.
  532. void * pData = GlobalLock( hGlobal);
  533. memcpy( pData, stream.GetBuffer(), ulDataSize );
  534. GlobalUnlock( hGlobal);
  535. stream.Advance(ulDataSize);
  536. }
  537. }
  538. else if (IS_HANDLE64_MARKER( UnionDisc ))
  539. {
  540. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  541. {
  542. // Hey, you can't send us one of these!
  543. RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
  544. }
  545. // Make sure the old stuff is cleaned up...
  546. if ( *pGlobal != hGlobal && *pGlobal )
  547. GlobalFree( *pGlobal );
  548. }
  549. else
  550. {
  551. RAISE_RPC_EXCEPTION( RPC_S_INVALID_TAG );
  552. }
  553. *pGlobal = hGlobal;
  554. return( stream.GetBuffer() );
  555. }
  556. //+-------------------------------------------------------------------------
  557. //
  558. // Function: HGLOBAL_UserUnmarshal64
  559. //
  560. // Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
  561. //
  562. // Derivation: Conformant struct with a flag field:
  563. // align, size, null flag, size, data (bytes, if any)
  564. //
  565. // history: Dec-00 JohnDoty Created from 32bit function
  566. //
  567. //--------------------------------------------------------------------------
  568. unsigned char __RPC_FAR * __RPC_USER
  569. HGLOBAL_UserUnmarshal64 (
  570. unsigned long * pFlags,
  571. unsigned char * pBuffer,
  572. HGLOBAL * pGlobal)
  573. {
  574. // Get the buffer size and the start of the buffer.
  575. CUserMarshalInfo MarshalInfo( pFlags, pBuffer );
  576. ULONG_PTR BufferSize = MarshalInfo.GetBufferSize();
  577. UCHAR* pBufferStart = MarshalInfo.GetBuffer();
  578. pBuffer = WdtpGlobalUnmarshal64( pFlags,
  579. pBufferStart,
  580. pGlobal,
  581. TRUE, // reallocation possible
  582. BufferSize );
  583. return( pBuffer );
  584. }
  585. //+-------------------------------------------------------------------------
  586. //
  587. // Function: HGLOBAL_UserFree64
  588. //
  589. // Synopsis: Free an HGLOBAL.
  590. //
  591. // history: Dec-00 JohnDoty Created from 32bit function
  592. //
  593. //--------------------------------------------------------------------------
  594. void __RPC_USER
  595. HGLOBAL_UserFree64 (
  596. unsigned long * pFlags,
  597. HGLOBAL * pGlobal)
  598. {
  599. if( pGlobal && *pGlobal )
  600. {
  601. if ( HGLOBAL_DATA_PASSING(*pFlags) )
  602. GlobalFree( *pGlobal);
  603. }
  604. }
  605. #endif