/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDMDEV
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   OS2_PM_DRV_DEVMODE
 *             prdm_DevMode
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#define INCL_DEV
#define INCL_WINWINDOWMGR
#define INCL_WINPOINTERS
#define INCL_WINDIALOGS
#define INCL_DOSMODULEMGR
#define INCL_WINHEAP
#define INCL_DOSMISC
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS
#undef INCL_DEV
#undef INCL_WINPOINTERS
#undef INCL_WINWINDOWMGR
#undef INCL_WINDIALOGS
#undef INCL_DOSMODULEMGR
#undef INCL_WINHEAP
#undef INCL_DOSMISC

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#define INCL_WINP_SELSERVER
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_WINP_SELSERVER

#define INCL_HELP
#include <pmtktp.h>
#undef INCL_HELP
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdconse.h>
#include <prdmcone.h>

#define NO_SYS
#define INCL_HELP
#define PRDMTYPE_INCL
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef NO_SYS
#undef INCL_HELP
#undef PRDMTYPE_INCL

#include <prdmextf.h>
#include <prduextf.h>
#include <prdyextf.h>
#include <prdeextf.h>                     /* PD00208 */


/*extern PFSRSEM              lpDeviceModeSem;    CON3201 */
extern HMTX                 hmtxDeviceModeSem; /* CON3201 */
extern CHAR                 szCaption[40];
extern CHAR                 szMessage[SLEN_BOX_MESSAGE];
extern DModeDataType        DMData;
extern HMODULE               prdd_ModHandle;

extern USHORT               NO_OF_PRINTERS;
extern PCHAR                DriverNameString;
extern PCHAR                InternalDriverName;

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: OS2_PM_DRV_DEVMODE                                     */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PDRIVDATA      DriverData;    Information about the driver       */
/*   Dptr           DriverName;    Pointer to the driver name         */
/*   Dptr           DeviceName;    Pointer to the device name         */
/*   Dptr           PrinterName;   Pointer to the ptinter name        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function is an entry point into the device driver.  It is   */
/*   accessed from the OS/2 Control Panel and it calls prdm_Dialog    */
/*   which manages the window and dialog boxes that are used to allow */
/*   the user to set parameters from the control panel.               */
/*                                                                    */
/* PD00149 : New function that calls Prdm_ReplaceStack and Prdm_      */
/*           RestoreStack. If this is changed then the asembler       */
/*           functions may also need changing.                        */
/*                                                                    */
/* PD00268 : prdm_ReplaceStack returns a parameter indicating that    */
/*           the stack was replaced.                                  */
/*                                                                    */
/**********************************************************************/
#if 0
ULONG EXPENTRY OS2_PM_DRV_DEVMODE( DriverData,
                                   DriverName,
                                   DeviceName,
                                   PrinterName,
                                   uFlags )
PDRIVDATA      DriverData;
PBYTE          DriverName;
PBYTE          DeviceName;
PBYTE          PrinterName;
ULONG          uFlags;
#endif

ULONG EXPENTRY OS2_PM_DRV_DEVMODE( PDRIVDATA DriverData,   /* CON3201 */
                                   PBYTE     DriverName,   /* CON3201 */
                                   PBYTE     DeviceName,   /* CON3201 */
                                   PBYTE     PrinterName,  /* CON3201 */
                                   ULONG     uFlags )      /* CON3201 */

{
    /******************************************************************/
    /* Local variables. Keep these in alphabetical order and sensibly */
    /* alligned on DWORD bounderies to make debugging of this code    */
    /* easier.                                                        */
    /******************************************************************/
    USHORT      Result;
    USHORT      Stack;
    USHORT      StackAlloc = 0x0000;
    USHORT      StackSize  = 0x8000;

    /******************************************************************/
    /* Get some memory for our stack                                  */
    /******************************************************************/
#if 0
//  if (SSALLOCSEG(StackSize,&Stack, 0) != DOS_OK)
//  {
//      return(ERROR_ZERO);
//  }
#endif

    /******************************************************************/
    /* Replace the stack                                              */
    /******************************************************************/
/*  StackAlloc = Prdm_ReplaceStack(Stack, StackSize); /*

    /******************************************************************/
    /* Now call the real routine                                      */
    /******************************************************************/
    Result = (USHORT) prdm_DevMode (DriverData,
                                    DriverName,
                                    DeviceName,
                                    PrinterName,
                                    uFlags);

    /******************************************************************/
    /* Now restore the stack if necessary                             */
    /******************************************************************/
#if 0
//  if (StackAlloc)
//  {
//      Prdm_RestoreStack(Stack, StackSize);
//  }
#endif

    /******************************************************************/
    /* Free the memory                                                */
    /******************************************************************/
/*  SSFREESEG ( Stack ); */

    /******************************************************************/
    /* And complete.                                                  */
    /******************************************************************/
    return( Result );
}




/**********************************************************************/
/*                                                                    */
/*   FUNCTION: PRDM_DEVMODE                                           */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PDRIVDATA      DriverData;    Information about the driver       */
/*   Dptr           DriverName;    Pointer to the driver name         */
/*   Dptr           DeviceName;    Pointer to the device name         */
/*   Dptr           PrinterName;   Pointer to the ptinter name        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function used to be an entry point into the device driver   */
/*   until the driver had to replace it's stack. It calls prdm_Dialog */
/*   which manages the window and dialog boxes that are used to allow */
/*   the user to set parameters from the control panel.               */
/*                                                                    */
/* PD00149 : Renamed old OS2_PM_DRV_DEVMODE                           */
/*                                                                    */
/**********************************************************************/
#if 0
ULONG PASCAL FAR _loadds prdm_DevMode( DriverData,
                                       DriverName,
                                       DeviceName,
                                       PrinterName,
                                       uFlags )
PDRIVDATA      DriverData;
PBYTE          DriverName;
PBYTE          DeviceName;
PBYTE          PrinterName;
ULONG          uFlags;
#endif

ULONG prdm_DevMode( PDRIVDATA DriverData,                  /* CON3201 */
                    PBYTE     DriverName,                  /* CON3201 */
                    PBYTE     DeviceName,                  /* CON3201 */
                    PBYTE     PrinterName,                 /* CON3201 */
                    ULONG     uFlags )                     /* CON3201 */

{
#define TFUNC "OS2_PM_DRV_DMDE"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    PBYTE     NewStack;        /* Address of the our local stack      */
    CHAR      Prntr_Name_Buf[MAX_PRNTR_NAME];
    CHAR      DeviceName_KeyWord[MAX_PRNTR_NAME+8];
    USHORT    Result;          /* Function call return values         */
    USHORT    Result1;         /* Function call return values         */
    HWND      HwndOwner;
    HPOINTER  HourGlass;       /* Cursor put up while waiting...      */
    HPOINTER  CursorHandle;    /* orginal cursor                      */
    SHORT     i;               /* Loop control variables              */
    USHORT    Version;         /* PM Version Number  PD00262          */
    USHORT    DrvInstallResult; /* Function call return values        */
    /* CON3201                                                        */
    ULONG     ulResult;       /* Result of DosQueryMutexSem           */
    PID       pidTemp;        /* Temp variable to hold process info   */
    TID       tidTemp;        /* Temp variable to hold thread info    */
    PPIB      ppibTemp;       /* Temp variable for DosGetInfoBlocks   */
    PTIB      ptibTemp;       /* Temp variable for DosGetInfoBlocks   */

    DrvInstallResult = 0;
#if PRD_TRACE
    prdz_Init(TRUE);
#endif

#if PRD_DEBUG
    haltproc();
#endif


    /******************************************************************/
    /* If the DriverData pointer is NULL then this is an inquiry as   */
    /* to the size of buffer needed.                                  */
    /******************************************************************/
    if ( !DriverData )
    {
        /**************************************************************/
        /* Return the size of the Printer Driver Data structure.      */
        /* Our general data is one byte larger than the structure in  */
        /* the public headers - OK since this is device specific.     */
        /**************************************************************/
        TRACE6(TFUNC, "Return size", FNULL, 0);
        return((ULONG)(sizeof(DRIVDATA) + sizeof(DMDriverStruc) - 1));
    }
    else   /* DriverData != FNULL */
    {
        /**************************************************************/
        /* Check that nothing else is in Device modes.                */
        /*                                                            */
        /*      !!!!!! Private fix for Office Vision !!!!!!           */
        /*                                                            */
        /* Office Vision has been written to call DeviceModes         */
        /* simultaneously from multiple threads to query the driver   */
        /* data. The uFlags == 0x02 check below stops the             */
        /* "In Progress" dialog box from being displayed when all     */
        /* the caller wants to do is retrieve the driver data without */
        /* displaying any dialog boxes and without updating the       */
        /* INI file. Instead the caller will wait until the           */
        /* semaphore is cleared by the thread already in DeviceModes. */
        /*                                                            */
        /* Lexington should be raising a DCR to clarify printer       */
        /* driver behaviour on multiple simultaneous calls to         */
        /* DeviceModes.  Until this DCR is approved, the fix below    */
        /* is a temporary one to keep Office Vision happy.            */
        /**************************************************************/
/*      if (( FSRSemCheck(lpDeviceModeSem) == 0xFFFFFFFF ) ||         CON3201 */
/*          (uFlags == 0x02))                                         CON3201 */

/* CON3201 */
/* First get the process and thread info for the process and the semaphore.   */
/* Then check the info and see if uFlags = 02                                 */

        DosGetInfoBlocks(&ptibTemp, &ppibTemp);
        DosQueryMutexSem(hmtxDeviceModeSem, &pidTemp, &tidTemp, &ulResult);

        if ((!((ptibTemp->tib_ptib2->tib2_ultid == tidTemp) &&
           (ppibTemp->pib_ulpid == pidTemp))) || (uFlags == 0x02))
        {
            (VOID) prdg_RequestSemaphore(hmtxDeviceModeSem, 0);
        }
        else
        {
            WinLoadString( hab,
                           prdd_ModHandle,
                           IDS_SMB_CAPTION,
                           40,
                           (PSZ)szCaption);

            WinLoadString( hab,
                           prdd_ModHandle,
                           IDS_IN_PROGRESS,
                           100,
                           (PSZ)szMessage);

            /**********************************************************/
            /* Lock the window that called us before displaying the   */
            /* error message. This ensures that it cannot be closed   */
            /* until this message has been cancelled.                 */
            /**********************************************************/
         /* HwndOwner = WinQueryActiveWindow(HWND_DESKTOP,TRUE); */
            HwndOwner = WinQueryActiveWindow(HWND_DESKTOP);  /*CON3201*/

            WinMessageBox( HWND_DESKTOP,
                           HwndOwner,
                           (PSZ)szMessage,
                           (PSZ)szCaption,
                           0,
                           MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION );

            /**********************************************************/
            /* Now unlock that window.                                */
            /**********************************************************/
        /*  WinLockWindow(HwndOwner,FALSE); CON3201 - this call does nothing */
            return(DPDM_ERROR);
        }
        /*******************************************************************/
        /* Check that the driver name is the driver we are part of. PD00175*/
        /*******************************************************************/

        if ( DriverName )
        {
            /**************************************************************/
            /* Copy DriverName into DriverNameString and set it to        */
            /* uppercase. PD00175                                         */
            /**************************************************************/
            (VOID) prdu_strcpy( (PBYTE)DriverNameString,
                                (PBYTE)DriverName);

            (VOID) prdu_strupr( (PBYTE)DriverNameString );

            /**************************************************************/
            /* A DriverName was passed in. Compare against the string     */
            /* defined in the drivers data segment.                       */
            /**************************************************************/
            if ( prdu_strcmp( (PBYTE)InternalDriverName,
                              (PBYTE)DriverNameString ) )
            {
                /**********************************************************/
                /* The DriverName wasn't our driver. Exit with an error.  */
                /**********************************************************/
                Result = DPDM_ERROR;
                goto Return_DPDM;

            }
            else
            {
                /**********************************************************/
                /* Copy DriverName into DriverNameString and set the case */
                /* back to its original form.  PD00175                    */
                /**********************************************************/
                (VOID) prdu_strcpy( (PBYTE)DriverNameString,
                                    (PBYTE)DriverName);

            }
        }

        /**************************************************************/
        /* Clear the entire DMData buffer to Zippo.  DMData is a      */
        /* global data structure so there could be some crud left     */
        /* there from the last call to device modes.                  */
        /**************************************************************/
        (VOID) prdu_memset( (PBYTE)&DMData,
                             0,
                             (sizeof(DModeDataType)) );

        /**************************************************************/
        /* If PrinterName (e.g. "PRINTER1") is a an empty string or   */
        /* a null pointer the we need to handle the driver data       */
        /* passed in - DMData.PrinterName will act as a flag.         */
        /**************************************************************/

        if ((PrinterName == FNULL) || (((PBYTE)PrinterName)[0] == '\0'))
        {
            DMData.PrinterName[0] = '\0';
        }
        else
        {
            /**********************************************************/
            /* PD00185                                                */
            /**********************************************************/
            prdu_strcpyN( DMData.PrinterName, PrinterName, 32 );
        }

        /**************************************************************/
        /* A null PrinterName is invaled for uFlags = 1 since we      */
        /* may need to write to the INI file.                         */
        /**************************************************************/
        if ( (uFlags == 1) && (DMData.PrinterName[0] == '\0') )
        {
            /**********************************************************/
            /* Do not use LogErr as this causes a cal from ring 2 to 3*/
            /* if PRD_DEBUG is on.                                    */
            /**********************************************************/
            Result = DPDM_ERROR;
            goto Return_DPDM;
        }
        /**************************************************************/
        /* Store the current Cursor shape.                            */
        /**************************************************************/
     /* CursorHandle = (PULONG)WinQueryPointer( HWND_DESKTOP ); */
        CursorHandle = WinQueryPointer( HWND_DESKTOP );    /* CON3201 */

     /* HwndOwner = WinQueryActiveWindow(HWND_DESKTOP,TRUE); */
        HwndOwner = WinQueryActiveWindow(HWND_DESKTOP);    /* CON3201 */

        HourGlass = WinQuerySysPointer( HWND_DESKTOP,
                                        SPTR_WAIT,
                                        FALSE );

        /**************************************************************/
        /* If DeviceName is null and uFlags = 1 then call DrvInstall  */
        /* because this old driver format.                            */
        /**************************************************************/
        if ( ( DeviceName ==  FNULL || DeviceName[0] == '\0' ) &&
#if 0
//           (DriverData->szDeviceName[0] == '\0') &&   /* PD00591    */
#endif
             ( uFlags == 01 ))
        {
            (VOID)prdm_DispConversionMsg( HwndOwner,
                                       IDS_INV_DEVICE_CONV,
                                       SLEN_BOX_MESSAGE,
                                       DB_TXT_DUMMY,
                                       MB_OK | MB_WARNING );

            /*************************************************************/
            /* Set the cursor to the hour glass pointer.                 */
            /*************************************************************/
            Result = WinSetPointer( HWND_DESKTOP, HourGlass );
            Result = (USHORT)prdm_ConvertOldIniToNew(TRUE);

            /*************************************************************/
            /* Ensure the cursor is reset to its original shape.         */
            /*************************************************************/
            Result1 = WinSetPointer( HWND_DESKTOP, CursorHandle );

            /******************************************************/
            /* Get the OS version. PD00262                        */
            /******************************************************/
/* CON3201 ********************************************************/
/* Will always run on 2.0 or higher, so we don't need to worry    */
/* if it is 1.3 or 1.2                                            */
/*          if (DOS_OK != DosGetVersion(&Version))                */
/*          {                                                     */
/*              Result = DPDM_ERROR;                              */
/*              goto Return_DPDM;                                 */
/*          }                                                     */
/******************************************************************/
            switch (Result)
            {
                case IDS_CONVERSION_COMP:

                    /********************************************************/
                    /* We need to display IDS_CONVERSION_COMP msg if the OS2*/
                    /* level is 1.2 or 1.3. We should display IDS_CONVERSION*/
                    /* _DONE1 if the OS2 level is 2.0+. PD00597             */
                    /********************************************************/
             /* CON3201 *****************************************************/
             /*     if (HIBYTE(Version) == 10)                              */
             /*     {                                                       */
             /*         (VOID)prdm_DispConversionMsg( HwndOwner,            */
             /*                            IDS_CONVERSION_COMP,             */
             /*                            SLEN_BOX_MESSAGE,                */
             /*                            DB_TXT_DUMMY,                    */
             /*                            MB_OK | MB_ICONEXCLAMATION );    */
             /*     }                                                       */
             /*     else                                                    */
             /*     {                                                       */
             /***************************************************************/
                        (VOID)prdm_DispConversionMsg( HwndOwner,
                                           IDS_CONVERSION_DONE1,
                                           SLEN_BOX_MESSAGE,
                                           DB_TXT_DUMMY,
                                           MB_OK | MB_ICONEXCLAMATION );

             /*     }                                              CON3201 */
                    break;


                case IDS_CONVERSION_NO_BUFFER:

                    (VOID)prdm_DispConversionMsg( HwndOwner,
                                         IDS_CONVERSION_NO_BUFFER,
                                         SLEN_BOX_MESSAGE,
                                         DB_TXT_DUMMY,
                                         MB_OK | MB_ERROR );
                    break;

                case IDS_CONVERSION_ERR_OLD:

                    /***********************************************************/
                    /* We need to display IDS_CONVERSION_ERR_OLD msg if the OS2*/
                    /* level is 1.2 or 1.3. We should display IDS_CONVERSION   */
                    /* _ERR_OLD2 if the OS2 level is 2.0+.                        */
                    /***********************************************************/
                /* CON3201 *****************************************************/
                /*  if (HIBYTE(Version) == 10)                                 */
                /*  {                                                          */
                /*      (VOID)prdm_DispConversionMsg( HwndOwner,               */
                /*                       IDS_CONVERSION_ERR_OLD,               */
                /*                       SLEN_BOX_MESSAGE,                     */
                /*                       DB_TXT_DUMMY,                         */
                /*                       MB_OK | MB_ERROR );                   */
                /*  }                                                          */
                /*  else                                                       */
                /*  {                                                          */
                /***************************************************************/
                        (VOID)prdm_DispConversionMsg( HwndOwner,
                                         IDS_CONVERSION_ERR_OLD2,
                                         SLEN_BOX_MESSAGE,
                                         DB_TXT_DUMMY,
                                         MB_OK | MB_ERROR );

                /*  }                                                  CON3201 */
                    break;

                case IDS_CONVERSION_ERR:
                default:
                    (VOID)prdm_DispConversionMsg( HwndOwner,
                                         IDS_CONVERSION_ERR,
                                         SLEN_BOX_MESSAGE,
                                         DB_TXT_DUMMY,
                                         MB_OK | MB_ERROR );
                    break;
            } /* switch                                          */
        }
        /**************************************************************/
        /* If DeviceName is not null and uFlags = 1 but the Ini entry */
        /* does not contain any data call DrvInstall. There may be old*/
        /* driver data available.                                     */
        /**************************************************************/
        else
        {
            if ( uFlags == 1)
            {
                DeviceName_KeyWord[0] = '\0';   /* initialize            */

                for ( i = 0; i < NO_OF_PRINTERS; i++ )
                {
                    /*****************************************************/
                    /* description string from the Rc  file.             */
                    /*****************************************************/
                    WinLoadString( hab,
                                   prdd_ModHandle,
                                   IDS_FIRST_PRINTER + i,
                                   MAX_PRNTR_NAME,
                                   (PSZ)Prntr_Name_Buf );

                    /******************************************************/
                    /* Now compare strings. If they match then build a    */
                    /* keyword to read PM_SPOOLER_DD entry in INI file.   */
                    /******************************************************/
                    if ( !prdu_strcmp(DeviceName,
                                      Prntr_Name_Buf))
                    {
                        prdu_strcpy(DeviceName_KeyWord,DriverNameString);

                        *(DeviceName_KeyWord+7) = '.';

                        prdu_strcpy(DeviceName_KeyWord+8,
                                    Prntr_Name_Buf);

                        break;
                    } /* if (!prdu_strcmpN...    */

                } /* for (i = 0; i < NO_OF_PRINTERS; i++)   */
                /************************************************************/
                /* if KeyWord is not NULL (DeviceName was a valid printer   */
                /* type) read Ini for this devicename.                      */
                /************************************************************/
                if ( DeviceName_KeyWord[0] != '\0' )
                {
                    /********************************************************/
                    /* Find out if  this entry already exist.               */
                    /* If exist then do not call prdm_ConvertOldIniToNew.   */
                    /* Otherwise, call prdm_ConvertOldIniToNew with the     */
                    /* parm FALSE: not to delete the old driver.            */
                    /********************************************************/
                    if ( !prde_PM_DD_Exist( PrinterName,
                                           DeviceName_KeyWord ))
                    {
                        /*****************************************************/
                        /* Set the cursor to the hour glass pointer.         */
                        /*****************************************************/
                        Result = WinSetPointer( HWND_DESKTOP, HourGlass );
                        DrvInstallResult = (USHORT)prdm_ConvertOldIniToNew(
                                                        FALSE);
                        /*****************************************************/
                        /* Ensure the cursor is reset to its original shape. */
                        /*****************************************************/
                        Result = WinSetPointer( HWND_DESKTOP, CursorHandle );
                    }

                }
#if 0
//              Result = prdm_SelectOldDriver(DMData.PrinterName); /*PD00542*/
#endif
            } /* if (uFlag == 1)                                      */

            /**********************************************************/
            /* Call prdm_Dialog to run the dialog boxes               */
            /* and get input from the user.                           */
            /**********************************************************/
            Result = prdm_Dialog( DriverData,
                                  DriverName,
                                  DeviceName,
                                  PrinterName,
                                  uFlags );

        }

        /**************************************************************/
        /* Clear the semaphore.                                       */
        /**************************************************************/
Return_DPDM:
        (VOID) prdg_ClearSemaphore(hmtxDeviceModeSem);

        TRACE4(TFUNC, "Return Result", &Result, 1);
        return((ULONG)Result);
    }
}
#undef TFUNC

