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.

1563 lines
42 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // ctemacro.c
  4. //
  5. // This file contains macros for the common transport environment - similar
  6. // to the way that ctestuff.c contains common procedures.
  7. //
  8. #ifndef _CTEMACRO_H_
  9. #define _CTEMACRO_H_
  10. #ifndef VXD
  11. #define NT 1
  12. #include <cxport.h>
  13. #ifdef _PNP_POWER_
  14. #define _PNP_POWER_DBG_ 1
  15. #endif // _PNP_POWER_
  16. char LastLockFile[255] ;
  17. int LastLockLine ;
  18. char LastUnlockFile[255] ;
  19. int LastUnlockLine ;
  20. #endif
  21. #ifdef VXD
  22. #ifdef DEBUG
  23. #define DBG_PRINT 1
  24. #else
  25. #endif // DEBUG
  26. #endif // VXD
  27. //----------------------------------------------------------------------------
  28. #define IS_UNIQUE_ADDR(IpAddress) ((((PUCHAR)(&IpAddress))[3]) < ((UCHAR)0xe0))
  29. //----------------------------------------------------------------------------
  30. //------------------------------------------------------------------------------
  31. //
  32. // This HACK is being to avoid NetBT from logging Events whenever the Messenger
  33. // name goes into conflict. This is TEMPORARY ONLY, and the proper fix (post NT5)
  34. // is:
  35. // 1) Change the Duplicate name error to a Warning
  36. // 2) Log the name + Device on which error occurred + IP address
  37. //
  38. #define IS_MESSENGER_NAME(_pName) \
  39. (_pName[15] == 0x03)
  40. //------------------------------------------------------------------------------
  41. // VOID
  42. // NTDereferenceObject(
  43. // PFILE_OBJECT pFileObject
  44. // )
  45. /*++
  46. Routine Description:
  47. This routine dereferences an object.
  48. --*/
  49. #ifdef VXD
  50. //
  51. // No equivalent for Vxd
  52. //
  53. #define NTDereferenceObject( fileobject )
  54. #else //VXD
  55. #define NTDereferenceObject( fileobject ) ObDereferenceObject( fileobject)
  56. #endif
  57. //----------------------------------------------------------------------------
  58. // VOID
  59. // CHECK_PTR(
  60. // PVOID SpinLock,
  61. // )
  62. /*++
  63. Routine Description:
  64. This routine checks if a ptr points to freed memory
  65. --*/
  66. #if DBG
  67. #define CHECK_PTR(_Ptr) \
  68. ASSERT(MmIsAddressValid(_Ptr));
  69. #else
  70. #define CHECK_PTR(_Ptr)
  71. #endif
  72. #ifndef VXD
  73. /*++
  74. This macro verifies that an IRP passed to IoCallDriver() is
  75. set up to call the CompletionRoutine in all cases.
  76. --*/
  77. #if DBG
  78. #define CHECK_COMPLETION(__pIrp)\
  79. {\
  80. PIO_STACK_LOCATION __pIrpSp = IoGetNextIrpStackLocation(__pIrp);\
  81. BOOL CompletionWillBeCalled =\
  82. ( __pIrpSp->Control & ( SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL ) )\
  83. == ( SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL );\
  84. ASSERT ( CompletionWillBeCalled );\
  85. }
  86. #else // DBG
  87. #define CHECK_COMPLETION(__pIrp)
  88. #endif // DBG
  89. #endif // VXD
  90. //
  91. // Macros
  92. //
  93. //++
  94. //
  95. // LARGE_INTEGER
  96. // CTEConvertMillisecondsTo100ns(
  97. // IN LARGE_INTEGER MsTime
  98. // );
  99. //
  100. // Routine Description:
  101. //
  102. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  103. //
  104. // Arguments:
  105. //
  106. // MsTime - Time in milliseconds.
  107. //
  108. // Return Value:
  109. //
  110. // Time in hundreds of nanoseconds.
  111. //
  112. //--
  113. #define CTEConvertMillisecondsTo100ns(MsTime) \
  114. RtlExtendedIntegerMultiply(MsTime, 10000)
  115. //++
  116. //
  117. // LARGE_INTEGER
  118. // CTEConvert100nsToMilliseconds(
  119. // IN LARGE_INTEGER HnsTime
  120. // );
  121. //
  122. // Routine Description:
  123. //
  124. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  125. //
  126. // Arguments:
  127. //
  128. // HnsTime - Time in hundreds of nanoseconds.
  129. //
  130. // Return Value:
  131. //
  132. // Time in milliseconds.
  133. //
  134. //--
  135. // Used in the conversion of 100ns times to milliseconds.
  136. static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  137. #define SHIFT10000 13
  138. extern LARGE_INTEGER Magic10000;
  139. #define CTEConvert100nsToMilliseconds(HnsTime) \
  140. RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
  141. //----------------------------------------------------------------------------
  142. //
  143. // CTELockHandle
  144. //
  145. #ifndef VXD
  146. //
  147. // The Spinlock structure is different between the NT driver and the VXD
  148. // driver. This macro is defined in cxport.h when compiling as a VXD.
  149. //
  150. #define CTELockHandle KIRQL
  151. #endif
  152. //----------------------------------------------------------------------------
  153. // VOID
  154. // CTESpinLock(
  155. // tCONNECTELE Structure,
  156. // CTELockHandle OldIrqLevel
  157. // )
  158. /*++
  159. Routine Description:
  160. This Routine acquires a spin lock.
  161. Arguments:
  162. Size - the number of bytes to allocate
  163. Return Value:
  164. PVOID - a pointer to the memory or NULL if a failure
  165. --*/
  166. #ifndef VXD
  167. #if DBG
  168. #define CTESpinLock(DataStruct,OldIrqLevel) \
  169. { \
  170. AcquireSpinLockDebug(&(DataStruct)->LockInfo,&OldIrqLevel,__LINE__); \
  171. strcpy( LastLockFile, __FILE__ ) ; \
  172. LastLockLine = __LINE__ ; \
  173. }
  174. #else
  175. #define CTESpinLock(DataStruct,OldIrqLevel) \
  176. { \
  177. CTEGetLock(&(DataStruct)->LockInfo.SpinLock,&(OldIrqLevel)); \
  178. }
  179. #endif
  180. #else
  181. #ifdef DEBUG
  182. #define CTESpinLock(DataStruct,OldIrqLevel) \
  183. { \
  184. CTEGetLock( &(DataStruct)->LockInfo.SpinLock, &OldIrqLevel ) ; \
  185. }
  186. #else
  187. #define CTESpinLock(DataStruct,OldIrqLevel)
  188. #endif // !DEBUG
  189. #endif
  190. //----------------------------------------------------------------------------
  191. // VOID
  192. // CTESpinFree(
  193. // PVOID SpinLock,
  194. // CTELockHandle OldIrqLevel
  195. // )
  196. /*++
  197. Routine Description:
  198. This Routine releases a spin lock.
  199. Arguments:
  200. Size - the number of bytes to allocate
  201. Return Value:
  202. PVOID - a pointer to the memory or NULL if a failure
  203. --*/
  204. #ifndef VXD
  205. #if DBG
  206. #define CTESpinFree(DataStruct,OldIrqLevel) \
  207. { \
  208. strcpy( LastUnlockFile, __FILE__ ) ; \
  209. LastUnlockLine = __LINE__ ; \
  210. FreeSpinLockDebug(&(DataStruct)->LockInfo,OldIrqLevel,__LINE__); \
  211. }
  212. #else
  213. #define CTESpinFree(DataStruct,OldIrqLevel) \
  214. { \
  215. CTEFreeLock((PKSPIN_LOCK)(&(DataStruct)->LockInfo.SpinLock),(OldIrqLevel)); \
  216. }
  217. #endif
  218. #else
  219. #ifdef DEBUG
  220. #define CTESpinFree(DataStruct,OldIrqLevel) \
  221. { \
  222. CTEFreeLock( &(DataStruct)->LockInfo.SpinLock, OldIrqLevel ) ; \
  223. }
  224. #else
  225. #define CTESpinFree(DataStruct,OldIrqLevel)
  226. #endif
  227. #endif
  228. //----------------------------------------------------------------------------
  229. // VOID
  230. // CTESpinLockAtDpc(
  231. // tCONNECTELE Structure
  232. // )
  233. /*++
  234. Routine Description:
  235. This Routine acquires a spin lock.
  236. Arguments:
  237. Size - the number of bytes to allocate
  238. Return Value:
  239. PVOID - a pointer to the memory or NULL if a failure
  240. --*/
  241. #ifndef VXD
  242. #if DBG
  243. #define CTESpinLockAtDpc(DataStruct) \
  244. { \
  245. AcquireSpinLockAtDpcDebug(&(DataStruct)->LockInfo,__LINE__); \
  246. strcpy( LastLockFile, __FILE__ ) ; \
  247. LastLockLine = __LINE__ ; \
  248. }
  249. #else // DBG
  250. #define CTESpinLockAtDpc(DataStruct) \
  251. { \
  252. CTEGetLockAtDPC((PKSPIN_LOCK)(&(DataStruct)->LockInfo.SpinLock)); \
  253. }
  254. #endif // DBG
  255. #else // VXD
  256. #define CTESpinLockAtDpc(DataStruct)
  257. #endif // VXD
  258. //----------------------------------------------------------------------------
  259. // VOID
  260. // CTESpinFreeAtDpc(
  261. // PVOID SpinLock,
  262. // CTELockHandle OldIrqLevel
  263. // )
  264. /*++
  265. Routine Description:
  266. This Routine releases a spin lock.
  267. Arguments:
  268. Size - the number of bytes to allocate
  269. Return Value:
  270. PVOID - a pointer to the memory or NULL if a failure
  271. --*/
  272. #ifndef VXD
  273. #if DBG
  274. #define CTESpinFreeAtDpc(DataStruct) \
  275. { \
  276. strcpy( LastUnlockFile, __FILE__ ) ; \
  277. LastUnlockLine = __LINE__ ; \
  278. FreeSpinLockAtDpcDebug(&(DataStruct)->LockInfo,__LINE__); \
  279. }
  280. #else // DBG
  281. #define CTESpinFreeAtDpc(DataStruct) \
  282. { \
  283. CTEFreeLockFromDPC((PKSPIN_LOCK)(&(DataStruct)->LockInfo.SpinLock)); \
  284. }
  285. #endif // DBG
  286. #else // VXD
  287. #define CTESpinFreeAtDpc(DataStruct)
  288. #endif // VXD
  289. //----------------------------------------------------------------------------
  290. //
  291. // VOID
  292. // CTEVerifyHandle(
  293. // IN PVOID pDataStruct,
  294. // IN ULONG Verifier,
  295. // IN VOID TypeofStruct,
  296. // OUT NTSTATUS *pRet
  297. // )
  298. /*++
  299. Routine Description:
  300. This Routine checks that a handle pts to a data structure with the
  301. correct verifier in it.
  302. Arguments:
  303. Size - the number of bytes to allocate
  304. Return Value:
  305. NTSTATUS
  306. --*/
  307. #ifndef VXD
  308. #if DBG
  309. #define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret) \
  310. { \
  311. if ((_pDataStruct) && \
  312. ((((_TypeofStruct *)(_pDataStruct))->Verify) == (_Verifier))) \
  313. *_ret=STATUS_SUCCESS; \
  314. else \
  315. { \
  316. ASSERTMSG("Invalid Handle Passed to Nbt",0); \
  317. return(STATUS_INVALID_HANDLE); \
  318. } \
  319. }
  320. #else
  321. #define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret)
  322. #endif // DBG
  323. #else
  324. #define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret) \
  325. { \
  326. if ((((_TypeofStruct *)(_pDataStruct))->Verify) == (_Verifier)) \
  327. *_ret=STATUS_SUCCESS; \
  328. else \
  329. return(STATUS_INVALID_HANDLE); \
  330. }
  331. #endif
  332. #define NBT_VERIFY_HANDLE(s, V) \
  333. ((s) && (s->Verify == V))
  334. #define NBT_VERIFY_HANDLE2(s, V1, V2) \
  335. ((s) && ((s->Verify == V1) || (s->Verify == V2)))
  336. //----------------------------------------------------------------------------
  337. //
  338. // VOID
  339. // CTEIoComplete( IN CTE_IRP * pIrp,
  340. // IN NTSTATUS StatusCompletion,
  341. // IN ULONG cbBytes
  342. // );
  343. //
  344. /*++
  345. Routine Description:
  346. Completes the requested IO packet. For NT this involves calling the IO
  347. subsytem. As a VxD, the Irp is a pointer to the NCB so we set the status
  348. variables appropriately and call the post routine if present.
  349. Arguments:
  350. pIrp - Packet to complete
  351. StatusCompletion - Status of the completion
  352. cbBytes - Dependent on the type of IO
  353. Return Value:
  354. --*/
  355. #ifndef VXD
  356. #define PCTE_MDL PMDL
  357. #define CTE_IRP IRP
  358. #define PCTE_IRP PIRP
  359. #define CTE_ADDR_HANDLE PFILE_OBJECT
  360. #define CTEIoComplete( pIrp, StatusCompletion, cbBytes ) \
  361. NTIoComplete( pIrp, StatusCompletion, cbBytes )
  362. #else
  363. #define PCTE_MDL PVOID
  364. #define CTE_IRP NCB
  365. #define PCTE_IRP PNCB
  366. #define PIRP PNCB
  367. #define CTE_ADDR_HANDLE PVOID
  368. #define PFILE_OBJECT CTE_ADDR_HANDLE
  369. #define CTEIoComplete( pIrp, StatusCompletion, cbBytes ) \
  370. VxdIoComplete( pIrp, StatusCompletion, cbBytes )
  371. #endif
  372. //----------------------------------------------------------------------------
  373. //
  374. // ULONG
  375. // CTEMemCmp( PVOID S1, PVOID S2, ULONG Length )
  376. //
  377. /*++
  378. Routine Description:
  379. Compares two memory regions and returns the byte count at which the
  380. compare failed. The return value will equal Length if the memory
  381. regions are identical.
  382. Arguments:
  383. S1, S2 - Memory source 1 and 2 to compare
  384. Length - Count of bytes to compare
  385. Return Value:
  386. --*/
  387. //
  388. // CXPORT.H defines this macro differntly and they did it after we had
  389. // it here, so undef their definition so we can use ours without getting
  390. // warnings.
  391. //
  392. #undef CTEMemCmp
  393. #ifndef VXD
  394. #define CTEMemCmp( S1, S2, Length ) RtlCompareMemory( (S1), (S2), (Length) )
  395. #else
  396. //
  397. // Same thing as RtlCompareMemory except avoid standard call decoration
  398. //
  399. #define CTEMemCmp( S1, S2, Length ) VxdRtlCompareMemory( (S1), (S2), (Length) )
  400. #endif
  401. //----------------------------------------------------------------------------
  402. //
  403. // LOGICAL
  404. // CTEMemEqu( PVOID S1, PVOID S2, ULONG Length )
  405. //
  406. /*++
  407. Routine Description:
  408. Compares two memory regions and returns a value of TRUE is the regions
  409. match. Otherwise, FALSE is returned.
  410. Arguments:
  411. S1, S2 - Memory source 1 and 2 to compare
  412. Length - Count of bytes to compare
  413. Return Value:
  414. --*/
  415. #ifndef VXD
  416. #define CTEMemEqu( S1, S2, Length ) RtlEqualMemory( (S1), (S2), (Length) )
  417. #else
  418. //
  419. // Same thing as RtlEqualMemory except avoid standard call decoration
  420. //
  421. #define CTEMemEqu( S1, S2, Length ) ( VxdRtlCompareMemory( (S1), (S2), (Length) ) == (Length) )
  422. #endif
  423. //----------------------------------------------------------------------------
  424. //
  425. // Define away any try and except clauses when we are a VXD
  426. //
  427. #ifndef VXD
  428. #define CTE_try try
  429. #define CTE_except except
  430. #else
  431. #define CTE_try
  432. #define CTE_except( x ) if ( 0 )
  433. #endif
  434. //
  435. // Misc. memory routines that get mapped when compiling as a VXD
  436. //
  437. #ifdef VXD
  438. #define CTEZeroMemory( pDest, uLength ) CTEMemSet( pDest, 0, uLength )
  439. #define CTEMemFree( p ) CTEFreeMem( p )
  440. #endif
  441. //----------------------------------------------------------------------------
  442. /*++
  443. PVOID
  444. CTEAllocMem(
  445. USHORT Size
  446. )
  447. Routine Description:
  448. This Routine allocates memory for NT drivers by calling ExAllocatePool
  449. It uses the definition of CTEAllocMem from cxport.h
  450. Arguments:
  451. Size - the number of bytes to allocate
  452. Return Value:
  453. PVOID - a pointer to the memory or NULL if a failure
  454. --*/
  455. #ifndef VXD
  456. #ifdef POOL_TAGGING
  457. #undef ExAllocatePool
  458. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' tbN')
  459. #endif
  460. #endif
  461. #ifndef VXD
  462. #ifdef POOL_TAGGING
  463. #define NBT_TAG(x) (((x)<<24)|'\0tbN')
  464. #define NBT_TAG2(x) ( ((x & 0xff)<<24) | ((x & 0xff00)<<8) | '\0bN' )
  465. #define NbtAllocMem(size,__tag__) ExAllocatePoolWithTag(NonPagedPool,(size),(__tag__))
  466. #else // POOL_TAGGING
  467. #define NBT_TAG(x) 0
  468. #define NBT_TAG2(x) 0
  469. #define NbtAllocMem(size,__tag__) ExAllocatePool(NonPagedPool,(size))
  470. #endif // POOL_TAGGING
  471. #else // POOL_TAGGING
  472. #define NBT_TAG(x) 0
  473. #define NBT_TAG2(x) 0
  474. #define NbtAllocMem(size,__tag__) CTEAllocMem((size))
  475. #endif // VXD
  476. #ifdef VXD
  477. #ifdef DEBUG
  478. #undef CTEAllocMem
  479. #define CTEAllocMem DbgAllocMem
  480. #undef CTEFreeMem
  481. #define CTEFreeMem DbgFreeMem
  482. #undef CTEMemFree
  483. #define CTEMemFree DbgFreeMem
  484. PVOID DbgAllocMem( DWORD ReqSize );
  485. VOID DbgFreeMem( PVOID pBufferToFree );
  486. VOID DbgMemCopy( PVOID pDestBuf, PVOID pSrcBuf, ULONG Length );
  487. #endif
  488. #endif
  489. //----------------------------------------------------------------------------
  490. /*++
  491. PVOID
  492. CTEAllocInitMem(
  493. ULONG Size
  494. )
  495. Routine Description:
  496. This Routine allocates memory and if nbt is a Vxd and it's called during
  497. DeviceInit time, will refill the heap and retry the allocation before
  498. failing.
  499. Arguments:
  500. Size - the number of bytes to allocate
  501. Return Value:
  502. PVOID - a pointer to the memory or NULL if a failure
  503. --*/
  504. #ifndef VXD
  505. #define CTEAllocInitMem(Size) \
  506. ExAllocatePool(NonPagedPool, Size)
  507. #endif
  508. //----------------------------------------------------------------------------
  509. /*++
  510. VOID
  511. CTEMemFree(
  512. PVOID pMem
  513. )
  514. Routine Description:
  515. This Routine frees memory for NT drivers by calling ExFreePool
  516. Arguments:
  517. pMem - ptr to memory
  518. Return Value:
  519. NONE
  520. --*/
  521. #ifndef VXD
  522. #define CTEMemFree(pMem) \
  523. { \
  524. IF_DBG(NBT_DEBUG_MEMFREE) \
  525. KdPrint(("Nbt.CTEMemFree: pmemfree = %X,lin %d in file %s\n",pMem,__LINE__,__FILE__)); \
  526. CTEFreeMem(pMem); \
  527. }
  528. #endif
  529. //----------------------------------------------------------------------------
  530. /*++
  531. VOID
  532. CTEZeroMemory(
  533. PVOID pDest,
  534. ULONG uLength
  535. )
  536. Routine Description:
  537. This Routine sets memory to a single byte value
  538. Arguments:
  539. pDest - dest address
  540. uLength - number to zero
  541. Return Value:
  542. NONE
  543. --*/
  544. #ifndef VXD
  545. #define CTEZeroMemory(pDest,uLength) \
  546. RtlZeroMemory(pDest,uLength)
  547. #endif
  548. //----------------------------------------------------------------------------
  549. /*++
  550. NTSTATUS
  551. CTEReadIniString(
  552. HANDLE ParmHandle,
  553. LPTSTR KeyName,
  554. LPTSTR * ppStringBuff
  555. )
  556. Routine Description:
  557. This routine retrieves a string from the users configuration profile
  558. Arguments:
  559. ParmHandle - Registry handle
  560. KeyName - Name of value to retrieve
  561. ppStringBuff - Pointer to allocated buffer containing found string
  562. Return Value:
  563. NTSTATUS
  564. --*/
  565. #ifndef VXD
  566. #define CTEReadIniString( ParmHandle, KeyName, ppStringBuff ) \
  567. NTReadIniString( ParmHandle, KeyName, ppStringBuff )
  568. #else
  569. #define CTEReadIniString( ParmHandle, KeyName, ppStringBuff ) \
  570. VxdReadIniString( KeyName, ppStringBuff )
  571. #endif
  572. //----------------------------------------------------------------------------
  573. /*++
  574. ULONG
  575. CTEReadSingleHexParameter(
  576. HANDLE ParmHandle,
  577. LPTSTR KeyName,
  578. ULONG Default,
  579. ULONG Minimum
  580. )
  581. Routine Description:
  582. This routine retrieves a value in hex from the .ini file or registry
  583. Arguments:
  584. ParmHandle - Registry handle
  585. KeyName - Name of value to retrieve
  586. Default - Default value if not present
  587. Minimum - Minimum value if present
  588. Return Value:
  589. NTSTATUS
  590. --*/
  591. #ifndef VXD
  592. #define CTEReadSingleIntParameter( ParmHandle, KeyName, Default, Minimum ) \
  593. NbtReadSingleParameter( ParmHandle, KeyName, Default, Minimum )
  594. #define CTEReadSingleHexParameter( ParmHandle, KeyName, Default, Minimum ) \
  595. NbtReadSingleParameter( ParmHandle, KeyName, Default, Minimum )
  596. #else
  597. #define CTEReadSingleIntParameter( ParmHandle, KeyName, Default, Minimum ) \
  598. GetProfileInt( ParmHandle, KeyName, Default, Minimum )
  599. #define CTEReadSingleHexParameter( ParmHandle, KeyName, Default, Minimum ) \
  600. GetProfileHex( ParmHandle, KeyName, Default, Minimum )
  601. #endif
  602. //----------------------------------------------------------------------------
  603. //
  604. // NBT_REFERENCE_XXX(_pXXX)
  605. //
  606. /*++
  607. Routine Description:
  608. Increments the reference count
  609. Arguments:
  610. - the structure to be referenced
  611. Return Value:
  612. None
  613. --*/
  614. //----------------------------------------------------------------------------
  615. #define NBT_REFERENCE_CONNECTION( _pConnEle, _RefContext ) \
  616. { \
  617. IF_DBG(NBT_DEBUG_REF) \
  618. KdPrint(("\t++pConnEle=<%x:%d->%d>, <%d:%s>\n", \
  619. _pConnEle,_pConnEle->RefCount,(_pConnEle->RefCount+1),__LINE__,__FILE__)); \
  620. ASSERT ((_pConnEle->Verify==NBT_VERIFY_CONNECTION) || (_pConnEle->Verify==NBT_VERIFY_CONNECTION_DOWN)); \
  621. InterlockedIncrement(&_pConnEle->RefCount); \
  622. ASSERT (++_pConnEle->References[_RefContext]); \
  623. }
  624. #define NBT_REFERENCE_LOWERCONN( _pLowerConn, _RefContext ) \
  625. { \
  626. IF_DBG(NBT_DEBUG_REF) \
  627. KdPrint(("\t++pLowerConn=<%x:%d->%d>, <%d:%s>\n", \
  628. _pLowerConn,_pLowerConn->RefCount,(_pLowerConn->RefCount+1),__LINE__,__FILE__)); \
  629. ASSERT (_pLowerConn->Verify == NBT_VERIFY_LOWERCONN); \
  630. InterlockedIncrement(&_pLowerConn->RefCount); \
  631. ASSERT (++_pLowerConn->References[_RefContext]); \
  632. }
  633. #define NBT_REFERENCE_CLIENT( _pClient ) \
  634. { \
  635. IF_DBG(NBT_DEBUG_REF) \
  636. KdPrint(("\t++pClient=<%x:%d->%d>, <%d:%s>\n", \
  637. _pClient,_pClient->RefCount,(_pClient->RefCount+1),__LINE__,__FILE__)); \
  638. ASSERT (NBT_VERIFY_HANDLE (_pClient, NBT_VERIFY_CLIENT)); \
  639. ASSERT (NBT_VERIFY_HANDLE (_pClient->pAddress, NBT_VERIFY_ADDRESS)); \
  640. InterlockedIncrement(&_pClient->RefCount); \
  641. }
  642. #define NBT_REFERENCE_ADDRESS( _pAddrEle, _Context ) \
  643. { \
  644. IF_DBG(NBT_DEBUG_REF) \
  645. KdPrint(("\t++pAddrEle=<%x:%d->%d>, <%d:%s>\n", \
  646. _pAddrEle,_pAddrEle->RefCount,(_pAddrEle->RefCount+1),__LINE__,__FILE__)); \
  647. ASSERT (NBT_VERIFY_HANDLE (_pAddrEle, NBT_VERIFY_ADDRESS)); \
  648. InterlockedIncrement(&_pAddrEle->RefCount); \
  649. }
  650. #define NBT_REFERENCE_NAMEADDR(_pNameAddr, _RefContext) \
  651. { \
  652. IF_DBG(NBT_DEBUG_REF) \
  653. KdPrint(("\t++pNameAddr=<%x:%d->%d>, <%d:%s>\n", \
  654. _pNameAddr,_pNameAddr->RefCount,(_pNameAddr->RefCount+1),__LINE__,__FILE__)); \
  655. ASSERT ((_pNameAddr->Verify == LOCAL_NAME) || \
  656. (_pNameAddr->Verify == REMOTE_NAME)); \
  657. InterlockedIncrement(&_pNameAddr->RefCount); \
  658. ASSERT (++_pNameAddr->References[_RefContext]); \
  659. }
  660. #define NBT_REFERENCE_TRACKER( _pTracker ) \
  661. { \
  662. IF_DBG(NBT_DEBUG_REF) \
  663. KdPrint(("\t++pTracker=<%x:%d->%d>, <%d:%s>\n", \
  664. _pTracker,_pTracker->RefCount,(_pTracker->RefCount+1),__LINE__,__FILE__)); \
  665. ASSERT (_pTracker->Verify == NBT_VERIFY_TRACKER); \
  666. InterlockedIncrement(&_pTracker->RefCount); \
  667. }
  668. //----------------------------------------------------------------------------
  669. //
  670. // NBT_DEREFERENCE_XXX(_pXXX)
  671. //
  672. /*++
  673. Routine Description:
  674. Wrapper for the real Derefencing routine
  675. Arguments:
  676. - the structure to be de-referenced
  677. Return Value:
  678. None
  679. --*/
  680. //----------------------------------------------------------------------------
  681. #define NBT_DEREFERENCE_LOWERCONN( _pLowerConn, _RefContext, fJointLockHeld ) \
  682. { \
  683. IF_DBG(NBT_DEBUG_REF) \
  684. KdPrint(("\t--pLowerConn=<%x:%d->%d>, <%d:%s>\n", \
  685. _pLowerConn,_pLowerConn->RefCount,(_pLowerConn->RefCount-1),__LINE__,__FILE__)); \
  686. ASSERT (_pLowerConn->Verify == NBT_VERIFY_LOWERCONN); \
  687. NbtDereferenceLowerConnection(_pLowerConn, _RefContext, fJointLockHeld); \
  688. }
  689. #define NBT_SWAP_REFERENCE_LOWERCONN(_pLowerConn, _RefContextOld, _RefContextNew, _fLowerLockHeld) \
  690. { \
  691. CTELockHandle OldIrqSwap; \
  692. \
  693. if (!_fLowerLockHeld) \
  694. { \
  695. CTESpinLock (_pLowerConn, OldIrqSwap); \
  696. } \
  697. ASSERT (NBT_VERIFY_HANDLE (_pLowerConn, NBT_VERIFY_LOWERCONN)); \
  698. ASSERT (_pLowerConn->RefCount); \
  699. ASSERT (++_pLowerConn->References[_RefContextNew]); \
  700. ASSERT (_pLowerConn->References[_RefContextOld]--); \
  701. if (!_fLowerLockHeld) \
  702. { \
  703. CTESpinFree (_pLowerConn, OldIrqSwap); \
  704. } \
  705. }
  706. #define NBT_DEREFERENCE_NAMEADDR(_pNameAddr, _RefContext, _fLocked) \
  707. { \
  708. IF_DBG(NBT_DEBUG_REF) \
  709. KdPrint(("\t--pNameAddr=<%x:%d->%d>, <%d:%s>\n", \
  710. _pNameAddr,_pNameAddr->RefCount,(_pNameAddr->RefCount-1),__LINE__,__FILE__)); \
  711. ASSERT ((_pNameAddr->Verify==LOCAL_NAME) || (_pNameAddr->Verify==REMOTE_NAME)); \
  712. NbtDereferenceName(_pNameAddr, _RefContext, _fLocked); \
  713. }
  714. #define NBT_DEREFERENCE_TRACKER( _pTracker, _fLocked ) \
  715. { \
  716. IF_DBG(NBT_DEBUG_REF) \
  717. KdPrint(("\t--pTracker=<%x:%d->%d>, <%d:%s>\n", \
  718. _pTracker,_pTracker->RefCount,(_pTracker->RefCount-1),__LINE__,__FILE__)); \
  719. ASSERT (_pTracker->Verify == NBT_VERIFY_TRACKER); \
  720. NbtDereferenceTracker(_pTracker, _fLocked); \
  721. }
  722. #define NBT_DEREFERENCE_CONNECTION( _pConnEle, _RefContext )\
  723. { \
  724. NbtDereferenceConnection(_pConnEle, _RefContext); \
  725. }
  726. #define NBT_DEREFERENCE_CLIENT( _pClient ) \
  727. { \
  728. NbtDereferenceClient(_pClient); \
  729. }
  730. #define NBT_DEREFERENCE_ADDRESS( _pAddressEle, _Context ) \
  731. { \
  732. NbtDereferenceAddress(_pAddressEle, _Context); \
  733. }
  734. //----------------------------------------------------------------------------
  735. //
  736. // CTEExInitializeResource(Resource)
  737. //
  738. /*++
  739. Routine Description:
  740. Initializes the Resource structure by calling an excutive support routine.
  741. Arguments:
  742. Return Value:
  743. None
  744. --*/
  745. #ifndef VXD
  746. #define CTEExInitializeResource( _Resource ) \
  747. ExInitializeResourceLite(_Resource)
  748. #else
  749. #define CTEExInitializeResource( _Resource )
  750. #endif
  751. //----------------------------------------------------------------------------
  752. //
  753. // CTEExAcquireResourceExclusive(Resource,Wait)
  754. //
  755. /*++
  756. Routine Description:
  757. Acquires the Resource by calling an excutive support routine.
  758. Arguments:
  759. Return Value:
  760. None
  761. --*/
  762. #ifndef VXD
  763. #define CTEExAcquireResourceExclusive( _Resource, _Wait ) \
  764. KeEnterCriticalRegion(); \
  765. ExAcquireResourceExclusiveLite(_Resource,_Wait);
  766. #else
  767. #define CTEExAcquireResourceExclusive( _Resource, _Wait )
  768. #endif
  769. //----------------------------------------------------------------------------
  770. //
  771. // CTEExReleaseResource(Resource)
  772. //
  773. /*++
  774. Routine Description:
  775. Releases the Resource by calling an excutive support routine.
  776. Arguments:
  777. Return Value:
  778. None
  779. --*/
  780. #ifndef VXD
  781. #define CTEExReleaseResource( _Resource ) \
  782. ExReleaseResourceLite(_Resource); \
  783. KeLeaveCriticalRegion();
  784. #else
  785. #define CTEExReleaseResource( _Resource )
  786. #endif
  787. //----------------------------------------------------------------------------
  788. //
  789. // PUSH_LOCATION(Spot)
  790. //
  791. /*++
  792. Routine Description:
  793. This macro is used for debugging the receive code. It puts a byte value
  794. into a circular list of byte values so that previous history can be traced
  795. through the receive code.
  796. Arguments:
  797. Spot - the location to put in the list
  798. Return Value:
  799. None
  800. --*/
  801. #if DBG
  802. extern unsigned char pLocBuff[256];
  803. extern unsigned char CurrLoc;
  804. #define PUSH_LOCATION( _Spot) \
  805. { \
  806. if (++CurrLoc == 256) \
  807. { \
  808. CurrLoc = 0; \
  809. } \
  810. pLocBuff[CurrLoc] = _Spot; \
  811. }
  812. #else
  813. #define PUSH_LOCATION( _Spot )
  814. #endif
  815. #if DBG
  816. extern unsigned char Buff[256];
  817. extern unsigned char Loc;
  818. #define LOCATION( _Spot) \
  819. { \
  820. if (++Loc == 256) \
  821. { \
  822. Loc = 0; \
  823. } \
  824. Buff[Loc] = _Spot; \
  825. }
  826. #else
  827. #define LOCATION( _Spot )
  828. #endif
  829. //----------------------------------------------------------------------------
  830. //
  831. // CTEQueueForNonDispProcessing( DelayedWorkerRoutine,
  832. // pTracker,
  833. // pClientContext,
  834. // ClientCompletion,
  835. // pDeviceContext,
  836. // fJointLockHeld) ;
  837. //
  838. /*++
  839. Routine Description:
  840. This macro queues a request for a callback that can't be performed in
  841. the current context (such as dispatch processing).
  842. In NT, this calls NTQueueToWorkerThread.
  843. As a VxD, we schedule an event that calls the specified routine.
  844. Arguments:
  845. pTracker - pointer to a tDGRAM_SEND_TRACKING structure (or NULL).
  846. pClietContext - Context to pass to CallBackRoutine
  847. ClientCompletion -
  848. CallBackRoutine - Procedure to call at outside the current context
  849. Return Value:
  850. STATUS_SUCCESS if successful, error code otherwise
  851. --*/
  852. #ifndef VXD
  853. #else
  854. #define CTEQueueForNonDispProcessing( DelayedWorkerRoutine, \
  855. pTracker, \
  856. pClientContext, \
  857. ClientCompletion, \
  858. pDeviceContext, \
  859. fJointLockHeld) \
  860. VxdScheduleDelayedCall( DelayedWorkerRoutine, pTracker, pClientContext, \
  861. ClientCompletion, pDeviceContext, TRUE )
  862. // For Win98, we also need a function which schedules a call
  863. // outside of a critical section
  864. #define CTEQueueForNonCritNonDispProcessing( DelayedWorkerRoutine \
  865. pTracker, \
  866. pClientContext, \
  867. ClientCompletion, \
  868. pDeviceContext) \
  869. VxdScheduleDelayedCall( DelayedWorkerRoutine, pTracker, pClientContext, \
  870. ClientCompletion, pDeviceContext, FALSE )
  871. #endif
  872. //----------------------------------------------------------------------------
  873. //
  874. // CTESystemUpTime( OUT PTIME pTime );
  875. //
  876. /*++
  877. Routine Description:
  878. This macro returns the current system time in clock tics or whatever
  879. in the value pTime. For NT this is a Large Integer. For the VXD it is
  880. a ULONG.
  881. Arguments:
  882. pTime
  883. Return Value:
  884. NONE
  885. --*/
  886. #ifndef VXD
  887. #define CTESystemTime LARGE_INTEGER
  888. #define CTEQuerySystemTime( _Time ) \
  889. KeQuerySystemTime( &(_Time) )
  890. // the lower 4 bits appear to be zero always...!!
  891. #define RandomizeFromTime( Time, Mod ) \
  892. ((Time.LowTime >> 8) % Mod)
  893. #else
  894. #define CTESystemTime ULONG
  895. #define CTEQuerySystemTime( _Time ) \
  896. _Time = CTESystemUpTime()
  897. #define RandomizeFromTime( Time, Mod ) \
  898. ((Time >> 4) % Mod)
  899. #endif
  900. //----------------------------------------------------------------------------
  901. //
  902. // CTEPagedCode();
  903. //
  904. /*++
  905. Routine Description:
  906. This macro is used in NT to check if the Irql is above zero. All
  907. coded that is pageable has this macro call to catch any code that might
  908. be marked as pageable when in fact it isn't.
  909. Arguments:
  910. none
  911. Return Value:
  912. NONE
  913. --*/
  914. #ifndef VXD
  915. #define CTEPagedCode() PAGED_CODE()
  916. #else
  917. #define CTEPagedCode()
  918. #ifdef CHICAGO
  919. #ifdef DEBUG
  920. #undef CTEPagedCode
  921. #define CTEPagedCode() _Debug_Flags_Service(DFS_TEST_REENTER+DFS_TEST_BLOCK)
  922. #endif
  923. #endif
  924. #endif
  925. //----------------------------------------------------------------------------
  926. //
  927. // CTEMakePageable(Page,Routine);
  928. //
  929. /*++
  930. Routine Description:
  931. This macro is used in NT to activate teh alloc_text pragma, to put
  932. a procedure in the pageable code segment.
  933. Arguments:
  934. none
  935. Return Value:
  936. NONE
  937. --*/
  938. #define CTEMakePageable( _Page, _Routine ) \
  939. alloc_text(_Page,_Routine)
  940. #ifdef CHICAGO
  941. #define ALLOC_PRAGMA
  942. #define INIT _ITEXT
  943. // #define PAGE _PTEXT "vmm.h" has a macro for this. We override it later.
  944. #endif // CHICAGO
  945. //----------------------------------------------------------------------------
  946. //
  947. // NTSetCancelRoutine(pIrp,Routine);
  948. //
  949. /*++
  950. Routine Description:
  951. This macro removes the call to set the cancel routine for an irp from the
  952. VXD environment.
  953. Arguments:
  954. none
  955. Return Value:
  956. NONE
  957. --*/
  958. #ifdef VXD
  959. #define NTSetCancelRoutine(_pIrp,_CancelRoutine,_pDeviceContext) (0)
  960. #define NTCheckSetCancelRoutine(_pIrp,_CancelRoutine,_pDeviceContext) (0)
  961. #define NTClearContextCancel(pWiContext) (0)
  962. #endif
  963. //----------------------------------------------------------------------------
  964. //
  965. // NbtLogEvent(LogEvent,status)
  966. //
  967. /*++
  968. Routine Description:
  969. This macro removes the call to the log routine for the Vxd environment
  970. Arguments:
  971. none
  972. Return Value:
  973. NONE
  974. --*/
  975. #ifdef VXD
  976. #define NbtLogEvent(LogEvent,status,Info)
  977. #endif
  978. //----------------------------------------------------------------------------
  979. //
  980. // CTEGetTimeout(_pTimeout);
  981. //
  982. /*++
  983. Routine Description:
  984. This macro gets the timeout value for a connect attempt
  985. VXD environment.
  986. Arguments:
  987. none
  988. Return Value:
  989. NONE
  990. --*/
  991. #ifndef VXD
  992. #define CTEGetTimeout(pTimeout,pRetTime) \
  993. { \
  994. LARGE_INTEGER _Timeout; \
  995. ULONG Remainder; \
  996. _Timeout.QuadPart = -(((PLARGE_INTEGER)pTimeout)->QuadPart); \
  997. _Timeout = RtlExtendedLargeIntegerDivide(_Timeout,MILLISEC_TO_100NS,&Remainder);\
  998. *pRetTime = (ULONG)_Timeout.LowPart; \
  999. }
  1000. #else
  1001. //
  1002. // VXD timeout is a pointer to a ULONG
  1003. //
  1004. #define CTEGetTimeout(_pTimeout, pRet ) (*pRet = ((ULONG) _pTimeout ? *((PULONG)_pTimeout) : 0 ))
  1005. #endif
  1006. //----------------------------------------------------------------------------
  1007. //
  1008. // CTEAttachFsp()
  1009. //
  1010. /*++
  1011. Routine Description:
  1012. This macro attaches a process to the File System Process to be sure
  1013. that handles are created and released in the same process
  1014. Arguments:
  1015. Return Value:
  1016. STATUS_SUCCESS if successful, error code otherwise
  1017. --*/
  1018. #ifndef VXD
  1019. #define CTEAttachFsp(_pAttached, _Context) \
  1020. { \
  1021. if (PsGetCurrentProcess() != NbtFspProcess) \
  1022. { \
  1023. KeAttachProcess((PRKPROCESS)NbtFspProcess);\
  1024. *_pAttached = TRUE; \
  1025. } \
  1026. else \
  1027. { \
  1028. *_pAttached = FALSE; \
  1029. } \
  1030. }
  1031. #else
  1032. #define CTEAttachFsp( _pAttached, _Context )
  1033. #endif
  1034. //----------------------------------------------------------------------------
  1035. //
  1036. // CTEAttachFsp()
  1037. //
  1038. /*++
  1039. Routine Description:
  1040. This macro attaches a process to the File System Process to be sure
  1041. that handles are created and released in the same process
  1042. Arguments:
  1043. Return Value:
  1044. STATUS_SUCCESS if successful, error code otherwise
  1045. --*/
  1046. #ifndef VXD
  1047. #define CTEDetachFsp(_Attached, _Context) \
  1048. { \
  1049. if (_Attached) \
  1050. { \
  1051. KeDetachProcess(); \
  1052. } \
  1053. }
  1054. #else
  1055. #define CTEDetachFsp(_Attached, _Context)
  1056. #endif
  1057. //----------------------------------------------------------------------------
  1058. //
  1059. // CTEResetIrpPending(PIRP pIrp)
  1060. //
  1061. /*++
  1062. Routine Description:
  1063. This macro resets the irp pending bit in an irp.
  1064. Arguments:
  1065. Return Value:
  1066. STATUS_SUCCESS if successful, error code otherwise
  1067. --*/
  1068. #ifndef VXD
  1069. #define CTEResetIrpPending(pIrp) \
  1070. { \
  1071. PIO_STACK_LOCATION pIrpsp; \
  1072. pIrpsp = IoGetCurrentIrpStackLocation(pIrp);\
  1073. pIrpsp->Control &= ~SL_PENDING_RETURNED; \
  1074. }
  1075. #else
  1076. #define CTEResetIrpPending( a )
  1077. #endif
  1078. //----------------------------------------------------------------------------
  1079. //
  1080. // CTESaveClientSecurity(pClientEle)
  1081. //
  1082. /*++
  1083. Routine Description:
  1084. This macro saves the client thread security context so that it can be used
  1085. later to impersonate the client when a remote lmhosts file is openned.
  1086. Arguments:
  1087. Return Value:
  1088. --*/
  1089. #ifndef VXD
  1090. #define CTESaveClientSecurity(_pClientEle) \
  1091. /*SaveClientSecurity(_pClientEle)*/
  1092. #else
  1093. #define CTESaveClientSecurity(_pClientEle)
  1094. #endif
  1095. //----------------------------------------------------------------------------
  1096. //
  1097. // IMPERSONATE_CLIENT(pClientSecurity)
  1098. //
  1099. /*++
  1100. Routine Description:
  1101. This macro sets an excutive worker thread to impersonate a client
  1102. thread so that remote lmhost files can be openned by that thread.
  1103. Arguments:
  1104. Return Value:
  1105. --*/
  1106. #ifndef VXD
  1107. #define IMPERSONATE_CLIENT(_pClientSecurity) \
  1108. /*SeImpersonateClient((_pClientSecurity),NULL)*/
  1109. #else
  1110. #define IMPERSONATE_CLIENT(_pClientSecurity)
  1111. #endif
  1112. //----------------------------------------------------------------------------
  1113. //
  1114. // STOP_IMPERSONATE_CLIENT(pClientSecurity)
  1115. //
  1116. /*++
  1117. Routine Description:
  1118. This macro sets an excutive worker thread NOT to impersonate a client.
  1119. Arguments:
  1120. Return Value:
  1121. --*/
  1122. #ifndef VXD
  1123. #define STOP_IMPERSONATE_CLIENT(_pClientSecurity) \
  1124. /*NtSetInformationThread(PsGetCurrentThread(),ThreadImpersonationToken,NULL,sizeof(HANDLE))*/
  1125. #else
  1126. #define STOP_IMPERSONATE_CLIENT(_pClientSecurity)
  1127. #endif
  1128. //----------------------------------------------------------------------------
  1129. //
  1130. // DELETE_CLIENT_SECURITY(pTracker)
  1131. //
  1132. /*++
  1133. Routine Description:
  1134. This macro deletes a client security.
  1135. Arguments:
  1136. Return Value:
  1137. --*/
  1138. #ifndef VXD
  1139. #define DELETE_CLIENT_SECURITY(_pTracker) \
  1140. /* NtDeleteClientSecurity(_pTracker)*/
  1141. #else
  1142. #define DELETE_CLIENT_SECURITY(_pTracker)
  1143. #endif
  1144. #ifdef VXD // Taken from ntrtl.h (Vxd doesn't include NT Headers)
  1145. // Doubly-linked list manipulation routines. Implemented as macros
  1146. // but logically these are procedures.
  1147. //
  1148. //
  1149. // VOID
  1150. // InitializeListHead(
  1151. // PLIST_ENTRY ListHead
  1152. // );
  1153. //
  1154. #define InitializeListHead(ListHead) (\
  1155. (ListHead)->Flink = (ListHead)->Blink = (ListHead))
  1156. //
  1157. // BOOLEAN
  1158. // IsListEmpty(
  1159. // PLIST_ENTRY ListHead
  1160. // );
  1161. //
  1162. #define IsListEmpty(ListHead) \
  1163. ((ListHead)->Flink == (ListHead))
  1164. //
  1165. // PLIST_ENTRY
  1166. // RemoveHeadList(
  1167. // PLIST_ENTRY ListHead
  1168. // );
  1169. //
  1170. #define RemoveHeadList(ListHead) \
  1171. (ListHead)->Flink;\
  1172. {RemoveEntryList((ListHead)->Flink)}
  1173. //
  1174. // PLIST_ENTRY
  1175. // RemoveTailList(
  1176. // PLIST_ENTRY ListHead
  1177. // );
  1178. //
  1179. #define RemoveTailList(ListHead) \
  1180. (ListHead)->Blink;\
  1181. {RemoveEntryList((ListHead)->Blink)}
  1182. //
  1183. // VOID
  1184. // RemoveEntryList(
  1185. // PLIST_ENTRY Entry
  1186. // );
  1187. //
  1188. #define RemoveEntryList(Entry) {\
  1189. PLIST_ENTRY _EX_Blink;\
  1190. PLIST_ENTRY _EX_Flink;\
  1191. _EX_Flink = (Entry)->Flink;\
  1192. _EX_Blink = (Entry)->Blink;\
  1193. _EX_Blink->Flink = _EX_Flink;\
  1194. _EX_Flink->Blink = _EX_Blink;\
  1195. }
  1196. //
  1197. // VOID
  1198. // InsertTailList(
  1199. // PLIST_ENTRY ListHead,
  1200. // PLIST_ENTRY Entry
  1201. // );
  1202. //
  1203. #define InsertTailList(ListHead,Entry) {\
  1204. PLIST_ENTRY _EX_Blink;\
  1205. PLIST_ENTRY _EX_ListHead;\
  1206. _EX_ListHead = (ListHead);\
  1207. _EX_Blink = _EX_ListHead->Blink;\
  1208. (Entry)->Flink = _EX_ListHead;\
  1209. (Entry)->Blink = _EX_Blink;\
  1210. _EX_Blink->Flink = (Entry);\
  1211. _EX_ListHead->Blink = (Entry);\
  1212. }
  1213. //
  1214. // VOID
  1215. // InsertHeadList(
  1216. // PLIST_ENTRY ListHead,
  1217. // PLIST_ENTRY Entry
  1218. // );
  1219. //
  1220. #define InsertHeadList(ListHead,Entry) {\
  1221. PLIST_ENTRY _EX_Flink;\
  1222. PLIST_ENTRY _EX_ListHead;\
  1223. _EX_ListHead = (ListHead);\
  1224. _EX_Flink = _EX_ListHead->Flink;\
  1225. (Entry)->Flink = _EX_Flink;\
  1226. (Entry)->Blink = _EX_ListHead;\
  1227. _EX_Flink->Blink = (Entry);\
  1228. _EX_ListHead->Flink = (Entry);\
  1229. }
  1230. #endif // VXD
  1231. #endif // _CTEMACRO_H_