/*DDK*************************************************************************/
/*                                                                           */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/*SCCSID = %%s %%s %%s */

/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/

/*********************************************************************/
/*                                                                   */
/*  SOURCE FILE NAME: svga.c                                         */
/*                                                                   */
/*  DESCRIPTIVE NAME: Main source file for S3 SVGA action routine DLL*/
/*                                                                   */
/*  FUNCTION: This contains the entry points for SVGA.DLL            */
/*                                                                   */
/*********************************************************************/
#define  INCL_DOS
#define  INCL_DOSERRORS
#define  INCL_DOSPROCESS
#define  INCL_DOSRESOURCES
#define  INCL_WIN
#define  INCL_GPIDISPPRF

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <time.h>
#include <process.h>
#include "dispmain.h"
#include "dispact.h"
#include "svga.h"

/********************************************
 *private function declarations for this module
 *********************************************/
VOID    APIENTRY svga_ParseAdapter(PDSPINSTL_CHAIN pInstalChain,
                                   PADAPTERENTRY pAdpentry);
VOID    APIENTRY svga_ParseMonitor(PDSPINSTL_CHAIN pInstalChain,
                                   PVIDEOENTRY pVidentry);
ULONG   APIENTRY svga_WriteResolution(PSZ pszConfig,PVIDEOENTRY pVidentry);
ULONG   APIENTRY svga_WriteNewResolution(PVIDEOENTRY pVidEntry);
ULONG   APIENTRY svga_GetCurrentResolution(VOID);
INT     APIENTRY svga_WriteResolIni(PINIPARMS);
INT     APIENTRY svga_WriteInterlIni(PINIPARMS);
INT     APIENTRY svga_WriteRefrIni(PINIPARMS);
ULONG   APIENTRY svga_UpWriteIni(PSZ pszApplication,PSZ pszKey,PSZ pszString);
MRESULT EXPENTRY WaitSvgaDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2);
//@TM  feature
MRESULT EXPENTRY SelectSvgaUtilDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY SvgaUtilDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2);
APIRET  CreateSvgaTmpBat(CHAR *achBuffer );
VOID    InitHelp( HWND *phwndHelpInstance );
//@TM
BOOL    OpenResolutionsFile(PRESOLUTIONS pResolutions,PULONG pulCount);
APIRET  GetResolutionsData(PRESOLUTIONS pResolutions,
                           PRESOLUTIONS pResolutionsToDisplay,
                           HWND hwnd,
                           PDSPINSTL_CHAIN  pInstalChain,
                           BOOL fUseDefault,
                           PULONG pulCount,
                           PFN pfnGetNext,
                           BOOL *fShowResolutionsToUser);
BOOL   ReadResolutionsFile(PRESOLUTIONS pResolutions,HFILE hf,PULONG pulCount);
VOID   RunSvga(PVOID);
PSZ    strip_white(PSZ pszString);
BOOL   ValidateResolutions(PRESOLUTIONS pResolutions,
                           PRESOLUTIONS pResolutionsToDisplay,
                           PDSPINSTL_CHAIN   pDspInstlHeadChain,
                           BOOL fUseDefault,
                           PULONG pulCount,
                           ULONG ulCount,
                           PFN pfnGetNext);
BOOL   CompareResolutions(PSZ pszResolution,PRESOLUTIONS pSupportedResolutions,
                            ULONG ulCount);
APIRET APIENTRY GetDllHandle( PHMODULE phmodResource);
VOID   APIENTRY WaitThread(PVOID);
VOID   StringToResolution(PSZ pszString,PRESOLUTIONDATA pResolutionData);
VOID   APIENTRY BuildSvgaNodes(PDSPINSTL_CHAIN pDspinstlChain,
                               PRESOLUTIONS pSelectedResolutions,
                               ULONG ulCount,
                               LONG lDesignatedResolution);
PSZ             GetSelectedResolution(PRESOLUTIONS pResolution,ULONG ulCount);
PDSPINSTL_CHAIN GetLastElement(PDSPINSTL_CHAIN pDspInstlChain);
USHORT APIENTRY16 Dos16GetPrty(USHORT usScope,PUSHORT pusPriority,USHORT pid);
VOID   SvgaReportError(ULONG rc,PSZ pszMsg,HWND hwndOwner);
VOID   svgaLog(PSZ pszMsg);
USHORT SvgaMessageBox(ULONG rc,PSZ pszMsg,HWND hwndOwner);
PSZ    GetDesignatedResolution(PDSPINSTL_CHAIN pChain,ULONG ulCount,
                               LONG lDesignatedResolution);

                                                   /* Amol; D58319;12/09/92*/
BOOL   CheckSVGAMem (PRESOLUTIONS, ULONG);
BOOL   IsResolutionOver1Mg(PSZ pszResolution,PRESOLUTIONDATA  pResolution);

/*****************************************
 *private data declarations
 *****************************************/
PSZ  pszConfig        = "MONITOR.CFG";       //name of  monitor file to pass
PSZ  pszAdapter       = "ADAPTER.CFG";       //name of  adapter file to pass
PSZ  pszDefMonKey;                           //default  monitor key
PSZ  pszSelMonKey;                           //selected monitor key
PSZ  pszDefAdpKey;
PSZ  pszSelAdpKey;
PSZ  pszResolutionString = NULL;
RESOLUTIONS   ResolutionsArray[MAX_RESOLUTIONS];
RESOLUTIONS   ResolutionsToDisplay[MAX_RESOLUTIONS];
HMODULE hmodResource;
BOOL    f1024K;                        /* Amol; Defect #58319; 12/09/92    */
//@TMCHAR *szErrorMsg []=
//@TM{
//@TM   "A error has occurred reading the svgadata.pmi file",
//@TM   "Unable to determine hardware configuration",
//@TM   "Unable to resolve module handle",
//@TM   "The current hardware configuration does not support the high resolution mode. \
//@TM If you continue, your video support might be unusable.  Do you want to continue ?"
//@TM};

CHAR   szResolution[SIZ_PARMS];
CHAR   szInterLace [SIZ_PARMS];
CHAR   szRefresh   [SIZ_PARMS];
CHAR   szString1   [SIZ_PARMS];
CHAR   szString2   [SIZ_PARMS];
CHAR   szString3   [SIZ_PARMS];


INIPARMS  IniParms [] =
{
     MONITOR_RES,      szResolution,szString1,svga_WriteResolIni,
     MONITOR_VREFRESH, szRefresh   ,szString2,NULL,
     MONITOR_INTERLACE,szInterLace ,szString3,NULL,
};
PFN  pfnLogFunction = NULL;
TID  tidThread;

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:Default_Primary
 *
 *  Purpose:This action routine handles svga specific routines that
 *          need to be called from the display install utility for the
 *          default primary selection.This routine does the following:
 *        a)Gets a pointer to the head of the selected display install
 *                 chain
 *        b)Does the setup for the GetResolutionsData routine and calls it
 *        c)If no error occurred call to have the resolutions displayed to
 *          the user.
 *        d)Call to have the linked list built,based upon the resoluition
 *          the user has selected.
 *
 *
 *  Returns:
 *         Non-Zero -  Error occurred,User Aborted.
 *          0        - Successful Operation,Continue
\****************************************************************/
LONG EXPENTRY Default_Primary(HWND hwnd,PDSPINSTL_GLOBAL_DATA pInstalData)
{

    PRESOLUTIONS  pResolutions;
    ULONG ulSelections = 0;
    LONG lRetValue;
    PDSPINSTL_CHAIN pHeadofChain;
    BOOL fShowResolutionsToUser  = TRUE;
    LONG lGetDesignated = -1;

    pfnLogFunction = pInstalData->pfnLogFunction;

    /*
     * If resolution string passed in make it global
     */

    if( pInstalData->pszResolutionString )
    {
       pszResolutionString = malloc(
                                strlen( pInstalData->pszResolutionString)
                                  + 1);
       strcpy( pszResolutionString, pInstalData->pszResolutionString );
    }

    /*
     *start at the head
     *of the chain
     */
    if((*pInstalData->pfnNextElementRoutine)(&pHeadofChain,
                                             CHAIN_HEAD,
                                             NULL) )
    {
          return(CANCEL_OPERATION);
    }

   /*
    *set up to get the supported resolutions
    */
    memset(ResolutionsArray,0,sizeof(RESOLUTIONS) * MAX_RESOLUTIONS);
    memset(ResolutionsToDisplay,0,sizeof(RESOLUTIONS) * MAX_RESOLUTIONS);
    /*
     *get the resolutions data,setting the default flag
     *to true.
     */
    if((lRetValue = GetResolutionsData(ResolutionsArray,
                                       ResolutionsToDisplay,
                                       hwnd,pHeadofChain,
                                       TRUE,
                                       &ulSelections,
                                       pInstalData->pfnNextElementRoutine,
                                       &fShowResolutionsToUser) ))
    {
         if (lRetValue != CONTINUE_WITH_ERR)
             return(lRetValue);
    }

    if(fShowResolutionsToUser)
    {
         /*
          *display the list of resolutions
          */
         if( lRetValue =  (*pInstalData->pfnSpecifyResolution)(hwnd,&ResolutionsToDisplay,
                                                    ulSelections,
                                                    FALSE) )
         {
               /*
                *user aborted
                */
               return(lRetValue);
         }
    }
    else
    {
          /*
           *this should only be happening on speedway
           *make sure the first one in our list is selected
           */
           lGetDesignated = 0;
    }


    /*
     *build the key for the
     *first node and set the next node to be the
     *node that was selected
     */
//    BuildSvgaNodes(pHeadofChain,
//                         ResolutionsToDisplay,
//                         ulSelections,
//                         lGetDesignated);
//
    return(lRetValue);
}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:Default_Secondary
 *
 *  Purpose:This action routine handles the calling of the specify
 *          adapter and specify monitor routines. The key that is
 *          returned in the adapter structre is saved off so as to
 *          used later while querying the .DSP files.
 *
 *
 *
 *  Usage:
 *
 *  Returns:
 *          Non-Zero -  Error occurred,User Aborted.
 *          0        - Successful Operation,Continue
\****************************************************************/
LONG EXPENTRY Default_Secondary(HWND hwnd,PDSPINSTL_GLOBAL_DATA pInstalData)
{
    ADAPTERENTRY adpentry;
    VIDEOENTRY videntry;
    LONG rc;
    PDSPINSTL_CHAIN pDspChain;



    pfnLogFunction = pInstalData->pfnLogFunction;
    /*
     *start at the head
     *of the chain
     */
    pDspChain = pInstalData->pHeadDspInstl_Chain;

    if((rc = (*pInstalData->pfnSpecifyVideoMonitor)(hwnd,pszConfig, &videntry)))
    {
        /*
         *user aborted
         */
        return(CANCEL_OPERATION);
    }
    return(rc);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:Selected_Primary

 *  Purpose:This action routine handles svga specific routines that
 *          need to be called from the display install utility for the
 *          selected primary selection.This routine does the following:
 *        a)Gets a pointer to the head of the selected display install
 *                 chain
 *        b)Does the setup for the GetResolutionsData routine and calls it
 *        c)If no error occurred call to have the resolutions displayed to
 *          the user.
 *        d)Call to have the linked list built,based upon the resolution
 *          the user has selected.
 *        Note - Kenner
 *        Changed the  usedefaultflag so that it is always true.
 *        this will insure that only resolutions the hardware can support
 *        are displayed to the customer.
 *
 *  Returns:
 *          Non-Zero -  Error occurred,User Aborted.
 *          0        - Successful Operation,Continue
\****************************************************************/
LONG EXPENTRY Selected_Primary(HWND hwnd,PDSPINSTL_GLOBAL_DATA pInstalData)
{

    PRESOLUTIONS  pResolutions;
    ULONG ulSelections = 0;
    LONG lRetValue;
    PDSPINSTL_CHAIN pHeadofChain;
    BOOL fShowResolutionsToUser  = TRUE;
    LONG lGetDesignated = -1;


    pfnLogFunction = pInstalData->pfnLogFunction;

    /*
     * If resolution string passed in make it global
     */

    if( pInstalData->pszResolutionString )
    {
       pszResolutionString = malloc(
                                strlen( pInstalData->pszResolutionString)
                                  + 1);
       strcpy( pszResolutionString, pInstalData->pszResolutionString );
    }


    /*
     *start at the head
     *of the chain
     */
    if( (*pInstalData->pfnNextElementRoutine)(&pHeadofChain,
                                              CHAIN_HEAD,
                                              NULL) )
    {
          return(CANCEL_OPERATION);
    }

   /*
    *read in the resolutions file
    */
    memset(ResolutionsArray,0,sizeof(RESOLUTIONS) * MAX_RESOLUTIONS);
    memset(ResolutionsToDisplay,0,sizeof(RESOLUTIONS) * MAX_RESOLUTIONS);
    if((lRetValue = GetResolutionsData(ResolutionsArray,
                                       ResolutionsToDisplay,
                                       hwnd,pHeadofChain,
                                       TRUE,
                                       &ulSelections,
                                       pInstalData->pfnNextElementRoutine,
                                       &fShowResolutionsToUser) ))
    {
         if (lRetValue != CONTINUE_WITH_ERR)
             return(lRetValue);
    }
    if(fShowResolutionsToUser)
    {
          if( lRetValue =  (*pInstalData->pfnSpecifyResolution)(hwnd,&ResolutionsToDisplay,
                                               ulSelections,
                                               FALSE) )
          {
                return(lRetValue);

          }
     }
     else
     {
           /*
            *this should only be happening on speedway
            *make sure the first one in our list is selected
            */
            lGetDesignated = 0;
     }



    /*
     *build the key for the
     *first node and set the next node to be the
     *node that was selected
     */
//    BuildSvgaNodes(pHeadofChain,
//                         ResolutionsToDisplay,
//                         ulSelections,
//                         lGetDesignated);
    return(lRetValue);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:BuildSvgaNodes
 *
 *  Purpose:This routine will build the configuration node and the
 *          associated key to look for in the dsp files.The next node
 *          in the link will be set to the one that matches what the
 *          user selected. The next link will be set to the first
 *          node that does not have a resoulution associated with
 *          it.
 *          Updated 8-18-92 -Kenner
 *          Check the first node that does not have a resolution
 *          to see if HI-RESOLUTION was selected,if so reset the
 *          key to pick up the hires fonts.
 *
 *         Head      ->      pszKey  = "C600x400x256"
 *         NextNode  ->      pszKey  = "600x400x256"
 *         NextNode  ->      pszKey  = "FONT_HI" || "FONT_LO"
 *  Returns:
 *        VOID
\****************************************************************/
VOID APIENTRY BuildSvgaNodes(PDSPINSTL_CHAIN pDspinstlChain,
                              PRESOLUTIONS pSelectedResolutions,
                              ULONG ulCount,
                              LONG lGetDesignated)
{
     PSZ pszSelectedResolution;
     PDSPINSTL_CHAIN pTempChain,pLastResolution;

     /*
      *get the selected resolutions
      */
     if(lGetDesignated == -1)
     {
          pszSelectedResolution = GetSelectedResolution(pSelectedResolutions,ulCount);
     }
     else
     {
          /*
           *get the reslution
           *designated
           */
          pszSelectedResolution = GetDesignatedResolution(pDspinstlChain,ulCount,
                                                          lGetDesignated);
     }

     /*
      *get the first node after the head of the
      *list that does not have a associated resolution
      */
     pLastResolution = GetLastElement(pDspinstlChain);

     /*
      *build the key for the head
      *of our chain
      */
     pDspinstlChain->pszKey = malloc(MAX_SIZ_KEY);
     *(pDspinstlChain->pszKey) = 'C';

     for(pTempChain = pDspinstlChain;pTempChain;
                             pTempChain = pTempChain->pNextDspInstl)
     {
          /*
           *find the right one in the node that matches what we have
           *selected
           */
           if(pTempChain->pszResolution)
           {
               /*
                *found it
                */
               if(!strcmp(pTempChain->pszResolution,
                    pszSelectedResolution) )
               {
                  pDspinstlChain->pNextDspInstl =
                    pTempChain;
                  /*
                   *we used to incorrectly use the resolution
                   *as the key,should be using the key from
                   *the dsc file to match the key
                   *for the dsp file
                   */


                  strcat(pDspinstlChain->pszKey,pTempChain->pszKey);
                  /*
                   *set the next node to
                   *start with the next node in the list
                   *that does not have a resolution
                   */
                  pTempChain->pNextDspInstl = pLastResolution;
                  /*
                   *we should now be looking at the first diskette
                   *that does not have a resolution,this should now
                   *be the fonts diskette
                   *check to see if the resoulution that was selected was
                   *HI-RES if so reset the key to pick-up the hires font
                   *dsp file
                   */
//                if(!strcmp(pszSelectedResolution,_1024_768_256 ) ||
//                       !strcmp(pszSelectedResolution,_1024_768_16 ) )
//                {
//                      pLastResolution->pszKey = malloc(MAX_SIZ_KEY);
//                      strcpy(pLastResolution->pszKey,FONT_HI);
//                }

                  break;
               }
          }
     }
     return;
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:GetLastElement()
 *
 *  Purpose:Returns the a pointer to the last node in the list
 *          that contains a valid resolution.
 *
 *  Returns:
 *          pDspTemp - will point to either the first node that does
 *                     not have a resolution or the last node in
 *                     the linked list whichever occurs first
\****************************************************************/
PDSPINSTL_CHAIN GetLastElement(PDSPINSTL_CHAIN pDspInstlChain)
{
     PDSPINSTL_CHAIN pDspTemp;

     /*
      *the assumption for svga is that the first node is
      *always null
      */
     for(pDspTemp = pDspInstlChain->pNextDspInstl;pDspTemp->pszResolution;)
     {
          if(!pDspTemp->pNextDspInstl)
          {
               pDspTemp = NULL;
               break;
          }
          pDspTemp = pDspTemp->pNextDspInstl;
     }
     return(pDspTemp);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:GetSelectedResolution
 *
 *  Purpose: This routine will loop through the  list of pSelectedResolutions
 *           for up to ulCount number of elements looking for the ulSelected
 *           flag to be set to TRUE. A pointer to the first ulSelected
 *           element will be returned or NULL if no selection was made.
 *  Returns:
 *          pszResolutions  = a pointer to the selected resolutions string
 *                            or NULL if none was selected.
\****************************************************************/
PSZ GetSelectedResolution(PRESOLUTIONS pSelectedResolutions,ULONG ulCount)
{
     ULONG ulCounter;
     PRESOLUTIONS pTemp;
     PSZ pszResolutions = NULL;


     for(ulCounter =0,pTemp = pSelectedResolutions; ulCounter < ulCount;
                              pTemp++,ulCounter++)
     {

          if(pTemp->ulSelected)
          {
               pszResolutions= pTemp->achResolutionString;
               break;
          }
     }
     return(pszResolutions);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:Selected_Secondary
 *
 *  Purpose:This action routine handles the calling of the specify
 *          adapter and specify monitor routines. The key that is
 *          returned in the adapter structre is saved off so as to
 *          used later while querying the .DSP files.
 *
 *
 *
 *  Usage:This routine should be called when the user has selected
 *        to install a secondary monitor/adapter.
 *
 *  Returns:
 *          Non-Zero -  Erorr occurred,User Aborted.
 *          0        - Successful Operation,Continue
\****************************************************************/
LONG EXPENTRY Selected_Secondary(HWND hwnd,PDSPINSTL_GLOBAL_DATA pInstalData)
{
    ADAPTERENTRY adpentry;
    VIDEOENTRY videntry;
    LONG rc;
    PDSPINSTL_CHAIN pDspChain;


    pfnLogFunction = pInstalData->pfnLogFunction;
    /*
     *start at the head
     *of the chain
     */
    pDspChain = pInstalData->pHeadDspInstl_Chain;

    if(!(rc = (*pInstalData->pfnSpecifyDisplayAdapter)(hwnd,pszAdapter, &adpentry) ) )
    {
        /*
         *parse out the adapter info
         *and save the key
         */
        svga_ParseAdapter(pDspChain,&adpentry);
        if((rc = (*pInstalData->pfnSpecifyVideoMonitor)(hwnd,pszConfig, &videntry)))
        {
              SvgaReportError(rc,NULL,hwnd);

        }

    }
    return(rc);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:svga_ParseAdapter
 *
 *  Purpose:This routine will move over to the last argument in
 *          the achParms buffer and save it off the the key that
 *          is passed,pszKey is assumed to contain a buffer big
 *          enough to hold the key
 *  Returns:
 *          VOID
\****************************************************************/
VOID  APIENTRY svga_ParseAdapter(PDSPINSTL_CHAIN pInstalChain,
                                 PADAPTERENTRY pAdpentry)
{

     SHORT sCount;
     PSZ   pszEnd;
     PDSPINSTL_CHAIN  pTempChain;

     /*
      *move over to the key for the adapter
      *and save it off
      */
     pszEnd = pAdpentry->achParms;
     for(sCount= (pAdpentry->cParms -1);sCount;sCount--)
     {
          pszEnd = (pszEnd + strlen(pszEnd) +1);
     }
     /*
      *start at the head of the
      *chain and give every node
      *a copy of the key that was selected
      */
     for(pTempChain = pInstalChain;pTempChain; )
     {
          strcpy(pTempChain->pszKey,pszEnd);
          pTempChain = pTempChain->pNextDspInstl;
     }
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:svga_WriteNewResolution
 *
 *  Purpose:To parse the resolution strings and make the
 *          updates to the ini file.
 *  Returns:
 *          Non Zero - Error occurred
 *          0        - No error
\****************************************************************/
ULONG APIENTRY svga_WriteNewResolution(PVIDEOENTRY pVidEntry)
{
    ULONG  cbCount;
    PSZ    pszDelimiter;
    PSZ    pszApplicationName;
    CHAR   szMonitorRes[SIZ_TOWRITE];
    CHAR   szMonitorInt[SIZ_TOWRITE];
    CHAR   szMonitorRef[SIZ_TOWRITE];
    CHAR   szStringToWrite[C_MAX_VID_PARMS];
    SHORT  sArgs;
    ULONG  ulReturn = 0;
    PINIPARMS pIniParms;

    do
    {

           for(cbCount = 0;cbCount <pVidEntry->cVideoParms;cbCount++)
           {
               memset(szResolution,0,sizeof(szResolution) );
               memset(szInterLace,0,sizeof(szInterLace) );
               memset(szStringToWrite,0,C_MAX_VID_PARMS);


               /*
                *parse the three substrings out
                */
                pIniParms= IniParms;
                for(pszDelimiter = pVidEntry->avidparm[cbCount].achParms,sArgs = 0;
                                                       sArgs <pVidEntry->avidparm[cbCount].cParms;
                                                       sArgs++,
                                                       pIniParms++)
                {
                    strcpy(pIniParms->pszParms,pszDelimiter);
                    pszDelimiter = (pszDelimiter + (strlen(pszDelimiter) + 1) );
                }


                /*
                 *write each one out to the ini file
                 */
                pIniParms= IniParms;
                for(sArgs = 0;sArgs <pVidEntry->cVideoParms;
                                                       sArgs++,
                                                       pIniParms++)
                {

                     if( pIniParms->pfnWriteParmToIni(IniParms) )
                     {
                         /*
                          *generate error
                          */
                          break;
                     }
                }
           }
     }ONCE;

     return(ulReturn);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:svga_UpWriteIni
 *
 *  Purpose:Update the ini file.
 *
 *
 *
 *  Usage: Used to update the user ini,expects formed keys,and strings.
 *
 *
 *  Returns:
 *          0 - if successful execution completed
 *          1 - if error
\****************************************************************/
ULONG APIENTRY svga_UpWriteIni(PSZ pszApplication,PSZ pszKey,PSZ pszString)
{

    HINI   UserIni  =  HINI_USERPROFILE;
    ULONG  ulReturn = 0;

    if(!PrfWriteProfileString(UserIni,
                              pszApplication,
                              pszKey,
                              pszString) )
     {
         ulReturn = WRITE_INI_ERROR;
     }
     return(ulReturn);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:svga_WriteResolIni()
 *
 *  Purpose:Set up to right the resolution to the ini file
 *          based on the arguments contained in the pIniParms
 *          structure.
 *
 *  Returns:
 *          0 - if successful execution completed
 *          1 - if error
\****************************************************************/
INT   APIENTRY svga_WriteResolIni(PINIPARMS pIniParms)
{
     APIRET ulRet;

     /*
      *write out the string to the ini
      */
     ulRet = svga_UpWriteIni(MONITOR_RES,
                                 pIniParms->pszParms,
                                 pIniParms[INDEX_VREFRESH].pszParms);

     return(!ulRet);

}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:WaitThread
 *
 *  Purpose:This thread will sleep for SLEEP_TIME milliseconds,
 *          query the process id of that was passed to in the
 *          pWaitData structure.Once the process id we are interested
 *          in,is no longer a valid process,this thread will post
 *          the AM_QUIT message back to the owner of hwnd.
 *          The session id that was passed to the thread in the
 *          pWaitData structure will also be terminated.
 *  Returns:
 *          VOID
\****************************************************************/
VOID APIENTRY WaitThread(PVOID pvMessageData)
{
    PSVGAWAITDATA pWaitData;
    RESULTCODES  Results;
    ULONG ulProcessId;
    USHORT usPriority,rc;
    HWND hwndMain;

    pWaitData = (PSVGAWAITDATA)pvMessageData;

//    DosSetPriority( 2, 1, -20, 0);
    do
    {
          /*
           *
           */
           DosSleep(SLEEP_TIME);
           if(rc = Dos16GetPrty(PRTYS_PROCESS,
                             &usPriority,
                             (USHORT)pWaitData->ulProcessid) )
           {
               if(rc == ERROR_INVALID_PROCID)
               {
                    break;
               }

           }

     }FOREVER;

     /*
      *send message back to the main loop
      *that we are done
      */
     if(pWaitData->hwnd)
     {
//          DosEnterCritSec();
          WinPostMsg(pWaitData->hwnd, AM_QUIT,(MPARAM)FALSE, 0);
     }


     /*
      *kill off the session that svga.exe
      *was started in
      */
      DosStopSession(0,pWaitData->ulSession);
      DosExit(EXIT_THREAD,0);
}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:WaitSvgaDlgProc()
 *
 *  Purpose:This routine throws up the Hardware determination in
 *          progress dialog box,and waits for the AM_QUIT message
 *          to be sent back to it. No buttons are enable on the
 *          dialog box,so no other messages,except the default are
 *          expected.
 *  Returns:
 *          TRUE is always returned.
\****************************************************************/
MRESULT EXPENTRY WaitSvgaDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2)
{

    HWND     hwndListBox;
    ULONG    iItem,ulCount;
    static    SVGAWAITDATA WaitData;


    switch (msg)
    {
        case WM_INITDLG:
            hwndListBox = WinWindowFromID(hwnd, IDL_GENERAL);
            CenterDialog(hwnd);

            /*
             * Create a seperate thread to run svga.exe
             */

            WaitData.hwnd = hwnd;

            if(DosCreateThread(&tidThread,
                               (PFNTHREAD)RunSvga,
                               (ULONG)&WaitData,
                               FALSE,
                               STACK_SIZE_THRD) )
            {
                WinPostMsg(hwnd, AM_QUIT,(MPARAM)TRUE, 0);
            }


//91642             if( RunSvga(hwnd) )
//91642             {
//91642                 WinPostMsg(hwnd, AM_QUIT,(MPARAM)TRUE, 0);
//91642             }
            break;
        case WM_CLOSE:
            break;
        /*
         *our thread should send us this message
         *when the svga process dies
         */
        case AM_QUIT:
//91642             DosKillThread(tidThread);
             WinDismissDlg(hwnd,SHORT1FROMMP(mp1));
             break;

        default:
            return(WinDefDlgProc(hwnd, msg, mp1, mp2));
            break;
    }
    return 0L;
}

/****************************************************************\
 *
 *-----------------------------------------------------------------------
 *
 *  Name:SelectSvgaUtilDlgProc()
 *
 *  Purpose:This routine is the main dialog procedure for selecting an SVGA
 *          monitor configuration utility.
 *
 *  Called by: GetResolutionsData()
 *
 *  Calls to:  InitHelp()
 *             CreateSvgaTmpBat()
 *             SvgaUtilDlgProc()
 *             SvgaReportError()
 *
 *  Returns:
 *          (MPARAM)TRUE is returned on an error condition or WM_CANCEL
\************************************************************************/

MRESULT EXPENTRY SelectSvgaUtilDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2)
{
    BOOL   fError;
    APIRET apiRet;

    switch(msg)
    {
        case WM_INITDLG:
             /*
               initialize Help Manager
             */
             InitHelp(&hwndHelpInstance);
             if (hwndHelpInstance)
                WinAssociateHelpInstance(hwndHelpInstance, hwnd);

             CenterDialog(hwnd);
             break;

        case WM_COMMAND:
             switch (SHORT1FROMMP(mp1))
             {

                 case DID_OK:

                    apiRet = DID_OK;

                    /*
                     * Use Default Settings
                     */

                    if (SHORT1FROMMR(WinSendMsg(WinWindowFromID(hwnd, IDB_DEFAULTSETTINGS),
                                                BM_QUERYCHECK, 0L, 0L)))
                    {
                         if (CreateSvgaTmpBat( NULL ))
                         {
                             SvgaReportError(MSG_UNABLE_TO_DETERMINE_HARD,
                                             NULL,
                                             hwnd);

                             apiRet = DID_ERROR;
                         }

                    }
                    else if (SHORT1FROMMR(WinSendMsg(WinWindowFromID(hwnd, IDB_SVGAUTIL),
                                                BM_QUERYCHECK, 0L, 0L)))
                    {

                         apiRet = WinDlgBox((HWND)HWND_DESKTOP,
                                            HWND_DESKTOP,
                                            (PFNWP)SvgaUtilDlgProc,
                                            hmodResource,
                                            DLG_SVGAUTIL,
                                            NULL);
                    }

                    if (apiRet == DID_OK)
                        WinPostMsg(hwnd, AM_QUIT,0,0);
                    else if (apiRet == DID_ERROR)
                        WinPostMsg(hwnd, AM_QUIT,(MPARAM)TRUE, 0);
                 break;

                 case DID_CANCEL:
                     WinPostMsg(hwnd, AM_QUIT,(MPARAM)TRUE, 0);
                     break;

             }
             break;

        case AM_QUIT:
             WinDismissDlg(hwnd, SHORT1FROMMP(mp1));
             break;

        default:
            return(WinDefDlgProc(hwnd, msg, mp1, mp2));
               break;

    }
    return 0L;
}

/****************************************************************\
 *
 *-----------------------------------------------------------------------
 *
 *  Name:SvgaUtilDlgProc()
 *
 *  Purpose:This routine prompt the user for the SVGA display adapter
 *          utility file location and then creates the batch file
 *          used by RunSvga().
 *
 *  Called by: GetResolutionsData()
 *
 *  Calls to:  InitHelp()
 *             CreateSvgaTmpBat()
 *             SvgaReportError()
 *
 *  Returns:
 *          DID_OK, DID_CANCEL, DID_ERROR
\************************************************************************/

MRESULT EXPENTRY SvgaUtilDlgProc(HWND hwnd, ULONG  msg, MPARAM mp1, MPARAM mp2)
{

   FILEDLG  pfdFileDlg;
   static CHAR szTitle[CCHMAXPATH];
   PSZ pszFullFile = "*.*";
   HWND hwndWinFileDlg;
   PSVGAUTILDATA pUtilData;
   static       CHAR  pszSourceDir[] = "A:\\";
   PSZ          pszName;
   APIRET       apiRet;
   ULONG        ulBufLen;
   USHORT       i;
   FILESTATUS  FileBuf;
   BOOL        fError;
   CHAR        szBuffer[CCHMAXPATH];


    switch(msg)
    {
         case WM_INITDLG:

             if (hwndHelpInstance)
                WinAssociateHelpInstance(hwndHelpInstance, hwnd);

            /*
             * malloc util data structure
             */
             pUtilData = malloc( sizeof( SVGAUTILDATA ) );
             pUtilData->pszBuffer = malloc( CCHMAXPATH );
             pUtilData->pszMsg = malloc( CCHMAXPATH );
             pUtilData->pszTitle = malloc( CCHMAXPATH );
             pUtilData->fParms = FALSE;

             pUtilData->hab = WinInitialize(0);

             /*
              * Load resource strings from dll
              */
             WinLoadString(pUtilData->hab, hmodResource, MSG_FILE_NOT_EXIST, CCHMAXPATH,
                  pUtilData->pszMsg);
             WinLoadString(pUtilData->hab, hmodResource, MSG_SVGAUTIL_NOT_FOUND, CCHMAXPATH,
                  pUtilData->pszTitle);
             WinLoadString(pUtilData->hab, hmodResource, MSG_FILEDLG_TITLE, CCHMAXPATH,
                  szTitle);

             WinSetWindowULong(hwnd, QWL_USER, (ULONG)pUtilData);

             CenterDialog(hwnd);
             WinPostMsg(hwnd,WM_INIT,0,0);
             break;



         case WM_INIT:
             WinSendDlgItemMsg(hwnd,      /* set text limit of entry field */
                      IDE_SOURCEDIR,
                      EM_SETTEXTLIMIT,
                      MPFROMSHORT(CCHMAXPATH -10),
                      (MPARAM)0L);

             WinSetDlgItemText(hwnd,   /* set source directory a:\ */
                     IDE_SOURCEDIR,
                     pszSourceDir);


             WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, IDE_SOURCEDIR));

             break;

         case AM_QUIT:

             pUtilData = (PSVGAUTILDATA)WinQueryWindowULong(hwnd, QWL_USER);

             free( pUtilData->pszBuffer );
             free( pUtilData->pszMsg );
             free( pUtilData->pszTitle );
             free( pUtilData );
             WinTerminate(pUtilData->hab);
             WinDismissDlg(hwnd, SHORT1FROMMP(mp1));
             break;

         case WM_COMMAND:

             switch (SHORT1FROMMP(mp1))
             {

                 case DID_OK:

                     fError = FALSE;
                     fSvgaUtilPresent = FALSE;

                     pUtilData = (PSVGAUTILDATA)WinQueryWindowULong(hwnd, QWL_USER);

                     WinQueryDlgItemText( hwnd,
                                           IDE_SOURCEDIR,
                                           CCHMAXPATH - 10,
                                           pUtilData->pszBuffer );
                     /*
                      * If user selects okay without entering
                      * a utility program
                      */

                     if(!strcmp( pUtilData->pszBuffer, pszSourceDir) ||
                         strlen(pUtilData->pszBuffer) <= 3)
                     {
                            WinPostMsg(hwnd,WM_INIT,0,0);
                            break;
                     }
                     else
                     {
                          /*
                            parse buffer to first space character and
                            only copy name,  not parameters
                           */

                          pUtilData->fParms = FALSE;
                          ulBufLen = strlen( pUtilData->pszBuffer );
                          for( i=0; i<ulBufLen; i++ ) {
                             if( *((CHAR *)pUtilData->pszBuffer + i) == ' ')
                             {
                                 pszName =malloc( i );
                                 memcpy( pszName, pUtilData->pszBuffer, i );
                                 *(pszName + i) = '\0';
                                 pUtilData->fParms = TRUE;
                                 break;
                             }
                          }

                          if(!pUtilData->fParms)
                          {
                             pszName = strdup( pUtilData->pszBuffer );
                          }

                          /*
                           *make sure the program can be found
                           */

                           DosError( HARDERROR_DISABLE );

                           apiRet = DosQueryPathInfo( pszName,
                                               FIL_STANDARD,
                                               &FileBuf,
                                               sizeof( FileBuf ) );

                           DosError( HARDERROR_ENABLE );

                           if(apiRet) {
                              sprintf( szBuffer, pUtilData->pszMsg, pszName );
                              WinMessageBox( HWND_DESKTOP,
                                             hwnd,
                                             szBuffer,
                                             pUtilData->pszTitle,
                                             HELP_DLG_SELECTSVGAUTIL,
                                             MB_OK | MB_HELP | MB_INFORMATION | MB_MOVEABLE);

                             free( pszName );
                             WinPostMsg(hwnd,WM_INIT,0,0);
                             break;
                          }

                          fSvgaUtilPresent = TRUE;

                          if( CreateSvgaTmpBat( pUtilData->pszBuffer ) )
                          {
                              SvgaReportError(MSG_UNABLE_TO_DETERMINE_HARD,
                                              NULL,
                                              hwnd);

                                fError = TRUE;
                          }


                          free( pszName );
                     }

                     (fError ? WinPostMsg(hwnd, AM_QUIT,(MPARAM)DID_ERROR, 0) :
                              WinPostMsg(hwnd, AM_QUIT,(MPARAM)DID_OK,0));
                     break;

                 case DID_LOCATE:

                           memset( &pfdFileDlg,0,sizeof(FILEDLG));
                           pfdFileDlg.cbSize = sizeof(FILEDLG);
                           pfdFileDlg.fl = FDS_HELPBUTTON | FDS_CENTER | FDS_OPEN_DIALOG;
                           pfdFileDlg.pszTitle = szTitle;

                           pUtilData = (PSVGAUTILDATA)WinQueryWindowULong(hwnd,
                                                                 QWL_USER);
                           WinQueryDlgItemText( hwnd,
                                                IDE_SOURCEDIR,
                                                CCHMAXPATH - 10,
                                                pUtilData->pszBuffer );

                           pfdFileDlg.pszIDrive = "A:";
                           if(strcmp( pUtilData->pszBuffer, pszSourceDir ))
                           {
                              ulBufLen = strlen( pUtilData->pszBuffer );
                              for(i=0;i<ulBufLen;i++)
                              {
                                 if(*pUtilData->pszBuffer != ' ')
                                 {
                                    *pfdFileDlg.pszIDrive =
                                         *pUtilData->pszBuffer;
                                    break;
                                 }
                                 pUtilData->pszBuffer++;
                              }
                           }

                           strcpy( pfdFileDlg.szFullFile, pszFullFile );

                           hwndWinFileDlg = WinFileDlg( HWND_DESKTOP, hwnd, &pfdFileDlg );

                           if( hwndWinFileDlg && (pfdFileDlg.lReturn == DID_OK ) )
                           {
                               WinSetDlgItemText( hwnd, IDE_SOURCEDIR, pfdFileDlg.szFullFile );
                           }
                           break;

                 case DID_CANCEL:
                     WinPostMsg(hwnd, AM_QUIT,(MPARAM)DID_CANCEL, 0);
                     break;


                 default:
                     WinDismissDlg(hwnd, SHORT1FROMMP(mp1));
                     break;

             }
             break;

         default:
             return(WinDefDlgProc(hwnd, msg, mp1, mp2));
             break;

    }

    return 0L;

}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:GetResolutionsData()
 *
 *  Purpose:This routine should be used to determine which resolutions
 *          to display to the user. If the default flag is set,the
 *          svgadata.pmi file will be read,and the intersection of the
 *          dsc file and svgadata file will be displayed. Otherwise all
 *          of the resolutions the dsc file supports will be displayed.
 *
 *          pResolutions           - pointer to where to read in the
 *                                   resolutions from the svgadata.pmi
 *                                   file.
 *
 *          pResolutionsToDisplay  - pointer to the array of structures
 *                                   where to store the list of suppoted
 *                                   resolutions to display to the user.
 *
 *          hwnd                   - parent window handle
 *
 *          pInstalData            - pointer to the head of the list that
 *                                   contains the list of resolutions from
 *                                   the dsc file.
 *          fUseDefault            - flag to indicate whether to use
 *                                   only the intersection of the dsc
 *                                   resolutions and the svgadata.pmi
 *                                   resolutons.
 *          pulCount               - pointer to the number of supported
 *                                   resolutions to display
 *
 *  Returns:
 *          apiRet - re-map all error codes to CANCEL_OPERATION
 *                   ,forces the calling program to return to the main
 *                   panel
 *          0      - NO error
\****************************************************************/
APIRET  GetResolutionsData(PRESOLUTIONS pResolutions,
                           PRESOLUTIONS pResolutionsToDisplay,
                           HWND hwnd,
                           PDSPINSTL_CHAIN  pInstalChain,
                           BOOL fUseDefault,
                           PULONG pulCount,
                           PFN pfnGetNext,
                           BOOL *pulShowSelectionsToUser)
{
    APIRET apiRet = 0;
    HWND hwndMain;
    ULONG ulCount,ulSize;
    PVOID pVoid;
    static bOnce = TRUE;
    RESOLUTIONDATA  resData;
    SCREENRESOLUTION screenRes;
    HINI   UserIni  =  HINI_USERPROFILE;


    do
    {

         /*
          *make sure we run svga.exe at least once,or if the
          *svgadata.pmi file does not exist
          */
         if(OpenResolutionsFile(pResolutions,&ulCount) || bOnce)
         {
              /*
               *get handle to our dll's resources
               */
              if(apiRet = GetDllHandle(&hmodResource) )
              {
                   SvgaReportError(MSG_GET_DLL_HANDLE,NULL,hwnd);
                   break;
              }


              /*
               * If a resolution string was passed in then run
               * unattended.
               */
              if( pszResolutionString )
              {
                    if (CreateSvgaTmpBat( NULL ))
                    {
                        SvgaReportError(MSG_UNABLE_TO_DETERMINE_HARD,
                                        NULL,
                                        hwnd);

                        apiRet = DID_ERROR;
                    }

                   apiRet = WinDlgBox((HWND)HWND_DESKTOP,
                                       HWND_DESKTOP,
                                       (PFNWP)WaitSvgaDlgProc,
                                       hmodResource,
                                       DLG_RUNSVGA,
                                       NULL);

              }
              else
              {
                  /*
                   * Prompt for svga utility, create svgatmp.bat
                   * If function fails don't run svgatmp.bat
                   */

                   if(!(apiRet = WinDlgBox((HWND)HWND_DESKTOP,
                                 HWND_DESKTOP,
                                (PFNWP)SelectSvgaUtilDlgProc,
                                 hmodResource,
                                 DLG_SELECTSVGAUTIL,
                                 NULL)))
                   {
                       /*
                        *throw up a message box
                        *to indicate wait a moment
                        *while we run the svgatmp.bat
                        */
                       apiRet = WinDlgBox((HWND)HWND_DESKTOP,
                                           HWND_DESKTOP,
                                           (PFNWP)WaitSvgaDlgProc,
                                           hmodResource,
                                           DLG_RUNSVGA,
                                           NULL);

                       if( apiRet )
                       {

                          SvgaReportError(MSG_UNABLE_TO_DETERMINE_HARD,
                                  NULL,
                                  hwnd);

                       }

                   }
              }
         }
         /*
          *if we got no error while trying to run svga
          */
         if(!apiRet)
         {
             bOnce = FALSE;
             /*
              *we should have a valid file
              *by now
              */
             if(apiRet = OpenResolutionsFile(pResolutions,&ulCount) )
             {
                  /*
                   *report error if we still don't have something
                   *we can read
                   */
                   SvgaReportError(MSG_BAD_RESOLUTIONS_FILE,NULL,hwnd);
                   break;
             }

         }
         *pulShowSelectionsToUser = FALSE;

     }ONCE;

     /*
      * See if a resolution was passed to the action routine DLL.
      * If so, see if is supported in the .PMI.  and then write
      * the resolution to the .ini file.
      */

     if(!apiRet && pszResolutionString )
     {
        f1024K = CheckSVGAMem( pResolutions, ulCount );

        if(CompareResolutions( pszResolutionString,
                           pResolutions, ulCount ) == TRUE)
        {

           StringToResolution( pszResolutionString, &resData );

           screenRes.height = resData.Vert;
           screenRes.width  = resData.Horiz;
           screenRes.colors = resData.Colors;
           screenRes.planes = 1;
           screenRes.floptions = DSP_RESOLUTION_OBTAINABLE;

           if(!PrfWriteProfileData(UserIni,
                                  "PM_DISPLAYDRIVERS",
                                  "DEFAULTSYSTEMRESOLUTION",
                                   &screenRes,
                                   sizeof( SCREENRESOLUTION )))

           {
                apiRet = WRITE_INI_ERROR;
           }

        }

     }
     if(apiRet)
     {
          if (apiRet != CONTINUE_WITH_ERR)
              apiRet = CANCEL_OPERATION;
     }

     return(apiRet);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:OpenResolutionsFile()
 *
 *  Purpose: This routine will open the svgadata.pmi file and if
 *           successful will call readresolutions file.
 *
 *  pResolutions  - pointer to a array of resolutions structures that
 *                  is expected to be large enough to hold all of the
 *                  supported resoulutions.
 *  pulCount     -  the count of supported resolutions will be stored
 *                  here.
 *  Returns:
 *          FALSE   - No Error occurred.
 *          TRUE    - Error occurred.
\****************************************************************/
BOOL OpenResolutionsFile(PRESOLUTIONS pResolutions,PULONG pulCount)
{

    BOOL fError =FALSE;
    HFILE    hf;
    ULONG    ulAction,rc;
    PSZ    pszResolutionsFile = RESOLUTIONS_FILE;
    ULONG  ulBootDrive;

    /*
     *set the boot drive
     */
    DosQuerySysInfo(QSV_BOOT_DRIVE,
                    QSV_BOOT_DRIVE,
                    &ulBootDrive,
                    sizeof(ulBootDrive));
    *pszResolutionsFile = (CHAR)(ulBootDrive + 'A' - 1);
    if(!(rc = DosOpen(pszResolutionsFile,
                       &hf,
                       &ulAction,
                       0,
                       FILE_ARCHIVED | FILE_READONLY | FILE_SYSTEM
                                     | FILE_HIDDEN,
                       FILE_OPEN,
                       OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY,
                       NULL)))
    {
          if(ReadResolutionsFile(pResolutions,hf,pulCount) )
          {
               fError = TRUE;
          }
          DosClose(hf);
    }
    else
    {
          fError =TRUE;
    }

    return(fError);
}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:ReadResolutionsFile()
 *
 *  Purpose: This routine will read the  parameter file, and parse
 *           the graphics information and save the supported resolutions
 *           mode into the pResolutions structure that was passed.
 *           It is assumed the pResolutions structure is large enough to
 *           hold all of the supported resolutions.
 *
 *           pResolutions          - pointer to the list of structures
 *                                   where the resolutions will be stored.
 *           hfile                 - handle to the file that should have
 *                                   already been opened.
 *           pulCount              - where the number of supported resolutions
 *                                   that was placed in pResolutions will be
 *                                   stored.
 *  Returns:
 *          FALSE   - No error occurred.
 *          TRUE    - error occurred.
\****************************************************************/
BOOL ReadResolutionsFile(PRESOLUTIONS pResolutions,HFILE hf,PULONG pulCount)
{
     BOOL fError = TRUE;
     PVOID pvBuffer = NULL;
     FILESTATUS fstsFile;
     ULONG ulBytesRead,ulIndex;
     PSZ pszNextResolution,pszNextMode;


     do
     {
          *pulCount = 0;
          DosQueryFileInfo(hf,
                       FIL_STANDARD,
                       &fstsFile,
                       sizeof(FILESTATUS));                  /* get size of file */

          if(fstsFile.cbFile < (ULONG)-1)                 /* file size < 64K ? */
          {
               pvBuffer = malloc(fstsFile.cbFile + 1);
               if( pvBuffer )
               {
                   DosRead(hf,pvBuffer,fstsFile.cbFile,&ulBytesRead);
                   pszNextResolution = pvBuffer;
                   while(pszNextResolution)
                   {
                        /*
                         *get to the next graphics mode string
                         */
                        if(pszNextMode = strstr(pszNextResolution,GRAPHICS_MODE))
                        {
                             pszNextResolution = (strchr(pszNextMode,':') + 1);
                             pszNextResolution = strip_white(pszNextResolution);
                             ulIndex           = strcspn(pszNextResolution,".");
                             strncpy(pResolutions->achResolutionString,
                                       pszNextResolution,ulIndex);
                             pResolutions++;
                             (*pulCount)++;
                        }
                        else
                        {
                             pszNextResolution = NULL;
                        }
                   }

                   fError = FALSE;

               }

          }
          fError = FALSE;

     }ONCE;

     if(pvBuffer)
     {
          free(pvBuffer);
     }
     return(fError);
}

/*************************************************************
 *
 *
 *    Name: CreateSvgaTmpBat()
 *
 *    Purpose:   This function will make sure svga.exe exist, if
 *               so, it will create the svgatmp.bat file used by
 *               RunSvga()
 *
 *    Returns:  apiRet.
 *
 **************************************************************/
APIRET CreateSvgaTmpBat( CHAR *pszBuffer )
 {
      APIRET apiRet = 0;
      HFILE hFile;
      ULONG ulAction, ulTemp, ulBootDrive;
      PSZ   pszSvgaTmpBatFile = SVGATMP_BAT;
      CHAR  szSvgaFullProg[CCHMAXPATH];
      PSZ   pszArg1 = " ON";
      PSZ   pszArg2 = " INIT";


      memset( szSvgaFullProg,0, sizeof( szSvgaFullProg ) );
      /*
       ** get full program path for svga.exe
       */
      if(!(apiRet = DosSearchPath(SEARCH_ENVIRONMENT,
                        "PATH",
                         SVGA_PROGRAM,
                         szSvgaFullProg,
                         CCHMAXPATH)) )
      {
          /* get boot drive  */
          DosQuerySysInfo(QSV_BOOT_DRIVE,
                          QSV_BOOT_DRIVE,
                            &ulBootDrive,
                           sizeof(ulBootDrive));

          *pszSvgaTmpBatFile = (CHAR)(ulBootDrive + 'A' - 1);

          if(!(apiRet = DosOpen(pszSvgaTmpBatFile,
                     &hFile,
                     &ulAction,
                     0,
                     FILE_NORMAL,
                     FILE_TRUNCATE | FILE_CREATE,
                     OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
                     NULL)))
          {
              strcat( szSvgaFullProg, pszArg1 );

              if( fSvgaUtilPresent ){
                   strcat( pszBuffer, "\r\n" );
                   DosWrite(hFile, pszBuffer, strlen(pszBuffer),
                        &ulTemp);
                   DosWrite(hFile, szSvgaFullProg, strlen(szSvgaFullProg),
                        &ulTemp);
              }
              else{
                   strcat( szSvgaFullProg, pszArg2 );
                   DosWrite(hFile, szSvgaFullProg, strlen(szSvgaFullProg),
                        &ulTemp);
              }

              DosClose(hFile);
          }

      }

      return( apiRet );

}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:RunSvga
 *
 *  Purpose:This routine will run the dos batch file svgatmp.bat.
 *          If user has a Svga Utility, svga.exe will be passed
 *          the argument "ON", else svga.exe will be passed the
 *          arguement "ON DEFAULT". If the svga.exe is successfully
 *          started up in another session then, a separate thread will
 *          be started up,which will monitor the  process id that is
 *          passed to it.
 *
 *  Returns:
 *          Non - zero  - The system error number that occurred.
 *          0 - No Error occurred
\****************************************************************/
VOID RunSvga(PVOID pvMessageData)
{
    APIRET    apiRet = 0;
    ULONG     rc,ulSession,ulProcessId, ulBootDrive;
    CHAR      szArgs[CCHMAXPATH];
    CHAR      szFullProg[CCHMAXPATH];
    PSZ       pszSvgaTmpBatFile = SVGATMP_BAT;
    PSZ       pszCommandCom = "C:\\OS2\\MDOS\\COMMAND.COM";
    static PSZ  pszConfigSys = szConfigSys;
    static PSZ  pszAutoExecName = szAutoExecName;
    static PSZ  pszConfigDsp = szConfigDsp;
    static PSZ  pszAutoExecDsp = szAutoExecDsp;
    STARTDATA StartData;
    FILESTATUS fsts;
    static   PSVGAWAITDATA pWaitData;
    HQUEUE         hqueue;
    REQUESTDATA    requestData;
    ULONG          ulData;
    PSESSIONRESULT psesres;
    BYTE           bElemPrty;
    CHAR           szError[CCHMAXPATH];

    pWaitData = (PSVGAWAITDATA)pvMessageData;

    memset(szArgs,0,sizeof(szArgs) );
    memset(szFullProg,0,sizeof(szFullProg) );
    memset(&StartData,0,sizeof(StartData) );

    /*
     *make sure the program can be found, first search the
     *os2\mdos directory, if not found,  search the path.
     */

    DosQuerySysInfo(QSV_BOOT_DRIVE,
                    QSV_BOOT_DRIVE,
                    &ulBootDrive,
                    sizeof(ulBootDrive));

    *pszCommandCom = (CHAR)(ulBootDrive + 'A' - 1);

    if( apiRet = DosQueryPathInfo( pszCommandCom,
                                   1,
                                   &fsts, sizeof(fsts)))
    {
          apiRet = DosSearchPath(SEARCH_ENVIRONMENT,
                                "PATH",
                                 COMMAND_COM,
                                 szFullProg,
                                 CCHMAXPATH);
    }
    else
      strcpy( szFullProg, pszCommandCom );


    if(!apiRet)
    {

         *pszSvgaTmpBatFile = (CHAR)(ulBootDrive + 'A' - 1);

         if( fSvgaUtilPresent ) {

             /* Before executing command.com, if svga utility present then
                  copy save config.sys and autoexec.bat to *.dsp )  */

             *pszConfigSys      = (CHAR)(ulBootDrive + 'A' - 1);
             *pszAutoExecName   = (CHAR)(ulBootDrive + 'A' - 1);
             *pszAutoExecDsp    = (CHAR)(ulBootDrive + 'A' - 1);
             *pszConfigDsp      = (CHAR)(ulBootDrive + 'A' - 1);

             DosCopy( pszConfigSys, pszConfigDsp, DCPY_EXISTING );
             DosCopy( pszAutoExecName, pszAutoExecDsp, DCPY_EXISTING );

         }
         strcpy( szArgs, "/C ");
         strcat( szArgs, pszSvgaTmpBatFile );

         StartData.Length = sizeof(StartData);
         StartData.Related   = SSF_RELATED_CHILD;
         StartData.FgBg      = SSF_FGBG_FORE;
         StartData.TraceOpt  = SSF_TRACEOPT_NONE;
         StartData.PgmTitle  = COMMAND_COM;
         StartData.PgmName   = szFullProg;
         StartData.PgmInputs = szArgs;
         StartData.TermQ     = "\\queues\\svgainst.que";
         StartData.Environment = NULL;
         StartData.InheritOpt = 0;
         StartData.SessionType = SSF_TYPE_VDM;
         StartData.PgmHandle  =  0;

         if(!(apiRet = DosCreateQueue(&hqueue,
                                     QUE_FIFO,
                                     "\\queues\\svgainst.que")))
         {
             apiRet  = DosStartSession(&StartData,
                               (PULONG)&pWaitData->ulSession,
                               (PPID)&pWaitData->ulProcessid);

             if( apiRet == 0 || apiRet == ERROR_SMG_START_IN_BACKGROUND)
             {
                /* initialize data */
                apiRet = 0;
                requestData.ulData = -1;
                requestData.pid    = pWaitData->ulSession;

                while(!DosReadQueue( hqueue,
                                      &requestData,
                                      &ulData,
                                      (PPVOID)&psesres,
                                      0,
                                      DCWW_WAIT,
                                      &bElemPrty,
                                      NULL) &&
                                      requestData.ulData);

                if(psesres->usResultCode)
                {
                   apiRet = psesres->usResultCode;
                   sprintf(szError, "SVGA.EXE error:rc=%ld", apiRet);
                   svgaLog(szError);

                }

             }
             else
             {
                sprintf(szError, "DosStartSession error:rc=%ld",apiRet);
                svgaLog(szError);
             }

             DosCloseQueue(hqueue);
         }

    }
    if( fSvgaUtilPresent )
    {
         DosCopy( pszConfigDsp, pszConfigSys, DCPY_EXISTING );
         DosCopy( pszAutoExecDsp, pszAutoExecName, DCPY_EXISTING);
         DosDelete( pszAutoExecDsp );
         DosDelete( pszConfigDsp );
    }

    (apiRet ? WinPostMsg(pWaitData->hwnd, AM_QUIT,(MPARAM)TRUE, 0)
        :     WinPostMsg(pWaitData->hwnd, AM_QUIT,(MPARAM)FALSE, 0));

    DosExit(EXIT_THREAD,0);


}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:strip_white
 *
 *  Purpose:strip leading blank character from a string.
 *
 *  Returns:
 *        Pointer to the first non-blank character in the string
 *        that is passed.
\****************************************************************/
PSZ strip_white(PSZ pszString)
{
     while(*pszString == ' ')
     {
          pszString++;
     }
     return(pszString);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:ValidateResolutions
 *
 *  Purpose:If we are not using the default supported resolutions
 *          or if we are using only the supported resolutions and
 *          they are correctly validated,the resolutions that are
 *          contained in the pDspChain will be saved in the
 *          pResolutionToDisplay Stucture. It is expected that the
 *          pResolutions stucture is large enough to hold all of the
 *          supported resolutions.
 *
 *
 *          pResolutions          - pointer to the list of supported resolutions
 *          pResolutionsToDisplay - pointer to the resolutions data structure
 *                                  where the resolutions from the dsc file
 *                                  are saved to.
 *          pInstalData           - pointer to the linked list of resolutions
 *                                  that was passed to us by the
 *                                  display install utility.
 *          fUseDefault           - flag to indicate whether to use the only
 *                                  default resolutions or not.
 *          pulCount              - The number of resolutions that were
 *                                  stored in the pResolutionsToDisplay
 *                                  structure.
 *          ulCount               - The number of supported resolutios
 *                                  in the pResolutions structure.
 *  Returns:
 *          FALSE  - Currently always returns FALSE.
 *          TRUE   - if error
\****************************************************************/
BOOL ValidateResolutions(PRESOLUTIONS     pResolutions,
                         PRESOLUTIONS     pResolutionsToDisplay,
                         PDSPINSTL_CHAIN  pInstalData,
                         BOOL fUseDefault,
                         PULONG pulCount,
                         ULONG ulCount,
                         PFN pfnGetNext)

{

     PDSPINSTL_CHAIN pDspChain;

/* Amol; Defect #58319; 12/09/92 */
     f1024K                         /* Check if SVGA card has more than    */
     = CheckSVGAMem                 /* 512K memory                         */
         (pResolutions, ulCount);

     *pulCount = 0;
     for(pDspChain = pInstalData;pDspChain;
                              pDspChain = pDspChain->pNextDspInstl)
     {
          /*
           *if we've got a resolution
           */
          if(pDspChain->pszResolution)
          {
               /*
                *if we are not using the default include
                *it  ||
                *if we are using the default compare it
                *against the resolutions the adapter card
                *supports for this machine
                */
               if(!fUseDefault  || CompareResolutions(pDspChain->pszResolution,
                                                  pResolutions,ulCount) )
               {
                    /*
                     *save off the resolutions that are supported
                     */
                     strcpy(pResolutionsToDisplay->achResolutionString,
                              pDspChain->pszResolution);
                     (*pulCount)++;
                     pResolutionsToDisplay++;
               }
          }
     }
     return(FALSE);
}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:CompareResolutions
 *
 *  Purpose:To determine if the string pszResolution is contained in
 *          the list of supported resolutions (pSupportedResolutions).
 *          This routine will parse through ulResolutionCount number of
 *          items in the pSupportedResolutions strucuture that is passed.
 *  Returns:
 *          TRUE  -   Supported Resolution
 *          FALSE -   Not supported Resolution
\****************************************************************/
BOOL CompareResolutions(PSZ pszResolution,PRESOLUTIONS pSupportedResolutions,
                           ULONG ulResolutionCount)
{
    BOOL fSupported = FALSE;
    PRESOLUTIONS pTemp;
    ULONG ulCounter = 0;
    RESOLUTIONDATA  DscResolution,SupportedResolution;


    memset(&DscResolution,0,sizeof(RESOLUTIONDATA) );
    StringToResolution(pszResolution,&DscResolution);
    for(pTemp = pSupportedResolutions;ulCounter < ulResolutionCount;
                                   ulCounter++,
                                   pTemp++)
    {
               /*
                *convert each one to resolution format
                */
               memset(&SupportedResolution,0,sizeof(SupportedResolution) );
               StringToResolution(pTemp->achResolutionString,&SupportedResolution);

               /*
                *does  the string match any of
                *our  resoutions
                */

/* Amol; Defect #58319; 12/09/1992  */
               /*
                *if the video board has less than one meg of vram
                *then filter out any drivers that need one meg
                */

               if (!f1024K &&
                   IsResolutionOver1Mg (pszResolution, &DscResolution))

                  break;

              if(DscResolution.Horiz == SupportedResolution.Horiz)
              {
                    if(DscResolution.Vert == SupportedResolution.Vert)
                    {
                         if(DscResolution.Colors == SupportedResolution.Colors)
                         {
                              fSupported = TRUE;
                              break;
                         }
                    }
               }
    }
    return(fSupported);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:StringToResolution
 *
 *  Purpose: Convert a resolution in string format to
 *           it's corresponding parts and put them into
 *           the resolution data structure.
 *  Returns:
 *
 *          VOID - there is no error return.
\****************************************************************/
VOID StringToResolution(PSZ pszString,PRESOLUTIONDATA pResolutionData)
{
     PSZ pszTokens = "0123456789",pszNextToken;
     SHORT sPass;


     for(sPass = 0,pszNextToken = pszString; sPass < RESOLUTION_NUM; sPass++)
     {
          pszNextToken = strpbrk(pszNextToken,pszTokens);
          if(pszNextToken)
          {
               switch(sPass)
               {
               case 0:
                    pResolutionData->Horiz  = atoi(pszNextToken);
                    break;
               case 1:
                    pResolutionData->Vert = atoi(pszNextToken);
                    break;
               case 2:
                    pResolutionData->Colors = atoi(pszNextToken);
                    break;
               }
               pszNextToken = (pszNextToken + strspn(pszNextToken,pszTokens) );
          }
     }
     return;
}
//////////////////////////////////////////////////////////////////
//
//  Name: SvgaReportError
//
//  Purpose: Display error message.
//
//  Usage: Called when a fatal error occurrs while installing a
//         device driver.
//
//  Method: - Display message box with error message.
//          - Log error to logfile.
//
//  Returns:
//
//////////////////////////////////////////////////////////////////

VOID SvgaReportError(ULONG rc,PSZ pszMsg,HWND hwndOwner)
{
//@TM    PSZ  pszErrorTitle = "Svga Installation Error";
    HAB  hab;
    CHAR szMsg[CCHMAXPATH];
    CHAR szErrorTitle[CCHMAXPATH];
    PSZ  pszEnvironment = NULL;


    WinAlarm(HWND_DESKTOP, WA_ERROR);
    hab = WinInitialize(0);

//@TM    if (!pszMsg)
//@TM    {
//@TM        pszMsg = szErrorMsg[rc];
//@TM    }

    WinLoadString(hab, hmodResource, rc, CCHMAXPATH,
           szMsg);


    WinLoadString(hab, hmodResource, MSG_SVGA_ERROR_TITLE, CCHMAXPATH,
           szErrorTitle);

    WinMessageBox(HWND_DESKTOP,
                  hwndOwner,
                  szMsg,
                  szErrorTitle,
                  MBX_INSTERROR,
                  MB_OK | MB_ERROR | MB_MOVEABLE | MB_SYSTEMMODAL);


    /*
     *log the error
     */
     svgaLog(szMsg);

     WinTerminate( hab );

} /* SvgaReportError() */

//////////////////////////////////////////////////////////////////
//
//  Name: CenterDialog
//
//  Purpose: Center a dialog box on the main window.
//
//  Usage: Called during the WM_INITDLG of all dialog window
//         procedures.
//
//  Method:
//
//  Returns:
//        VOID
//////////////////////////////////////////////////////////////////
VOID CenterDialog(HWND hwnd)
{
  SWP    swpDlgPos;                      /* structure for position of dialog */
  SWP    swpFramePos;                     /* structure for position of frame */
  POINTL ptlDesktop;                          /* height and width of desktop */

  /* get gesktop size */
  ptlDesktop.x = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  ptlDesktop.y = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);

  /* get dialog position */
  WinQueryWindowPos(hwnd, &swpDlgPos);

  if (WinIsWindowVisible(hwnd) &&      /* center everything but logo and */
      (hwnd != hwnd))                  /* and main frame on hwndMain     */
  {
    /* get frame position */
    WinQueryWindowPos(hwnd, &swpFramePos);

    /* center the dialog vertically on frame */
    swpDlgPos.y = (SHORT)((swpFramePos.cy / 2) - (swpDlgPos.cy / 2) + swpFramePos.y);

    /* center the dialog horizontally on frame */
    swpDlgPos.x = (SHORT)((swpFramePos.cx /2) - (swpDlgPos.cx /2) + swpFramePos.x);
  }
  else
  {
    /* center the dialog vertically on the desktop */
    swpDlgPos.y = (SHORT)((ptlDesktop.y / 2) - (LONG)(swpDlgPos.cy / 2));

    /* center the dialog horizontally on the desktop */
    swpDlgPos.x = (SHORT)((ptlDesktop.x /2) - (LONG)(swpDlgPos.cx /2));
  }

  /* be sure the dialog didn't go off the left edge of the screen */
  if (swpDlgPos.x < 0)
    swpDlgPos.x = 0;

  /* be sure the dialog didn't go off the bottom edge of the screen */
  if (swpDlgPos.y < 0)
    swpDlgPos.y = 0;

  /* be sure the dialog didn't go off the right edge of the screen */
  if (((LONG)swpDlgPos.x + (LONG)swpDlgPos.cx) > ptlDesktop.x)
    swpDlgPos.x = (SHORT)(ptlDesktop.x - (LONG)swpDlgPos.cx);

  /* be sure the dialog didn't go off the top edge of the screen */
  if (((LONG)swpDlgPos.y + (LONG)swpDlgPos.cy) > ptlDesktop.y)
    swpDlgPos.y = (SHORT)(ptlDesktop.y - (LONG)swpDlgPos.cy);

  /* reposition the dialog and make it visible. */
  WinSetWindowPos(hwnd,
                  HWND_TOP,
                  swpDlgPos.x,
                  swpDlgPos.y,
                  0, 0,
                  SWP_ACTIVATE | SWP_MOVE | SWP_ZORDER | SWP_SHOW);

} /* CenterDialog() */

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:GetDllHandle
 *
 *  Purpose: Get a module resource handle to the svga.dll.
 *
 *
 *
 *  Usage:Pass a  pointer to a  resource handle to the routine. If
 *        error,the system error number is returned,else 0 is
 *        returned.
 *  Returns:
 *          apiRet - System Error number
 *          0 - if no error
\****************************************************************/
APIRET APIENTRY GetDllHandle( PHMODULE phmodResource)
{
     APIRET apiRet;
     CHAR szFailName[CCHMAXPATH];
     PSZ  pszModuleName = S3_MODULE;
     PSZ  pszModuleTemp = S3_MODULE;
     ULONG  ulDrive;
     CHAR szPath[CCHMAXPATH];
     PSZ  pchCur,pszTemp;
     ULONG ulSize;

     DosError(HARDERROR_DISABLE);


     memset(szFailName,0,sizeof(szFailName) );
     /*
      *try to load in from the dpath
      */
     if( pszTemp = strchr(pszModuleTemp,'.') )
     {
          *pszTemp = 0;
     }
     if(apiRet  = DosLoadModule(szFailName, 0,pszModuleTemp, phmodResource) )
     {
          /*
           *if not go out to the drives
           */
          for(ulDrive= 1; ulDrive <= MAXDRIVES;ulDrive++ )
          {
               /*
                *build the paths for each drive,
                *where oh,where might you be tonight
                */
               memset(szPath,0,sizeof(szPath) );
               ulSize = sizeof(szPath) - 3;
               DosQueryCurrentDir(ulDrive,&szPath[3],&ulSize);

               szPath[0] = 'A' + ulDrive - 1;
               szPath[1] = ':';
               szPath[2] = '\\';
               if( (szPath[strlen(szPath)-1]) != '\\')
               {
                    strcat(szPath,"\\");
               }
               strcat(szPath,pszModuleName);
               /*
                *try to load off this drive
                */
               apiRet  = DosLoadModule(szFailName, sizeof(szFailName),
                                       szPath, phmodResource);

               if(!apiRet)
               {
                   /*
                    *we loaded,time to boogey out
                    */
                   break;
               }
          }
     }
     DosError(HARDERROR_ENABLE);

     return(apiRet);
}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name: svgaLog
 *
 *  Purpose:   Generic logging routine for svga installation
 *             error. Note: this should be changed so that the
 *             display install utility can pass through a funciton
 *             pointer to it's own logging function.NOTE>>>>>>
 *
 *
 *
 *  Usage:
 *
 *  Method:
 *          -
 *
 *          -
 *          -
 *
 *          -
 *          -
 *
 *  Returns:
 *
 *          VOID
\****************************************************************/
VOID svgaLog(PSZ pszMsg)
{
     CHAR szDateTime [SIZ_DATE_TIME];
     CHAR *pszNull;


     memset(szDateTime,' ',sizeof(szDateTime) );
     _strdate(szDateTime);
     /*
      *get rid of the null and keep the date,time
      *on the same line in the log file
      */
     if( (pszNull = strchr(szDateTime,'\0') ) )
     {
          *pszNull = ' ';
     }
     _strtime( &szDateTime[SIZ_DATE_TIME /2]);

     if(pfnLogFunction)
     {
          (*pfnLogFunction)(szDateTime);
          (*pfnLogFunction)(pszMsg);
     }
}

//////////////////////////////////////////////////////////////////
//
//  Name: SvgaReportError
//
//  Purpose: Display error message.
//
//  Usage: Called when a fatal error occurrs while installing a
//         device driver.
//
//  Method: - Display message box with error message.
//          - Log error to logfile.
//
//  Returns:
//
//////////////////////////////////////////////////////////////////
USHORT SvgaMessageBox(ULONG rc,PSZ pszMsg,HWND hwndOwner)
{
//@TM    PSZ  pszErrorTitle = "Svga Installation Message";
    HAB  hab;
    USHORT usRc;
    CHAR szMsg[CCHMAXPATH];
    CHAR szErrorTitle[CCHMAXPATH];


    WinAlarm(HWND_DESKTOP, WA_ERROR);
    hab = WinInitialize(0);

//@TM    if (!pszMsg)
//@TM    {
//@TM        pszMsg = szErrorMsg[rc];
//@TM    }

    WinLoadString(hab, hmodResource, MSG_SVGA_INSTALL, CCHMAXPATH,
           szErrorTitle);
    WinLoadString(hab, hmodResource, rc, CCHMAXPATH,
           szMsg);

    usRc = WinMessageBox(HWND_DESKTOP,
                  hwndOwner,
                  szMsg,
                  szErrorTitle,
                  MBX_INSTERROR,
                  MB_YESNO | MB_ERROR | MB_MOVEABLE |
                  MB_DEFBUTTON2 | MB_SYSTEMMODAL );

     WinTerminate( hab );
     return(usRc);
}

/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:GetSelectedResolution
 *
 *  Purpose: This routine will loop through the  list of pSelectedResolutions
 *           for up to ulCount number of elements looking for the ulSelected
 *           flag to be set to TRUE. A pointer to the first ulSelected
 *           element will be returned or NULL if no selection was made.
 *  Returns:
 *          pszResolutions  = a pointer to the selected resolutions string
 *                            or NULL if none was selected.
\****************************************************************/
PSZ GetDesignatedResolution(PDSPINSTL_CHAIN pChain,
                            ULONG ulCount,
                            LONG lOffSetToGet)
{

     ULONG ulCounter;
     PSZ pszResolutions = NULL;
     PDSPINSTL_CHAIN  pTemp;


     for(ulCounter =0,pTemp = pChain; pTemp;
                              pTemp = pTemp->pNextDspInstl,ulCounter++)
     {

          if(pTemp->pszResolution)
          {
               pszResolutions= pTemp->pszResolution;
               break;
          }
     }
     return(pszResolutions);
}

/***************************************************************************/


                                                /* Amol; D58319; 12/09/92  */
BOOL CheckSVGAMem (PRESOLUTIONS pResolutions, ULONG ulResolutionCount)
/*-------------------------------------------------------------------------*\
 *
 * This is a routine to check if 1024x768 resolution has been specified for
 * this SVGA card. If it has been, then the routine returns TRUE else returns
 * FALSE. If the 1024x768 resolution is indeed supported, then it means that
 * the card has at least 1 MB memory on it.
 *
\*-------------------------------------------------------------------------*/
{
   ULONG          ulCounter   =  0;
   RESOLUTIONDATA resData;

   for (; ulCounter < ulResolutionCount; ulCounter++)
   {
      StringToResolution               /* Convert string to resolution     */
         ((pResolutions + ulCounter)->achResolutionString, &resData);

      if ((resData.Horiz >= 1024)   && /* Does this support 1024x768x256 ? */
          (resData.Vert  >= 768)    &&
          (resData.Colors >= 256))
                                       /* Yes, it does support the above ! */
         return TRUE;                  /* Done - return TRUE status        */
   }

   return FALSE;                       /* Done - return FALSE status       */

} /* CheckSVGAMem */

/***************************************************************************/


                                                /* Amol; D58319; 12/11/92  */
BOOL IsResolutionOver1Mg (PSZ pszResolution,PRESOLUTIONDATA  pResolutions)
/*-------------------------------------------------------------------------*\
 *
 * This is a routine to check if pszResolution specifies a driver requiring
 * 1 MB or more.
 *
 * The routine returns TRUE if the driver requires 1 MB or more else returns
 * FALSE.
 *
\*-------------------------------------------------------------------------*/
{
   PSZ  pszResCopy = strdup (pszResolution);

   strupr (pszResCopy);

   if ((pResolutions->Horiz  >= 1024)  && /* Check for 1024x768x256 mode   */
       (pResolutions->Vert   >=  768)  &&
       (pResolutions->Colors >=  256))
                                       /* This means more than 1 MB VRAM   */
      return TRUE;                     /* Done - return TRUE status        */

   if (strstr (pszResCopy, "1.0")   && /* Check if 1.0 MB was specified    */
       (strstr (pszResCopy, "MG")   ||
        strstr (pszResCopy, "MB")))
                                       /* 1.0 MB was NOT specified         */
      return TRUE;                     /* Done - return TRUE status        */

   return FALSE;                       /* Done - return FALSE status       */

}  /* IsResolutionOver1Mg */


//////////////////////////////////////////////////////////////////
//
//  Name: InitHelp
//
//  Purpose: Initializes the IPF help facility.
//
//  Usage: Called once during initialization of the program.
//
//  Method: Initializes the HELPINIT structure and creates the
//          help instance.
//
//  Returns:
//
//////////////////////////////////////////////////////////////////

VOID InitHelp(HWND *phwndHelpInstance)
{
  HELPINIT hmInitStruct;
  CHAR     szMsg[CCHMAXPATH];
  CHAR     szErrorTitle[CCHMAXPATH];
  CHAR     szMainTitle[CCHMAXPATH];
  PSZ      pszHelpFile = "C:\\OS2\\HELP\\DSPINSTL.HLP";
  static   HAB      hab;
  ULONG    ulBootDrive;


#ifndef RESPONSE_FILE


  hab = WinInitialize( 0 );
  WinLoadString(hab, hmodResource, MSG_MAINHELPTITLE, CCHMAXPATH,
         szMainTitle);

  DosQuerySysInfo(QSV_BOOT_DRIVE,
                  QSV_BOOT_DRIVE,
                  &ulBootDrive,
                  sizeof(ulBootDrive));

  *pszHelpFile = (CHAR)(ulBootDrive + 'A' - 1);

  /* inititalize help init structure */
  hmInitStruct.cb = sizeof(HELPINIT);
  hmInitStruct.ulReturnCode = 0;
  hmInitStruct.pszTutorialName = (PSZ)NULL;
  hmInitStruct.phtHelpTable = (PHELPTABLE)(0xffff0000 | MAIN_HELP_TABLE);
  hmInitStruct.hmodHelpTableModule = 0;
  hmInitStruct.hmodAccelActionBarModule = 0;
  hmInitStruct.idAccelTable = 0;
  hmInitStruct.idActionBar = 0;
  hmInitStruct.pszHelpWindowTitle = szMainTitle;
  hmInitStruct.fShowPanelId = (ULONG)CMIC_HIDE_PANEL_ID;
  hmInitStruct.pszHelpLibraryName = pszHelpFile;

  /* creating help instance */
  *phwndHelpInstance = WinCreateHelpInstance(hab, &hmInitStruct);

  if (!*phwndHelpInstance || hmInitStruct.ulReturnCode)
  {
        WinLoadString(hab, hmodResource, MSG_APPTITLE, CCHMAXPATH,
               szErrorTitle);

        WinLoadString(hab, hmodResource, MSG_HELPNOTAVAIL, CCHMAXPATH,
               szMsg);

        WinMessageBox(HWND_DESKTOP,
                      HWND_DESKTOP,
                      szMsg,
                      szErrorTitle,
                      0,
                      MB_OK | MB_INFORMATION | MB_MOVEABLE);

        if (*phwndHelpInstance)
        {
            WinDestroyHelpInstance(hwndHelpInstance);
        }
   }
#endif
} /* InitHelp() */

/**************************************************************************/

