#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"

#include <windows.h>
#include <initguid.h>
#include <devguid.h>

#include "tchar.h"
#include "string.h"

#include <setupapi.h>
#include <syssetup.h>
#include <regstr.h>
#include <setupbat.h>
#include <cfgmgr32.h>

#include "settings.h"
#include "setinc.h"


ULONG PreConfigured;
ULONG KeepEnabled;


BOOL
CALLBACK
AddPropSheetPageProc(
    IN HPROPSHEETPAGE hpage,
    IN LPARAM lParam
   )
{
    *((HPROPSHEETPAGE *)lParam) = hpage;
    return TRUE;
}


DWORD
DisplayClassInstaller(
    IN DI_FUNCTION      InstallFunction,
    IN HDEVINFO         hDevInfo,
    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
    )

/*++

Routine Description:

  This routine acts as the class installer for Display devices.

Arguments:

    InstallFunction - Specifies the device installer function code indicating
        the action being performed.

    DeviceInfoSet - Supplies a handle to the device information set being
        acted upon by this install action.

    DeviceInfoData - Optionally, supplies the address of a device information
        element being acted upon by this install action.

Return Value:

    If this function successfully completed the requested action, the return
        value is NO_ERROR.

    If the default behavior is to be performed for the requested action, the
        return value is ERROR_DI_DO_DEFAULT.

    If an error occurred while attempting to perform the requested action, a
        Win32 error code is returned.

--*/

{

    DWORD err;
    SP_DRVINFO_DATA DrvInfoData;

    KdPrint(("DisplayClassInstaller function = %d\n", (DWORD) InstallFunction));

    switch(InstallFunction) {

    case DIF_SELECTDEVICE :

        KdPrint(("DisplayClassInstaller DELECTDEVICE \n"));

        if (SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER))
        {
            if (!SetupDiEnumDriverInfo(hDevInfo,
                                       NULL,
                                       SPDIT_CLASSDRIVER,
                                       0,
                                       &DrvInfoData))
            {

                if (GetLastError() == ERROR_NO_MORE_ITEMS)
                {
                    //
                    // This is what happens when an old inf is loaded.
                    // Tell the user it is an old inf.
                    //

                    FmtMessageBox(ghwndPropSheet,   // BUGBUG
                                  MB_ICONEXCLAMATION,
                                  FALSE,
                                  ID_DSP_TXT_INSTALL_DRIVER,
                                  ID_DSP_TXT_BAD_INF);

                    return ERROR_NO_MORE_ITEMS;
                }
            }
        }


        break;

    //
    // we do not handle the following message because we are not
    // plug-and-play yet.
    //

    // case DIF_INSTALLDEVICE :

    default :

        break;
    }

    //
    // If we did not exit from the routine by handling the call, tell the
    // setup code to handle everything the default way.
    //

    return ERROR_DI_DO_DEFAULT;
}











VOID
SetSelectDevParams(
    HDEVINFO hDevInfo
    )

/*++

Routine Description:
    Sets the select device parameters by calling setup apis

Arguments:
    hDevInfo    : Handle to the printer class device information list

--*/
{
    SP_SELECTDEVICE_PARAMS  SelectDevParams;
    SP_DEVINSTALL_PARAMS    DeviceInstallParams;

    ZeroMemory(&SelectDevParams, sizeof(SelectDevParams));

    SelectDevParams.ClassInstallHeader.cbSize
                                 = sizeof(SelectDevParams.ClassInstallHeader);
    SelectDevParams.ClassInstallHeader.InstallFunction
                                 = DIF_SELECTDEVICE;

    //
    // Get current SelectDevice parameters, and then set the fields
    // we want to be different from default
    //

    SetupDiGetClassInstallParams(hDevInfo,
                                 NULL,
                                 &SelectDevParams.ClassInstallHeader,
                                 sizeof(SelectDevParams),
                                 NULL);

    SelectDevParams.ClassInstallHeader.cbSize
                             = sizeof(SelectDevParams.ClassInstallHeader);
    SelectDevParams.ClassInstallHeader.InstallFunction
                             = DIF_SELECTDEVICE;

    //
    // Set the strings to use on the select driver page .
    //

    LoadString(ghmod,
               IDS_DISPLAYINST,
               SelectDevParams.Title,
               sizeof(SelectDevParams.Title));

    LoadString(ghmod,
               IDS_WINNTDEV_INSTRUCT,
               SelectDevParams.Instructions,
               sizeof(SelectDevParams.Instructions));

    LoadString(ghmod,
               IDS_SELECTDEV_LABEL,
               SelectDevParams.ListLabel,
               sizeof(SelectDevParams.ListLabel));

    SetupDiSetClassInstallParams(hDevInfo,
                                 NULL,
                                 &SelectDevParams.ClassInstallHeader,
                                 sizeof(SelectDevParams));


    DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
    SetupDiGetDeviceInstallParams(hDevInfo,
                                  NULL,
                                  &DeviceInstallParams);

    DeviceInstallParams.Flags |= DI_USECI_SELECTSTRINGS | DI_SHOWOEM;
    SetupDiSetDeviceInstallParams(hDevInfo,
                                  NULL,
                                  &DeviceInstallParams);

}


VOID
PreSelectDriver(
    HDEVINFO    hDevInfo,
    LPCTSTR     pszModel
    )
/*++

Routine Description:

    Preselect a manufacturer and model for the driver dialog

    If same model is found select it, else if a match in manufacturer is
    found select first driver for the manufacturer.

--*/
{
    SP_DRVINFO_DATA DrvInfoData;
    DWORD           dwIndex = 0;

    //
    // If no model/manf given select first driver
    //

    if (pszModel && *pszModel)
    {
        DrvInfoData.cbSize = sizeof(DrvInfoData);

        while (SetupDiEnumDriverInfo(hDevInfo,
                                     NULL,
                                     SPDIT_CLASSDRIVER,
                                     dwIndex,
                                     &DrvInfoData))
        {
            if (!lstrcmp(pszModel, DrvInfoData.Description))
            {
                //
                // Found a full match.  We will return.
                //

                SetupDiSetSelectedDriver(hDevInfo,
                                         NULL,
                                         &DrvInfoData);

                return;
            }

            DrvInfoData.cbSize = sizeof(DrvInfoData);
            ++dwIndex;
        }

        //
        // There a many third-party names that we would like to match if
        // the third party driver disk is not available (old driver that
        // was not installed.
        //
        // Let do the mapping of third-party names to currently provided
        // names and restart the "selection".
        //

        // "#9 Imagine 128" = n9i128

    }

    return;
}








DWORD
InstallDriver(
    HWND         hwnd,
    INSTALL_TYPE InstallType,
    LPCTSTR      pszSourceDirectory,
    LPCTSTR      pszModel,
    LPCTSTR      pszInf,
    LPTSTR       serviceName
    )
{
    HCURSOR hCursorOrg;
    HCURSOR hCursor;
    HDEVINFO hDevInfo;
    DWORD err;
    DWORD bEntryFound;
    DWORD retError = NO_ERROR;
    SP_DRVINFO_DATA DriverInfoData;
    SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
    BOOL bThirdParty = FALSE;
    DWORD cbOutputSize;
    HINF InfFileHandle;
    PVOID Context;
    INFCONTEXT infoContext;

    LPTSTR pSourceLists[6];
    LPTSTR *pSourceList = pSourceLists;
    ULONG  pSourceListCount;
    TCHAR  szSourceLocation[LINE_LEN];

    LPTSTR InfName;
    LPTSTR copyFileSection;
    LPTSTR installSection;
    TCHAR installSectionData[LINE_LEN];
    TCHAR szServiceSection[LINE_LEN];
    TCHAR szServiceName[LINE_LEN];
    INFCONTEXT serviceContext;

    TCHAR DeviceInst[LINE_LEN];
    SP_DEVINFO_DATA DeviceInfoData;
    SP_DEVINSTALL_PARAMS DeviceInstallParams;
    TCHAR szSoftwareSection[LINE_LEN];
    INFCONTEXT tmpContext;
    ULONG maxmem;
    ULONG numDev;
    ULONG configFlags;

    TCHAR keyName[LINE_LEN];
    HKEY hkey;
    DWORD disposition;

    //
    // instantiate setup
    //

    hDevInfo = SetupDiCreateDeviceInfoList((LPGUID) &GUID_DEVCLASS_DISPLAY,
                                           hwnd);

    if (hDevInfo == INVALID_HANDLE_VALUE)
        return ERROR_INVALID_PARAMETER;

    if (InstallType != DETECT)
    {
        //
        // Turn on the hourglass since it will take a long time to process
        // the inf file
        //

        hCursorOrg = GetCursor();

        if (hCursor = LoadCursor(NULL, (LPCTSTR) IDC_WAIT))
        {
            SetCursor(hCursor);
        }

        //
        // Build the list of drivers, and select the approrpiate entry within
        // it, if possible.
        // If we are preinstalling, specify the appropriate inf
        //

        if (InstallType == INSTALL)
        {
            if (!SetupDiBuildDriverInfoList(hDevInfo,
                                            NULL,
                                            SPDIT_CLASSDRIVER))
            {
                SetupDiDestroyDeviceInfoList(hDevInfo);
                return ERROR_INVALID_PARAMETER;
            }
        }
        else
        {
            DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);

            SetupDiGetDeviceInstallParams(hDevInfo,
                                          NULL,
                                          &DeviceInstallParams);

            DeviceInstallParams.Flags |= DI_NOFILECOPY |
                                         DI_DONOTCALLCONFIGMG |
                                         DI_ENUMSINGLEINF;

            if (pszSourceDirectory == NULL)
            {
                if (SetupQuerySourceList(SRCLIST_SYSTEM,
                                         &pSourceList,
                                         &pSourceListCount))
                {
                    pSourceListCount = 0;

                    wsprintf(DeviceInstallParams.DriverPath,
                             TEXT("%ws\\%ws\\%ws"),
                             pSourceList[0], WINNT_OEM_DISPLAY_DIR, pszInf);

                    SetupFreeSourceList(&pSourceList, pSourceListCount);
                }
            }
            else
            {
                wsprintf(DeviceInstallParams.DriverPath,
                         TEXT("%ws\\%ws"),
                         pszSourceDirectory, pszInf);
            }

            SetupDiSetDeviceInstallParams(hDevInfo,
                                          NULL,
                                          &DeviceInstallParams);

            if (!SetupDiBuildDriverInfoList(hDevInfo,
                                            NULL,
                                            SPDIT_CLASSDRIVER))

            {
                SetupDiDestroyDeviceInfoList(hDevInfo);
                return ERROR_INVALID_PARAMETER;
            }
        }

        PreSelectDriver(hDevInfo, pszModel);

        //
        // Set the parameters for the window to show appriate text, buttons.
        // Then tell setup to use these parameters
        //

        SetSelectDevParams(hDevInfo);

        //
        // Restore the pointer
        //

        if (hCursorOrg)
        {
            SetCursor(hCursorOrg);
        }


        //
        // Call setup to run the window
        //

reselect:

        bEntryFound = FALSE;

        //
        // Ask the user to pick the device, unless we are preinstalling, in
        // which we just use the preselection.
        //

        if ((InstallType == PREINSTALL) ||
            SetupDiSelectDevice(hDevInfo, NULL))
        {
            DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);

            if (SetupDiGetSelectedDriver(hDevInfo,
                                         NULL,
                                         &DriverInfoData))
            {
                //
                // If this is thrid party driver, put up a popup.
                //

                if (_tcsicmp(DriverInfoData.ProviderName, TEXT("Microsoft")))
                {
                    bThirdParty = TRUE;

                    if (InstallType != PREINSTALL)
                    {
                        if (FmtMessageBox(hwnd,
                                          MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION,
                                          FALSE,
                                          ID_DSP_TXT_THIRD_PARTY,
                                          ID_DSP_TXT_THIRD_PARTY_DRIVER) != IDYES)
                        {
                            goto reselect;
                        }
                    }
                }

                DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);

                if ((SetupDiGetDriverInfoDetail(hDevInfo,
                                                NULL,
                                                &DriverInfoData,
                                                &DriverInfoDetailData,
                                                DriverInfoDetailData.cbSize,
                                                &cbOutputSize)) ||
                    (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
                {
                    bEntryFound = TRUE;
                }
            }
        }

        if (bEntryFound == FALSE)
        {
            retError = GetLastError();
            SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
            SetupDiDestroyDeviceInfoList(hDevInfo);

            return retError;
        }
    }

    //
    // open the inf so we can run the sections in the inf, more or less
    // manually.
    //

    if (InstallType == DETECT)
    {
        InfName = TEXT("display.inf");
        copyFileSection = TEXT("detect");
        installSection = installSectionData;
    }
    else
    {
        InfName = DriverInfoDetailData.InfFileName;
        copyFileSection = DriverInfoDetailData.SectionName;
        installSection = DriverInfoDetailData.SectionName;
    }

    //
    // Open the inf so we can copy the files from it.
    //

    InfFileHandle = SetupOpenInfFile(InfName,
                                     NULL,
                                     INF_STYLE_WIN4,
                                     NULL);

    if (InfFileHandle == INVALID_HANDLE_VALUE)
    {
        retError = ERROR_INVALID_PARAMETER;
    }
    else
    {


        //
        // For drivers we ship, the file information is lcoated in layout.inf.
        // So append that file if we need it.
        //

        if (bThirdParty == FALSE)
        {
            SetupOpenAppendInfFile(NULL,
                                   InfFileHandle,
                                   NULL);
        }

        //
        // Initialize the default callback so that the MsgHandler works
        // properly
        //

        Context = SetupInitDefaultQueueCallback(hwnd);

        //
        // Copy all the files to the disk
        //

        if (InstallType == PREINSTALL)
        {
            pSourceListCount = 0;

            if (pszSourceDirectory == NULL)
            {
                if (SetupQuerySourceList(SRCLIST_SYSTEM,
                                         &pSourceList,
                                         &pSourceListCount))
                {
                    wsprintf(szSourceLocation,
                             TEXT("%ws\\%ws"),
                             pSourceList[0], WINNT_OEM_DISPLAY_DIR);

                    pszSourceDirectory = szSourceLocation;

                    SetupFreeSourceList(&pSourceList, pSourceListCount);
                }
            }
        }

        if (!SetupInstallFromInfSection(hwnd,
                                        InfFileHandle,
                                        copyFileSection,
                                        SPINST_FILES,
                                        NULL,
                                        pszSourceDirectory,
                                        0,
                                        &SetupDefaultQueueCallback,
                                        Context,
                                        NULL,
                                        NULL))
        {
            err = GetLastError();
            DbgPrint("Install files Error %d\n", err);

            //
            // User cancelled.  give them a chance to reselect.
            //
            // If they were doing a detect, just exit with the cancel message.
            //

            if ( (err == ERROR_CANCELLED) &&
                 (InstallType == INSTALL) )
            {
                goto reselect;
            }

            return err;
        }

        //
        // If this is the detect key, then it's a list of all the sections
        // we need to run.  So we will have a loop.
        //

        if (InstallType == DETECT)
        {
            if (!SetupFindFirstLine(InfFileHandle,
                                    TEXT("detect.Services"),
                                    NULL,
                                    &infoContext))
            {
                return ERROR_INVALID_PARAMETER;
            }

            //
            // Get the next driver we have to install in a detect case
            //

detect_next:

            if (!SetupGetStringField(&infoContext,
                                     0,
                                     installSection,
                                     sizeof(installSectionData),
                                     NULL))
            {
                return ERROR_INVALID_PARAMETER;
            }
        }

        wsprintf(szServiceSection,
                 TEXT("%ws.Services"),
                 installSection);

        //
        // Formulate a service install section name based on the
        // install name (add .services at the end).
        // Go in this section and get the name of the service that
        // will be installed.
        //

        if (SetupFindFirstLine(InfFileHandle,
                               szServiceSection,
                               NULL,
                               &serviceContext))
        {
            SetupGetStringField(&serviceContext,
                                1,
                                szServiceName,
                                sizeof(szServiceName),
                                NULL);
        }

        if (serviceName)
        {
            wsprintf(serviceName,
                     TEXT("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%ws"),
                     szServiceName);
        }

        wsprintf(DeviceInst,
                 TEXT("Root\\LEGACY_%ws\\0000"),
                 szServiceName);

        ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
        DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if (SetupDiOpenDeviceInfo(hDevInfo,
                                  DeviceInst,
                                  hwnd,
                                  0,
                                  &DeviceInfoData) ||
            (SetupDiCreateDeviceInfo(hDevInfo,
                                     DeviceInst,
                                     (LPGUID) &GUID_DEVCLASS_DISPLAY,
                                     NULL,
                                     hwnd,
                                     0,
                                     &DeviceInfoData) &&
             SetupDiRegisterDeviceInfo(hDevInfo,
                                       &DeviceInfoData,
                                       0,
                                       NULL,
                                       NULL,
                                       NULL)) )
        {

            //
            // Set the parameters for the installation to do no
            // file copies
            //

            ZeroMemory(&DeviceInstallParams, sizeof(SP_DEVINSTALL_PARAMS));
            DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);

            SetupDiGetDeviceInstallParams(hDevInfo,
                                          &DeviceInfoData,
                                          &DeviceInstallParams);

            //
            // Don't copy the files since we already copied them.
            //
            // Don't configure device automatically otherwise the driver
            // can load, and end up generating a Device0 volatile key which
            // which break the next part of install.
            // This can be removed when we get rid of these Device0 instance
            // mechanism.
            //
            // We only need to enumerate the current inf.
            //

            DeviceInstallParams.Flags |= DI_NOFILECOPY |
                                         DI_DONOTCALLCONFIGMG |
                                         DI_ENUMSINGLEINF;

            lstrcpy(DeviceInstallParams.DriverPath,
                    InfName);

            SetupDiSetDeviceInstallParams(hDevInfo,
                                          &DeviceInfoData,
                                          &DeviceInstallParams);

            if (InstallType == DETECT)
            {
                TCHAR DeviceInstId[LINE_LEN];
                ULONG DeviceInstIdLength;

                //
                // Assume we get the hardware id from the detect driver node
                // line in our INF
                //

                if (SetupGetStringField(&infoContext,
                                        1,
                                        DeviceInstId,
                                        sizeof(DeviceInstId),
                                        NULL))
                {
                    //
                    // Make the DeviceInstId a MULTI_SZ.
                    //

                    DeviceInstIdLength = lstrlen(DeviceInstId);
                    DeviceInstId[DeviceInstIdLength] = (TCHAR) 0;
                    DeviceInstId[DeviceInstIdLength + 1] = (TCHAR) 0;

                    SetupDiSetDeviceRegistryProperty(hDevInfo,
                                                     &DeviceInfoData,
                                                     SPDRP_HARDWAREID,
                                                     (PBYTE) DeviceInstId,
                                                     (DeviceInstIdLength + 2) *
                                                         sizeof(TCHAR));
                }

                if (!SetupDiBuildDriverInfoList(hDevInfo,
                                                &DeviceInfoData,
                                                SPDIT_COMPATDRIVER))
                {
                    err = GetLastError();
                    DbgPrint("SetupDiBuildDriverInfoList Detail Error %d\n", err);

                    return ERROR_INVALID_PARAMETER;
                }

                //
                // Now you're guaranteed to have a non-empty list, and the first
                // (i.e., most-compatible) driver node is the one you want, so
                // so select it.
                //

                DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);

                if (!SetupDiEnumDriverInfo(hDevInfo,
                                           &DeviceInfoData,
                                           SPDIT_COMPATDRIVER,
                                           0,
                                           &DriverInfoData))
                {
                    err = GetLastError();
                    DbgPrint("SetupDiEnumDriverInfo Detail Error %d\n", err);

                    return ERROR_INVALID_PARAMETER;
                }
            }
            else
            {
                SetupDiBuildDriverInfoList(hDevInfo,
                                           &DeviceInfoData,
                                           SPDIT_CLASSDRIVER);

                //
                // Special feature that lets us use the original driver
                // description to find the equivalent one in the new
                // list.
                //

                DriverInfoData.Reserved = 0;
            }

            if (!SetupDiSetSelectedDriver(hDevInfo,
                                          &DeviceInfoData,
                                          &DriverInfoData))
            {
                return ERROR_INVALID_PARAMETER;
            }

            if (!SetupDiInstallDevice(hDevInfo,
                                      &DeviceInfoData))
            {
                return ERROR_INVALID_PARAMETER;
            }

            //
            // Make sure the device is enabled in case the setupapis
            // diabled the device for some reason.
            // See LonnyM for possible fix.
            //

            if (SetupDiGetDeviceRegistryProperty(hDevInfo,
                                                 &DeviceInfoData,
                                                 SPDRP_CONFIGFLAGS,
                                                 NULL,
                                                 (LPBYTE) &configFlags,
                                                 sizeof(DWORD),
                                                 NULL) &&
                (configFlags & CONFIGFLAG_DISABLED))
            {
                configFlags &= ~CONFIGFLAG_DISABLED;

                SetupDiSetDeviceRegistryProperty(hDevInfo,
                                                 &DeviceInfoData,
                                                 SPDRP_CONFIGFLAGS,
                                                 (LPBYTE) &configFlags,
                                                 sizeof(DWORD));
            }

            //
            // Destroy these structures
            //

            if (InstallType == DETECT)
            {
                SetupDiDestroyDriverInfoList(hDevInfo,
                                             &DeviceInfoData,
                                             SPDIT_COMPATDRIVER);
            }
            else
            {
                SetupDiDestroyDriverInfoList(hDevInfo,
                                             &DeviceInfoData,
                                             SPDIT_CLASSDRIVER);
            }
        }
        else
        {
            err = GetLastError();
            DbgPrint("Device Install Detail Error %d\n", err);

            return ERROR_INVALID_PARAMETER;
        }

        //
        // Get any interesteing configuration data for the inf file.
        //

        maxmem = 4;
        numDev = 1;
        PreConfigured = 0;
        KeepEnabled = 0;

        wsprintf(szSoftwareSection,
                 TEXT("%ws.GeneralConfigData"),
                 installSection);

        if (SetupFindFirstLine(InfFileHandle,
                               szSoftwareSection,
                               TEXT("MaximumNumberOfDevices"),
                               &tmpContext))
        {
            SetupGetIntField(&tmpContext,
                             1,
                             &numDev);
        }

        if (SetupFindFirstLine(InfFileHandle,
                               szSoftwareSection,
                               TEXT("MaximumDeviceMemoryConfiguration"),
                               &tmpContext))
        {
            SetupGetIntField(&tmpContext,
                             1,
                             &maxmem);
        }

        if (SetupFindFirstLine(InfFileHandle,
                               szSoftwareSection,
                               TEXT("PreConfiguredSettings"),
                               &tmpContext))
        {
            SetupGetIntField(&tmpContext,
                             1,
                             &PreConfigured);
        }

        if (SetupFindFirstLine(InfFileHandle,
                               szSoftwareSection,
                               TEXT("KeepExistingDriverEnabled"),
                               &tmpContext))
        {
            SetupGetIntField(&tmpContext,
                             1,
                             &KeepEnabled);
        }


        //
        // Write the configuration information to the registry.
        //

        //
        // Increase the number of system PTEs if we have cards that will need
        // more than 10 MEG of PTEs
        //

        if ((maxmem = maxmem * numDev) > 10)
        {
            //
            // we need 1K PTEs to support 1 MEG
            // Then add 50% for other devices this type of machine may have.
            //
            // NOTE - in the future, we may want to be smarter and try
            // to merge with whatever someone else put in there.
            //

            maxmem *= 0x400 * 3/2;

            if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                               TEXT("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"),
                               0,
                               NULL,
                               REG_OPTION_NON_VOLATILE,
                               KEY_READ | KEY_WRITE,
                               NULL,
                               &hkey,
                               &disposition) == ERROR_SUCCESS)
            {
                RegSetValueEx(hkey,
                              TEXT("SystemPages"),
                              0,
                              REG_DWORD,
                              (LPBYTE) &maxmem,
                              sizeof(DWORD));

                RegCloseKey(hkey);
            }
        }

        //
        // We may have to do this for multiple adapters at this point.
        // So loop throught the number of devices, which has 1 as the default
        // value
        //

        do {

            numDev -= 1;

            wsprintf(keyName,
                     TEXT("System\\CurrentControlSet\\Services\\%ws\\Device%d"),
                     szServiceName, numDev);

            if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                               keyName,
                               0,
                               NULL,
                               REG_OPTION_NON_VOLATILE,
                               KEY_READ | KEY_WRITE,
                               NULL,
                               &hkey,
                               &disposition) == ERROR_SUCCESS)
            {
                wsprintf(szSoftwareSection,
                         TEXT("%ws.SoftwareSettings"),
                         installSection);

                if (!SetupInstallFromInfSection(hwnd,
                                                InfFileHandle,
                                                szSoftwareSection,
                                                SPINST_REGISTRY,
                                                hkey,
                                                NULL,
                                                0,
                                                &SetupDefaultQueueCallback,
                                                Context,
                                                NULL,
                                                NULL))
                {
                    return ERROR_INVALID_PARAMETER;
                }

                //
                // Write the description of the device if we are not detecting
                //

                if (InstallType != DETECT)
                {
                    RegSetValueEx(hkey,
                                  TEXT("Device Description"),
                                  0,
                                  REG_SZ,
                                  (LPBYTE) DriverInfoDetailData.DrvDescription,
                                  (lstrlen(DriverInfoDetailData.DrvDescription) + 1) *
                                       sizeof(TCHAR) );
                }

                //
                // Invoke the resource picker for adapters that need it.
                //

                {
                    LOG_CONF LogConfig;
                    RES_DES ResDes;
                    HMODULE hModule;
                    FARPROC PropSheetExtProc;

                    if (CM_Get_First_Log_Conf(&LogConfig,
                                              DeviceInfoData.DevInst,
                                              BASIC_LOG_CONF) == CR_SUCCESS)
                    {
                        //
                        // This device instance has a basic log config, so we want to
                        // give the user a resource selection dialog.
                        // (before we do that, go ahead and free the log config
                        // handle--we don't need it.)
                        //

                        CM_Free_Log_Conf_Handle(LogConfig);

                        if ((hModule = GetModuleHandle(TEXT("setupapi.dll"))) &&
                            (PropSheetExtProc = GetProcAddress(hModule,
                                                               "ExtensionPropSheetPageProc")))
                        {
                            SP_PROPSHEETPAGE_REQUEST PropSheetRequest;
                            HPROPSHEETPAGE    hPage = {0};
                            PROPSHEETPAGE     PropPage;
                            PROPSHEETHEADER   PropHeader;

                            PropSheetRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
                            PropSheetRequest.PageRequested = SPPSR_SELECT_DEVICE_RESOURCES;
                            PropSheetRequest.DeviceInfoSet = hDevInfo;
                            PropSheetRequest.DeviceInfoData = &DeviceInfoData;

                            //
                            // Try to get the property sheet extension from setupapi.
                            //

                            if (PropSheetExtProc(&PropSheetRequest,
                                                 AddPropSheetPageProc,
                                                 &hPage))
                            {

                                PropHeader.dwSize      = sizeof(PROPSHEETHEADER);
                                PropHeader.dwFlags     = PSH_NOAPPLYNOW;
                                PropHeader.hwndParent  = hwnd;
                                PropHeader.hInstance   = ghmod;
                                PropHeader.pszIcon     = NULL;
                                PropHeader.pszCaption  = TEXT(" ");
                                PropHeader.nPages      = 1;
                                PropHeader.phpage      = &hPage;
                                PropHeader.nStartPage  = 0;
                                PropHeader.pfnCallback = NULL;

                                if (PropertySheet(&PropHeader) == -1)
                                {
                                    if(hPage)
                                    {
                                        DestroyPropertySheetPage(hPage);
                                    }
                                }
                                else
                                {
                                    //
                                    // BUGBUG can this return zero ?
                                    //

                                    //
                                    // If we were successful, then we want to retrieve the user's selection.
                                    //

                                    CM_Get_First_Log_Conf(&LogConfig,
                                                          DeviceInfoData.DevInst,
                                                          FORCED_LOG_CONF);

                                    ResDes = LogConfig;

                                    // while(

                                    if (CM_Get_Next_Res_Des(&ResDes,
                                                            ResDes,
                                                            ResType_Mem,
                                                            NULL,
                                                            0) == CR_SUCCESS)
                                    {
                                        MEM_RESOURCE memRes;

                                        if (CM_Get_Res_Des_Data(ResDes,
                                                                &memRes,
                                                                sizeof(memRes),
                                                                0) == CR_SUCCESS)
                                        {
                                            RegSetValueEx(hkey,
                                                          TEXT("MemBase"),
                                                          0,
                                                          REG_DWORD,
                                                          (LPBYTE) &(memRes.MEM_Header.MD_Alloc_Base),
                                                          sizeof(DWORD));
                                        }

                                        CM_Free_Res_Des_Handle(ResDes); // resdesnext
                                    }
                                }
                            }
                        }
                    }
                }

                RegCloseKey(hkey);
            }

        } while (numDev != 0);

        //
        // optinally run the OpenGl section in the inf.
        // Ignore any errors at this point since this is an optional
        // entry.
        //

        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                           TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"),
                           0,
                           NULL,
                           REG_OPTION_NON_VOLATILE,
                           KEY_READ | KEY_WRITE,
                           NULL,
                           &hkey,
                           &disposition) == ERROR_SUCCESS)
        {
            wsprintf(szSoftwareSection,
                     TEXT("%ws.OpenGLSoftwareSettings"),
                     installSection);

            SetupInstallFromInfSection(hwnd,
                                       InfFileHandle,
                                       szSoftwareSection,
                                       SPINST_REGISTRY,
                                       hkey,
                                       NULL,
                                       0,
                                       &SetupDefaultQueueCallback,
                                       Context,
                                       NULL,
                                       NULL);

            RegCloseKey(hkey);
        }

        //
        // Get the next line for detection if we are detecting.
        //

        if ((InstallType == DETECT) &&
            SetupFindNextLine(&infoContext, &infoContext))
        {
            goto detect_next;
        }

        SetupCloseInfFile(InfFileHandle);
    }

    SetupDiDestroyDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
    SetupDiDestroyDeviceInfoList(hDevInfo);

    return retError;
}


DWORD
InstallNewDriver(
    HWND    hwnd,
    LPCTSTR pszModel,
    BOOL    bDetect,
    PBOOL   pbKeepEnabled
    )
{
    DWORD err;
    LPTSTR keyName;

    if (bDetect)
    {
        LPTSTR psz1;
        int  iRet;

        psz1 = FmtSprint(ID_DSP_TXT_AUTODETECT_PROCEED);

        iRet = FmtMessageBox(hwnd,
                             MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION,
                             FALSE,
                             ID_DSP_TXT_INSTALL_DRIVER,
                             ID_DSP_TXT_AUTODETECT,
                             psz1);

        LocalFree(psz1);

        if (iRet != IDYES)
        {
            return ERROR_CANCELLED;
        }
    }

    err = InstallDriver(hwnd,
                        bDetect ? DETECT : INSTALL,
                        NULL,
                        pszModel,
                        NULL,
                        NULL);

    if (err == NO_ERROR)
    {
        DWORD disposition;
        HKEY hkey;

        *pbKeepEnabled = KeepEnabled;

        //
        // Tell the user the driver was installed.
        //

        FmtMessageBox(hwnd,
                      MB_ICONINFORMATION | MB_OK,
                      FALSE,
                      ID_DSP_TXT_INSTALL_DRIVER,
                      ID_DSP_TXT_DRIVER_INSTALLED);

        if (PreConfigured == 0)
        {
            if (bDetect)
            {
                //
                // Write a key to the registry to tell the display applet to
                // cleanup all the drivers after the autodetect.
                //

                keyName = SZ_DETECT_DISPLAY;
            }
            else
            {
                //
                // Create a registry key that indicates a new display was
                // installed.
                //

                keyName = SZ_NEW_DISPLAY;
            }

            if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                               keyName,
                               0,
                               NULL,
                               REG_OPTION_NON_VOLATILE,
                               KEY_READ | KEY_WRITE,
                               NULL,
                               &hkey,
                               &disposition) == ERROR_SUCCESS)
            {
                RegCloseKey(hkey);
            }
        }


        //
        // Save into the registry the fact that it will take a reboot
        // for these changes to take effect
        //

        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                           SZ_REBOOT_NECESSARY,
                           0,
                           NULL,
                           REG_OPTION_VOLATILE,
                           KEY_READ | KEY_WRITE,
                           NULL,
                           &hkey,
                           &disposition) == ERROR_SUCCESS)
        {
            RegCloseKey(hkey);
        }

        //
        // If everything succeeded properly, then we need to reboot the
        // machine
        //
        // Ask the user to reboot the machine.
        //

        PropSheet_RestartWindows(ghwndPropSheet);
        PropSheet_CancelToClose(ghwndPropSheet);

    }
    else if (err != ERROR_CANCELLED)
    {
        //
        // Tell the user the driver was not installed properly.
        //

        FmtMessageBox(hwnd,
                      MB_ICONSTOP | MB_OK,
                      FALSE,
                      ID_DSP_TXT_INSTALL_DRIVER,
                      ID_DSP_TXT_DRIVER_INSTALLED_FAILED);

    }

    return err;
}

DWORD
InstallGraphicsDriver(
    HWND    hwnd,
    LPCWSTR pszSourceDirectory,
    LPCWSTR pszModel,
    LPCWSTR pszInf
    )
{
    DWORD err;
    TCHAR ServiceName[MAX_PATH];

    err = InstallDriver(hwnd,
                        PREINSTALL,
                        pszSourceDirectory,
                        pszModel,
                        pszInf,
                        ServiceName);

    return err;
}



DWORD
PreInstallDriver(
    HWND    hwnd,
    LPCTSTR pszModel,
    LPCTSTR pszInf,
    LPTSTR  ServiceName
    )
{
    DWORD err;

    err = InstallDriver(hwnd,
                        PREINSTALL,
                        NULL,
                        pszModel,
                        pszInf,
                        ServiceName);

    //
    // Tell the user the driver was not installed properly.
    //

    if (err != NO_ERROR)
    {
        FmtMessageBox(hwnd,
                      MB_ICONSTOP | MB_OK,
                      FALSE,
                      ID_DSP_TXT_INSTALL_DRIVER,
                      ID_DSP_TXT_DRIVER_PREINSTALLED_FAILED);
    }

    return err;
}
