1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxRequestBase.hpp 8 9 Abstract: 10 11 This is the base class which request objects derive from for the driver 12 frameworks. 13 14 The request base object wraps the IRP, containing persistent 15 information required by the driver frameworks. 16 17 Author: 18 19 20 21 22 Environment: 23 24 Both kernel and user mode 25 26 Revision History: 27 28 --*/ 29 30 #ifndef _FXREQUESTBASE_H_ 31 #define _FXREQUESTBASE_H_ 32 33 #include "fxrequestcallbacks.hpp" 34 35 #define WDF_REQUEST_REUSE_MUST_COMPLETE 2 36 37 38 // 39 // COMPLETED - set when the request's i/o completion routine has executed 40 // 41 // PENDED - set when the request has been put onto the target's CSQ 42 // 43 // TIMER_SET - set when a timer has been queued along with sending the request 44 // down to the target 45 // 46 // CANCELLED_FROM_TIME - set by the timer to indicate that the request was 47 // cancelled by the timer DPC 48 // 49 // IGNORE_STATE - set when the request is going to be sent ignoring the 50 // state of the target. 51 // 52 enum FxRequestTargetFlags { 53 FX_REQUEST_COMPLETED = 0x01, 54 FX_REQUEST_PENDED = 0x02, 55 FX_REQUEST_TIMER_SET = 0x04, 56 FX_REQUEST_CANCELLED_FROM_TIMER = 0x08, 57 FX_REQUEST_IGNORE_STATE = 0x10, 58 }; 59 60 // 61 // internal private constraints 62 // 63 #define WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND (0x80000000) 64 65 #define WDF_REQUEST_INTERNAL_CONSTRAINTS_VALID_FLAGS \ 66 (WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND) 67 68 69 // 70 // Completion event callback prototype 71 // 72 typedef 73 VOID 74 (*PFN_COMPLETE_COPY_ROUTINE)( 75 __in FxIoTarget* This, 76 __in FxRequest* Request, 77 __in_opt FxRequestContext* Context 78 ); 79 80 81 struct FxRequestTimer : public FxStump { 82 MxTimer Timer; 83 }; 84 85 enum FxRequestAllocationSource { 86 REQUEST_ALLOCATED_FROM_IO = 0, // Irp came from the I/O package 87 REQUEST_ALLOCATED_INTERNAL = 1, // Irp was allocated internally and should be freed by the request 88 REQUEST_ALLOCATED_DRIVER = 2, // Irp was given to the request by the driver writer 89 }; 90 91 enum FxRequestIrpOwnership { 92 FxRequestOwnsIrp = 1, 93 FxRequestDoesNotOwnIrp, 94 }; 95 96 // begin_wpp config 97 // CUSTOM_TYPE(FxRequestIrpOwnership, ItemEnum(FxRequestIrpOwnership)); 98 // end_wpp 99 100 enum FxRequestConstructorCaller { 101 FxRequestConstructorCallerIsFx = 1, 102 FxRequestConstructorCallerIsDriver, 103 }; 104 105 // 106 // These defines are for VerifierFlags 107 // 108 enum FxRequestVerifierFlags { 109 // Request has been passed to the Driver 110 FXREQUEST_FLAG_DRIVER_OWNED = 0x0001, 111 112 // Request was returned as a "Tag" request to WdfIoQueuePeekNextRequest. 113 FXREQUEST_FLAG_TAG_REQUEST = 0x0002, 114 115 // Request has been forwarded from one queue to another 116 FXREQUEST_FLAG_FORWARDED = 0x0004, 117 118 // Request is being EvtIoDefault to the driver 119 FXREQUEST_FLAG_DRIVER_DISPATCH = 0x0008, 120 121 // The driver has specified the request as cancelable 122 FXREQUEST_FLAG_DRIVER_CANCELABLE = 0x0010, 123 124 FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT = 0x0020, 125 126 // The request has been cancelled 127 FXREQUEST_FLAG_CANCELLED = 0x0040, 128 129 // the next stack location has been formatted 130 FXREQUEST_FLAG_FORMATTED = 0x0080, 131 132 // the request has been sent on an I/O target and is in the target's sent list 133 FXREQUEST_FLAG_SENT_TO_TARGET = 0x0100, 134 135 // used to make sure the driver stop acknowledges in the context of EvtIoStop 136 FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT = 0x0200, 137 138 // used to indicate whether the Reserved Request is in use or on Free list 139 FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP = 0x0400, 140 }; 141 142 enum FxRequestBaseFlags { 143 FxRequestBaseSystemMdlMapped = 0x1, 144 FxRequestBaseOutputMdlMapped = 0x2, 145 FxRequestBaseSyncCleanupContext = 0x10, 146 }; 147 148 enum FxRequestBaseStaticFlags { 149 FxRequestBaseStaticSystemBufferValid = 0x1, 150 FxRequestBaseStaticOutputBufferValid = 0x2, 151 }; 152 153 // 154 // Designed to fit into a byte. FxRequestCompletionPkgFlag is a bit value 155 // used to distinguish between calling back into the io package or the current 156 // queue. When calling back into the current queue, we assume m_IoQueue is valid 157 // 158 enum FxRequestCompletionState { 159 FxRequestCompletionStateIoPkgFlag = 0x80, 160 161 FxRequestCompletionStateNone = 0x00, 162 FxRequestCompletionStateQueue = 0x01, 163 FxRequestCompletionStateIoPkg = 0x02 | FxRequestCompletionStateIoPkgFlag, 164 }; 165 166 class FxRequestBase : public FxNonPagedObject { 167 168 friend FxIoTarget; 169 friend FxSyncRequest; 170 171 public: 172 173 __inline 174 VOID 175 SetCompletionRoutine( 176 __in_opt PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine = NULL, 177 __in_opt WDFCONTEXT CompletionContext = NULL 178 ) 179 { 180 m_CompletionRoutine.m_Completion = CompletionRoutine; 181 m_TargetCompletionContext = CompletionContext; 182 } 183 184 PFN_WDF_REQUEST_COMPLETION_ROUTINE 185 ClearCompletionRoutine( 186 VOID 187 ) 188 { 189 PFN_WDF_REQUEST_COMPLETION_ROUTINE pRoutine; 190 191 pRoutine = m_CompletionRoutine.m_Completion; 192 m_CompletionRoutine.m_Completion = NULL; 193 194 return pRoutine; 195 } 196 197 WDFCONTEXT 198 ClearCompletionContext( 199 VOID 200 ) 201 { 202 WDFCONTEXT pContext; 203 204 pContext = m_TargetCompletionContext; 205 m_TargetCompletionContext = NULL; 206 207 return pContext; 208 } 209 210 __inline 211 BOOLEAN 212 IsCompletionRoutineSet( 213 VOID 214 ) 215 { 216 return (m_CompletionRoutine.m_Completion != NULL) ? 217 TRUE : FALSE; 218 } 219 220 __inline 221 BOOLEAN 222 IsCancelRoutineSet( 223 VOID 224 ) 225 { 226 return (m_CancelRoutine.m_Cancel != NULL) ? 227 TRUE : FALSE; 228 } 229 230 __inline 231 FxRequestContext* 232 GetContext( 233 VOID 234 ) 235 { 236 return m_RequestContext; 237 } 238 239 __inline 240 VOID 241 SetContext( 242 __in FxRequestContext* RequestContext = NULL 243 ) 244 { 245 // 246 // If we are setting to the same value, just return 247 // 248 if (m_RequestContext == RequestContext) { 249 return; 250 } 251 252 // 253 // If we are changing the context to another unique pointer, free the 254 // old context. 255 // 256 if (m_RequestContext != NULL) { 257 delete m_RequestContext; 258 } 259 260 m_RequestContext = RequestContext; 261 } 262 263 VOID 264 ContextReleaseAndRestore( 265 VOID 266 ) 267 { 268 // 269 // This does not free the context, rather it tells the context to release 270 // any references it is holding and restore fields back into the PIRP 271 // 272 if (m_RequestContext != NULL && m_Irp.GetIrp() != NULL) { 273 m_RequestContext->ReleaseAndRestore(this); 274 VerifierClearFormatted(); 275 } 276 } 277 278 __inline 279 VOID 280 EnableContextDisposeNotification( 281 VOID 282 ) 283 { 284 MarkDisposeOverride(); 285 } 286 287 __inline 288 BOOLEAN 289 HasContextType( 290 __in FX_REQUEST_CONTEXT_TYPE Type 291 ) 292 { 293 return (m_RequestContext != NULL && 294 m_RequestContext->m_RequestType == Type) ? TRUE : FALSE; 295 } 296 297 __inline 298 BOOLEAN 299 HasContext( 300 VOID 301 ) 302 { 303 return (m_RequestContext != NULL && 304 m_RequestContext->m_RequestType != 305 FX_REQUEST_CONTEXT_TYPE_NONE) ? TRUE : FALSE; 306 } 307 308 __inline 309 MdIrp 310 GetSubmitIrp( 311 VOID 312 ) 313 { 314 return m_Irp.GetIrp(); 315 } 316 317 __inline 318 FxIrp* 319 GetSubmitFxIrp( 320 VOID 321 ) 322 { 323 return &m_Irp; 324 } 325 326 MdIrp 327 SetSubmitIrp( 328 __in_opt MdIrp NewIrp, 329 __in BOOLEAN FreeIrp = TRUE 330 ); 331 332 __inline 333 BOOLEAN 334 CanComplete( 335 VOID 336 ) 337 { 338 LONG count; 339 count = InterlockedDecrement(&m_IrpCompletionReferenceCount); 340 ASSERT(count >= 0); 341 return count == 0 ? TRUE : FALSE; 342 } 343 344 VOID 345 CompleteSubmitted( 346 VOID 347 ); 348 349 _Must_inspect_result_ 350 NTSTATUS 351 ValidateTarget( 352 __in FxIoTarget* Target 353 ); 354 355 __inline 356 FxIoTarget* 357 GetTarget( 358 VOID 359 ) 360 { 361 return m_Target; 362 } 363 364 VOID 365 __inline 366 SetTarget( 367 __in FxIoTarget* Target 368 ) 369 { 370 m_Target = Target; 371 } 372 373 __inline 374 UCHAR 375 GetTargetFlags( 376 VOID 377 ) 378 { 379 // Assumes caller is holding appropriate lock 380 return m_TargetFlags; 381 } 382 383 __inline 384 VOID 385 SetTargetFlags( 386 __in UCHAR Flags 387 ) 388 { 389 // Assumes caller is holding appropriate lock 390 m_TargetFlags |= Flags; 391 } 392 393 __inline 394 ULONG 395 ClearTargetFlags( 396 __in UCHAR Flags 397 ) 398 { 399 ULONG oldFlags; 400 401 oldFlags = m_TargetFlags; 402 403 // Assumes caller is holding appropriate lock 404 m_TargetFlags &= ~Flags; 405 406 return oldFlags; 407 } 408 409 __inline 410 VOID 411 SetRequestBaseFlags( 412 __in UCHAR Flags 413 ) 414 { 415 // Assumes caller is holding appropriate lock 416 m_RequestBaseFlags|= Flags; 417 } 418 419 SHORT 420 GetVerifierFlagsLocked( 421 VOID 422 ) 423 { 424 ASSERT(GetDriverGlobals()->FxVerifierOn); 425 return m_VerifierFlags; 426 } 427 428 __inline 429 SHORT 430 GetVerifierFlags( 431 VOID 432 ) 433 { 434 SHORT flags; 435 KIRQL irql; 436 437 Lock(&irql); 438 flags = GetVerifierFlagsLocked(); 439 Unlock(irql); 440 441 return flags; 442 } 443 444 __inline 445 VOID 446 SetVerifierFlagsLocked( 447 __in SHORT Flags 448 ) 449 { 450 m_VerifierFlags |= Flags; 451 } 452 453 __inline 454 VOID 455 SetVerifierFlags( 456 __in SHORT Flags 457 ) 458 { 459 KIRQL irql; 460 461 ASSERT(GetDriverGlobals()->FxVerifierOn); 462 463 Lock(&irql); 464 SetVerifierFlagsLocked(Flags); 465 Unlock(irql); 466 } 467 468 __inline 469 VOID 470 ClearVerifierFlagsLocked( 471 __in SHORT Flags 472 ) 473 { 474 m_VerifierFlags &= ~Flags; 475 } 476 477 __inline 478 VOID 479 ClearVerifierFlags( 480 __in SHORT Flags 481 ) 482 { 483 KIRQL irql; 484 485 ASSERT(GetDriverGlobals()->FxVerifierOn); 486 487 Lock(&irql); 488 ClearVerifierFlagsLocked(Flags); 489 Unlock(irql); 490 } 491 492 __inline 493 VOID 494 VerifierSetFormatted( 495 VOID 496 ) 497 { 498 if (GetDriverGlobals()->FxVerifierOn && 499 GetDriverGlobals()->FxVerifierIO) { 500 SetVerifierFlags(FXREQUEST_FLAG_FORMATTED); 501 } 502 } 503 504 __inline 505 VOID 506 VerifierClearFormatted( 507 VOID 508 ) 509 { 510 if (GetDriverGlobals()->FxVerifierOn && 511 GetDriverGlobals()->FxVerifierIO) { 512 ClearVerifierFlags(FXREQUEST_FLAG_FORMATTED); 513 } 514 } 515 516 __inline 517 BOOLEAN 518 VerifierIsFormatted( 519 VOID 520 ) 521 { 522 if (GetDriverGlobals()->FxVerifierOn && 523 GetDriverGlobals()->FxVerifierIO) { 524 return (GetVerifierFlags() & FXREQUEST_FLAG_FORMATTED) ? TRUE : FALSE; 525 } 526 else { 527 // 528 // we are not tracking the state 529 // 530 return TRUE; 531 } 532 } 533 534 __inline 535 BOOLEAN 536 ShouldClearContext( 537 VOID 538 ) 539 { 540 return (m_RequestBaseFlags & FxRequestBaseSyncCleanupContext) ? TRUE 541 : FALSE; 542 } 543 544 _Must_inspect_result_ 545 NTSTATUS 546 CreateTimer( 547 VOID 548 ); 549 550 VOID 551 StartTimer( 552 __in LONGLONG Timeout 553 ); 554 555 _Must_inspect_result_ 556 BOOLEAN 557 CancelTimer( 558 VOID 559 ); 560 561 BOOLEAN 562 Cancel( 563 VOID 564 ); 565 566 BOOLEAN 567 __inline 568 IsAllocatedFromIo( 569 VOID 570 ) 571 { 572 return m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO ? TRUE : FALSE; 573 } 574 575 BOOLEAN 576 __inline 577 IsAllocatedDriver( 578 VOID 579 ) 580 { 581 return m_IrpAllocation == REQUEST_ALLOCATED_DRIVER ? TRUE : FALSE; 582 } 583 584 BOOLEAN 585 __inline 586 IsCanComplete( 587 VOID 588 ) 589 { 590 return m_CanComplete; 591 } 592 593 __inline 594 VOID 595 SetCompleted( 596 __in BOOLEAN Value 597 ) 598 { 599 m_Completed = Value; 600 } 601 602 VOID 603 __inline 604 SetPriorityBoost( 605 CCHAR PriorityBoost 606 ) 607 { 608 m_PriorityBoost = PriorityBoost; 609 } 610 611 CCHAR 612 __inline 613 GetPriorityBoost( 614 VOID 615 ) 616 { 617 return m_PriorityBoost; 618 } 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 __inline 634 WDFREQUEST 635 GetHandle( 636 VOID 637 ) 638 { 639 return (WDFREQUEST) GetObjectHandle(); 640 } 641 642 __inline 643 static 644 FxRequestBase* 645 _FromListEntry( 646 __in PLIST_ENTRY Entry 647 ) 648 { 649 return CONTAINING_RECORD(Entry, FxRequestBase, m_ListEntry); 650 } 651 652 __inline 653 static 654 FxRequestBase* 655 _FromDrainEntry( 656 __in PSINGLE_LIST_ENTRY Entry 657 ) 658 { 659 return CONTAINING_RECORD(Entry, FxRequestBase, m_DrainSingleEntry); 660 } 661 662 663 __inline 664 static 665 FxRequestBase* 666 _FromCsqContext( 667 __in PMdIoCsqIrpContext Context 668 ) 669 { 670 return CONTAINING_RECORD(Context, FxRequestBase, m_CsqContext); 671 } 672 673 __inline 674 PVOID 675 GetTraceObjectHandle( 676 VOID 677 ) 678 { 679 PVOID handle; 680 681 handle = GetObjectHandle(); 682 683 if (handle != NULL) { 684 return handle; 685 } 686 else { 687 return (PVOID) this; 688 } 689 } 690 691 VOID 692 FreeMdls( 693 VOID 694 ); 695 696 DECLSPEC_NORETURN 697 VOID 698 FatalError( 699 __in NTSTATUS Status 700 ); 701 702 VOID 703 ClearFieldsForReuse( 704 VOID 705 ); 706 707 protected: 708 FxRequestBase( 709 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 710 __in USHORT ObjectSize, 711 __in_opt MdIrp Irp, 712 __in FxRequestIrpOwnership Ownership, 713 __in FxRequestConstructorCaller Caller, 714 __in FxObjectType ObjectType = FxObjectTypeExternal 715 ); 716 717 virtual 718 ~FxRequestBase( 719 VOID 720 ); 721 722 // Do not specify argument names 723 FX_DECLARE_VF_FUNCTION( 724 VOID, 725 VerifyDispose 726 ); 727 728 // FxObject overrides 729 virtual 730 BOOLEAN 731 Dispose( 732 VOID 733 ); 734 735 static 736 MdDeferredRoutineType _TimerDPC; 737 738 VOID 739 CompleteSubmittedNoContext( 740 VOID 741 ); 742 743 VOID 744 ZeroOutDriverContext( 745 VOID 746 ) 747 { 748 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 749 RtlZeroMemory(GetSubmitFxIrp()->GetDriverContext(), 750 GetSubmitFxIrp()->GetDriverContextSize()); 751 #else 752 // 753 // UMDF host doesn't expose any easier way to zero out the contexts so 754 // set context to NULL one by one. 755 // 756 GetSubmitFxIrp()->SetContext(0, NULL); 757 GetSubmitFxIrp()->SetContext(1, NULL); 758 GetSubmitFxIrp()->SetContext(2, NULL); 759 GetSubmitFxIrp()->SetContext(3, NULL); 760 #endif 761 } 762 763 public: 764 765 union { 766 // 767 // The cancel safe queues use this context to identify 768 // the request in a race free manner. 769 // 770 MdIoCsqIrpContext m_CsqContext; 771 772 // 773 // IoTargets uses this to track the request when it is sent to the target. 774 // Since the request cannot be on an CSQ and sent to a target at the 775 // same time, we can unionize this with the CSQ context. 776 // 777 LIST_ENTRY m_ListEntry; 778 }; 779 780 union { 781 // 782 // IoTargest uses this when it needs to create a list of requests to cancel 783 // when making a state transition 784 // 785 SINGLE_LIST_ENTRY m_DrainSingleEntry; 786 787 // 788 // If TRUE, the driver formatted the request by copying the current stack 789 // location to next or by manually passing in an IO_STACK_LOCATION. This 790 // is union'ed with m_DrainSingleEntry b/c it is only relevant during 791 // send and forget and the request is never enqueued on the target in 792 // this case and m_DrainSingleEntry is used when tracking requests sent 793 // on a target for cancelation due to a target state change. 794 // 795 BOOLEAN m_NextStackLocationFormatted; 796 }; 797 798 protected: 799 // 800 // The NT IRP is wrapped by a frameworks FxIrp 801 // 802 // Note: If m_Irp is NULL after initialization, this means 803 // the IRP was cancelled by a FxIrpQueue cancellation 804 // callback, or completed. 805 // 806 FxIrp m_Irp; 807 808 // 809 // Target of the request. Access to this field is unguarded. The following 810 // have access to this field 811 // o The owning target itself 812 // o _TimerDPC() 813 // o Cancel() IFF it has successfully incremented the irp completion ref count 814 // 815 FxIoTarget* m_Target; 816 817 FxRequestContext* m_RequestContext; 818 819 820 821 822 FxRequestTimer* m_Timer; 823 824 // 825 // Client driver completion routine to call when the request has come back 826 // from the target device. 827 // 828 FxRequestCancelCallback m_CancelRoutine; 829 830 FxRequestCompletionCallback m_CompletionRoutine; 831 832 // 833 // Context to pass to CompletionRoutine when called 834 // 835 WDFCONTEXT m_TargetCompletionContext; 836 837 // 838 // Synchronization for this field is through Interlocked operations 839 // 840 LONG m_IrpCompletionReferenceCount; 841 842 // 843 // Access to flags guarded by FxIoTarget::Lock 844 // 845 // Values defined in the enum FxRequestTargetFlags 846 // 847 union { 848 UCHAR m_TargetFlags; 849 850 // 851 // These are used purely for debugging, not in live code anywhere! 852 // NOTE: if FxRequestTargetFlagschanges, so this this union 853 // 854 struct { 855 UCHAR Completed : 1; 856 UCHAR FlagsPended : 1; 857 UCHAR TimerSet : 1; 858 UCHAR CancelledFromTimer : 1; 859 UCHAR IgnoreState : 1; 860 } m_TargetFlagsByName; 861 }; 862 863 // 864 // Contains a value from the enum type FxRequestAllocationSource describing 865 // how the irp was allocated 866 // 867 UCHAR m_IrpAllocation; 868 869 BOOLEAN m_Completed; 870 871 BOOLEAN m_Canceled; 872 873 WDFOBJECT_OFFSET_ALIGNED m_SystemBufferOffset; 874 875 union { 876 // 877 // These are flags used by verifier. Set with values from the enum 878 // FxRequestVerifierFlags 879 // 880 SHORT m_VerifierFlags; 881 882 struct { 883 SHORT DriverOwned : 1; 884 SHORT TagRequest : 1; 885 SHORT Forwarded : 1; 886 SHORT DriverDispatch : 1; 887 SHORT DriverCancelable : 1; 888 SHORT DriverInprocessContext : 1; 889 SHORT Cancelled : 1; 890 SHORT Formatted : 1; 891 SHORT SentToTarget : 1; 892 SHORT DriverInEvtIoStopContext : 1; 893 } m_VeriferFlagsByName; 894 }; 895 896 // 897 // If this is !=0, its an indication of outstanding references 898 // on WDM IRP fields such as any system buffers. 899 // 900 LONG m_IrpReferenceCount; 901 902 // This field !=NULL if the request is on an IrpQueue. 903 FxIrpQueue* m_IrpQueue; 904 905 WDFOBJECT_OFFSET_ALIGNED m_OutputBufferOffset; 906 907 union { 908 // 909 // Bit field. Set with values from the enum FxRequestBaseFlags 910 // 911 UCHAR m_RequestBaseFlags; 912 913 struct { 914 UCHAR SystemMdlMapped : 1; 915 UCHAR OutputMdlMapped : 1; 916 UCHAR SyncCleanupContext : 1; 917 } m_RequestBaseFlagsByName; 918 }; 919 920 union { 921 // 922 // Bit field. Set with values from the enum FxRequestBaseStaticFlags 923 // 924 925 // 926 UCHAR m_RequestBaseStaticFlags; 927 928 struct { 929 UCHAR SystemBufferValid : 1; 930 UCHAR OutputBufferValid : 1; 931 } m_RequestBaseStaticFlagsByName; 932 }; 933 934 // 935 // Priority boost. 936 // 937 CCHAR m_PriorityBoost; 938 939 // 940 // Contains values from FxRequestCompletionState 941 // 942 BYTE m_CompletionState; 943 944 // 945 // TRUE, request can be completed by the driver. 946 // 947 BOOLEAN m_CanComplete; 948 949 // 950 // If !=NULL, MDL allocated and assocated with the request 951 // 952 PMDL m_AllocatedMdl; 953 }; 954 955 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 956 #include "fxrequestbasekm.hpp" 957 #elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) 958 #include "fxrequestbaseum.hpp" 959 #endif 960 961 962 #endif // _FXREQUESTBASE_H_ 963