/*++

Copyright (C) 1997-1999  Microsoft Corporation

Module Name:

    CDriver.cpp

Abstract:

    This module implements CDriver and CService classes

Author:

    William Hsieh (williamh) created

Revision History:


--*/

#include "devmgr.h"
#include "cdriver.h"

const TCHAR*  tszStringFileInfo = TEXT("StringFileInfo\\%04X%04X\\");
const TCHAR*  tszFileVersion = TEXT("FileVersion");
const TCHAR*  tszLegalCopyright = TEXT("LegalCopyright");
const TCHAR*  tszCompanyName = TEXT("CompanyName");
const TCHAR*  tszTranslation = TEXT("VarFileInfo\\Translation");
const TCHAR*  tszStringFileInfoDefault = TEXT("StringFileInfo\\040904B0\\");


BOOL
CDriver::Create(
    CDevice* pDevice,
    PSP_DRVINFO_DATA pDrvInfoData
    )
{
    HKEY hKey;
    TCHAR InfPath[MAX_PATH];
    TCHAR InfName[MAX_PATH];

    ASSERT(pDevice);

    m_pDevice = pDevice;
    m_OnLocalMachine  = pDevice->m_pMachine->IsLocal();

    CMachine* pMachine = m_pDevice->m_pMachine;

    ASSERT(pMachine);

    //
    // We can't get the digital signer on remote machines
    //
    if (!m_OnLocalMachine) {
        return TRUE;
    }

    m_hSDBDrvMain = SdbInitDatabase(SDB_DATABASE_MAIN_DRIVERS, NULL);

    //
    // Open drvice's driver registry key to get the InfPath
    //
    hKey = pMachine->DiOpenDevRegKey(*m_pDevice, DICS_FLAG_GLOBAL,
                 0, DIREG_DRV, KEY_READ);

    if (INVALID_HANDLE_VALUE != hKey) {

        DWORD regType;
        DWORD Len = sizeof(InfName);
        CSafeRegistry regDrv(hKey);

        //
        // Get the inf path from the driver key
        //
        if (regDrv.GetValue(REGSTR_VAL_INFPATH,
                            &regType,
                            (PBYTE)InfName,
                            &Len)) {


            if (GetSystemWindowsDirectory(InfPath, ARRAYLEN(InfPath))) {

                if (lstrlen(InfPath))
                {
                    //
                    // Tack on an extra back slash if one is needed
                    //
                    if (_T('\\') != InfPath[lstrlen(InfPath) - 1])
                    {
                        lstrcat(InfPath, TEXT("\\"));
                    }

                    lstrcat(InfPath, TEXT("INF\\"));
                    lstrcat(InfPath, InfName);

                    pMachine->GetDigitalSigner(InfPath, m_DigitalSigner);
                }
            }
        }
    }

    return TRUE;
}

BOOL
CDriver::BuildDriverList(
    PSP_DRVINFO_DATA pDrvInfoData,
    BOOL             bFunctionAndFiltersOnly
    )
{
    SP_DRVINFO_DATA DrvInfoData;
    HSPFILEQ hFileQueue = INVALID_HANDLE_VALUE;
    SP_DEVINSTALL_PARAMS DevInstParams;

    //
    // If we already built up the list of driver files then we don't need
    // to do it again.
    //
    if (m_DriverListBuilt) {
        return m_listDriverFile.GetCount();
    }

    ASSERT(m_pDevice);

    if (!m_OnLocalMachine) {
        AddFunctionAndFilterDrivers(m_pDevice);
        return m_listDriverFile.GetCount();
    }

    CMachine* pMachine = m_pDevice->m_pMachine;
    ASSERT(pMachine);

    hFileQueue = SetupOpenFileQueue();

    //
    // Only build up the list of files from the INF if bFunctionAndFiltersOnly
    // is not TRUE.
    //
    if (!bFunctionAndFiltersOnly) {
        DevInstParams.cbSize = sizeof(DevInstParams);

        if (!pDrvInfoData) {

            pMachine->DiGetDeviceInstallParams(*m_pDevice, &DevInstParams);

            //
            // Set the DI_FLAGSEX_INSTALLEDDRIVER flag before calling SetupDiBuildDriverInfoList.
            // This will have it only put the installed driver into the list.
            //
            DevInstParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER |
                                      DI_FLAGSEX_ALLOWEXCLUDEDDRVS);

            if (pMachine->DiSetDeviceInstallParams(*m_pDevice,
                               &DevInstParams) &&
                pMachine->DiBuildDriverInfoList(*m_pDevice,
                                                SPDIT_CLASSDRIVER)) {


                DrvInfoData.cbSize = sizeof(DrvInfoData);

                //
                // There should only be one driver in this list.  If there isn't any
                // drivers in this list then there must not be a driver currently
                // installed on this device.
                //
                if (pMachine->DiEnumDriverInfo(*m_pDevice, SPDIT_CLASSDRIVER, 0, &DrvInfoData)) {

                    //
                    // Set this as the selected driver
                    //
                    pMachine->DiSetSelectedDriver(*m_pDevice, &DrvInfoData);

                    pDrvInfoData = &DrvInfoData;

                } else {

                    //
                    // We did not find a match...so just destroy it.
                    //
                    pMachine->DiDestroyDriverInfoList(*m_pDevice,
                                                      SPDIT_CLASSDRIVER);

                    pDrvInfoData = NULL;
                }
            }
        }

        if (pDrvInfoData) {


            //
            // Get a list of all the files installed for this device
            //
            if (INVALID_HANDLE_VALUE != hFileQueue) {

                DevInstParams.FileQueue = hFileQueue;
                DevInstParams.Flags |= DI_NOVCP;

                if (pMachine->DiSetDeviceInstallParams(*m_pDevice, &DevInstParams) &&
                    pMachine->DiCallClassInstaller(DIF_INSTALLDEVICEFILES, *m_pDevice)) {
                    //
                    // Dereference the file queue so that we can close it
                    //
                    DevInstParams.FileQueue = NULL;
                    DevInstParams.Flags &= ~DI_NOVCP;
                    pMachine->DiSetDeviceInstallParams(*m_pDevice, &DevInstParams);
                }
            }

            if (pDrvInfoData == &DrvInfoData) {
                pMachine->DiDestroyDriverInfoList(*m_pDevice, SPDIT_CLASSDRIVER);
            }
        }
    }

    //
    // Add the funtion and device and class upper and lower filters, sometimes
    // these aren't added via the INF file directly so this makes sure they
    // show up in the list.
    //
    AddFunctionAndFilterDrivers(m_pDevice, hFileQueue);

    if (hFileQueue != INVALID_HANDLE_VALUE) {
        //
        // Scan the file queue.
        //
        DWORD ScanResult;
        SetupScanFileQueue(hFileQueue,
                           SPQ_SCAN_USE_CALLBACK_SIGNERINFO,
                           NULL,
                           ScanQueueCallback,
                           (PVOID)this,
                           &ScanResult
                           );

        //
        // Close the file queue
        //
        SetupCloseFileQueue(hFileQueue);
    }

    m_DriverListBuilt = TRUE;

    return m_listDriverFile.GetCount();
}

void
CDriver::AddDriverFile(
    CDriverFile* pNewDrvFile
    )
{
    //
    // Check to see if this driver already exists in the list.
    //
    POSITION pos = m_listDriverFile.GetHeadPosition();

    while (NULL != pos) {
        CDriverFile* pDrvFile = m_listDriverFile.GetNext(pos);

        if (lstrcmpi(pDrvFile->GetFullPathName(), pNewDrvFile->GetFullPathName()) == 0) {
            //
            // This file already exists in the list so just return without
            // adding it.
            //
            return;
        }
    }

    m_listDriverFile.AddTail(pNewDrvFile);
}

void
CDriver::AddFunctionAndFilterDrivers(
    CDevice* pDevice,
    HSPFILEQ hFileQueue
    )
{
    TCHAR ServiceName[MAX_PATH];
    ULONG BufferLen;
    HKEY hKey;
    DWORD regType;

    //
    // Get the function driver
    //
    if (pDevice->m_pMachine->DiGetDeviceRegistryProperty(*pDevice,
                     SPDRP_SERVICE,
                     NULL,
                     (PBYTE)ServiceName,
                     sizeof(ServiceName),
                     NULL
                     )) {
        CreateFromService(pDevice, ServiceName, hFileQueue);
    }

    //
    // Add the upper and lower device filters
    //
    for (int i = 0; i<2; i++) {
        BufferLen = 0;
        pDevice->m_pMachine->DiGetDeviceRegistryProperty(
                *pDevice,
                i ? SPDRP_LOWERFILTERS : SPDRP_UPPERFILTERS,
                NULL,
                NULL,
                BufferLen,
                &BufferLen
                );

        if (BufferLen != 0) {
            PTSTR Buffer = new TCHAR[BufferLen+2];

            if (Buffer) {
                ZeroMemory(Buffer, BufferLen+2);

                if (pDevice->m_pMachine->DiGetDeviceRegistryProperty(
                        *pDevice,
                        i ? SPDRP_LOWERFILTERS : SPDRP_UPPERFILTERS,
                        NULL,
                        (PBYTE)Buffer,
                        BufferLen,
                        &BufferLen
                        )) {
                    for (PTSTR SingleItem = Buffer; *SingleItem; SingleItem += (lstrlen(SingleItem) + 1)) {
                        CreateFromService(pDevice, SingleItem, hFileQueue);
                    }
                }

                delete Buffer;
            }
        }
    }

    //
    // Add the upper and lower class filters
    //
    GUID ClassGuid;
    pDevice->ClassGuid(ClassGuid);
    hKey = m_pDevice->m_pMachine->DiOpenClassRegKey(&ClassGuid, KEY_READ, DIOCR_INSTALLER);

    if (INVALID_HANDLE_VALUE != hKey) {

        CSafeRegistry regClass(hKey);

        for (int i = 0; i<2; i++) {
            BufferLen = 0;
            regClass.GetValue(i ? REGSTR_VAL_LOWERFILTERS : REGSTR_VAL_UPPERFILTERS,
                              &regType,
                              NULL,
                              &BufferLen
                              );
            if (BufferLen != 0) {
                PTSTR Buffer = new TCHAR[BufferLen+2];

                if (Buffer) {
                    ZeroMemory(Buffer, BufferLen+2);

                    if (regClass.GetValue(i ? REGSTR_VAL_LOWERFILTERS : REGSTR_VAL_UPPERFILTERS,
                              &regType,
                              (PBYTE)Buffer,
                              &BufferLen
                              )) {
                        for (PTSTR SingleItem = Buffer; *SingleItem; SingleItem += (lstrlen(SingleItem) + 1)) {
                            CreateFromService(pDevice, SingleItem, hFileQueue);
                        }
                    }

                    delete Buffer;
                }
            }
        }
    }

}

void
CDriver::CreateFromService(
    CDevice* pDevice,
    PCTSTR ServiceName,
    HSPFILEQ hFileQueue
    )
{
    SC_HANDLE hscManager = NULL;
    SC_HANDLE hscService = NULL;

    if (!ServiceName) {
        return;
    }

    try
    {
        BOOL ComposePathNameFromServiceName = TRUE;

        // open default database on local machine for now
        hscManager = OpenSCManager(m_OnLocalMachine ? NULL : pDevice->m_pMachine->GetMachineFullName(),
                       NULL, GENERIC_READ);

        if (NULL != hscManager)
        {
            hscService =  OpenService(hscManager, ServiceName, GENERIC_READ);
            if (NULL != hscService)
            {
                QUERY_SERVICE_CONFIG qsc;
                DWORD BytesRequired;

                // first, probe for buffer size
                if (!QueryServiceConfig(hscService, NULL, 0, &BytesRequired) &&
                    ERROR_INSUFFICIENT_BUFFER == GetLastError())
                {
                    TCHAR FullPath[MAX_PATH];
                    BufferPtr<BYTE> BufPtr(BytesRequired);
                    LPQUERY_SERVICE_CONFIG pqsc;
                    pqsc = (LPQUERY_SERVICE_CONFIG)(PBYTE)BufPtr;
                    DWORD Size;

                    if (QueryServiceConfig(hscService, pqsc, BytesRequired, &Size) &&
                        pqsc->lpBinaryPathName &&
                        (TEXT('\0') != pqsc->lpBinaryPathName[0]))
                    {
                        ComposePathNameFromServiceName = FALSE;

                        //
                        // Make sure we have a valid full path.
                        //
                        if (GetFullPathFromImagePath(pqsc->lpBinaryPathName,
                                                     FullPath,
                                                     ARRAYLEN(FullPath))) {

                            if (hFileQueue != INVALID_HANDLE_VALUE) {
                                //
                                // Add the file to the queue.
                                //
                                TCHAR TargetPath[MAX_PATH];
                                lstrcpy(TargetPath, FullPath);
                                PTSTR p = (PTSTR)StrRChr(TargetPath, NULL, TEXT('\\'));
                                if (p) {
                                    *p = TEXT('\0');
                                }

                                SetupQueueCopy(hFileQueue,
                                               NULL,
                                               NULL,
                                               MyGetFileTitle(FullPath),
                                               NULL,
                                               NULL,
                                               TargetPath,
                                               NULL,
                                               0
                                               );
                            } else {
                                //
                                // No file queue was passed in so just manually
                                // add this to our list of driver files.
                                //
                                SafePtr<CDriverFile> DrvFilePtr;
                                CDriverFile* pDrvFile = new CDriverFile();
                                DrvFilePtr.Attach(pDrvFile);

                                //
                                // We will set the GetWin32Error to 0xFFFFFFFF which will
                                // cause the UI to say 'not available' for the
                                // signature.
                                //
                                if (pDrvFile->Create(FullPath,
                                                     m_OnLocalMachine,
                                                     0xFFFFFFFF,
                                                     NULL,
                                                     m_hSDBDrvMain))
                                {
                                    AddDriverFile(pDrvFile);
                                    DrvFilePtr.Detach();
                                }
                            }
                        }
                    }
                }

                CloseServiceHandle(hscService);
                hscService = NULL;
            }

            CloseServiceHandle(hscManager);
            hscManager = NULL;
        }

        if (ComposePathNameFromServiceName)
        {
            TCHAR FullPathName[MAX_PATH];
            TCHAR SysDir[MAX_PATH];
            
            if ((GetSystemDirectory(SysDir, ARRAYLEN(SysDir)) != 0) &&
                SUCCEEDED(StringCchCopy(FullPathName, ARRAYLEN(FullPathName), SysDir)) &&
                SUCCEEDED(StringCchCat(FullPathName, ARRAYLEN(FullPathName), TEXT("\\drivers\\"))) &&
                SUCCEEDED(StringCchCat(FullPathName, ARRAYLEN(FullPathName), ServiceName)) &&
                SUCCEEDED(StringCchCat(FullPathName, ARRAYLEN(FullPathName), TEXT(".sys")))) {
    
                if (hFileQueue != INVALID_HANDLE_VALUE) {
                    //
                    // Add the file to the queue.
                    //
                    TCHAR TargetPath[MAX_PATH];
                    lstrcpy(TargetPath, FullPathName);
                    PTSTR p = (PTSTR)StrRChr(TargetPath, NULL, TEXT('\\'));
                    if (p) {
                        *p = TEXT('\0');
                    }
    
                    SetupQueueCopy(hFileQueue,
                                   NULL,
                                   NULL,
                                   MyGetFileTitle(FullPathName),
                                   NULL,
                                   NULL,
                                   TargetPath,
                                   NULL,
                                   0
                                   );
                } else {
                    //
                    // No file queue was passed in so just manually
                    // add this to our list of driver files.
                    //
                    SafePtr<CDriverFile> DrvFilePtr;
                    CDriverFile* pDrvFile = new CDriverFile();
                    DrvFilePtr.Attach(pDrvFile);
    
                    //
                    // We will set the GetWin32Error to 0xFFFFFFFF which will
                    // cause the UI to say 'not available' for the
                    // signature.
                    //
                    if (pDrvFile->Create(FullPathName,
                                         m_OnLocalMachine,
                                         0xFFFFFFFF,
                                         NULL,
                                         m_hSDBDrvMain))
                    {
                        AddDriverFile(pDrvFile);
                        DrvFilePtr.Detach();
                    }
                }
            }
        }
    }

    catch (CMemoryException* e)
    {
        if (hscService)
        {
            CloseServiceHandle(hscService);
        }

        if (hscManager)
        {
            CloseServiceHandle(hscManager);
        }
        throw;
    }
}

CDriver::~CDriver()
{
    if (!m_listDriverFile.IsEmpty())
    {
        POSITION pos = m_listDriverFile.GetHeadPosition();

        while (NULL != pos) {
            CDriverFile* pDrvFile = m_listDriverFile.GetNext(pos);
            delete pDrvFile;
        }

        m_listDriverFile.RemoveAll();
    }

    if (m_hSDBDrvMain) {
        SdbReleaseDatabase(m_hSDBDrvMain);
    }
}

BOOL
CDriver::operator ==(
    CDriver& OtherDriver
    )
{
    CDriverFile* pThisDrvFile;
    CDriverFile* pOtherDrvFile;
    BOOL DrvFileFound = FALSE;
    PVOID ThisContext, OtherContext;
    if (GetFirstDriverFile(&pThisDrvFile, ThisContext))
    {
        do {

            DrvFileFound = FALSE;

            if (OtherDriver.GetFirstDriverFile(&pOtherDrvFile, OtherContext))
            {
                do {
                    if (*pThisDrvFile == *pOtherDrvFile)
                    {
                        DrvFileFound = TRUE;
                        break;
                    }

                } while (OtherDriver.GetNextDriverFile(&pOtherDrvFile, OtherContext));
            }

        } while (DrvFileFound && GetNextDriverFile(&pThisDrvFile, ThisContext));

        return DrvFileFound;
    }

    else
    {
        // if both do not have driver file, they are equal.
        return !OtherDriver.GetFirstDriverFile(&pOtherDrvFile, OtherContext);
    }
}

//
// Can not throw a exception from this function because it is a callback
//
UINT
CDriver::ScanQueueCallback(
    PVOID Context,
    UINT  Notification,
    UINT_PTR  Param1,
    UINT_PTR  Param2
    )
{
    try
    {
        if (SPFILENOTIFY_QUEUESCAN_SIGNERINFO == Notification && Param1)
        {
            CDriver* pDriver = (CDriver*)Context;

            if (pDriver)
            {
                SafePtr<CDriverFile> DrvFilePtr;
                CDriverFile* pDrvFile = new CDriverFile();
                DrvFilePtr.Attach(pDrvFile);

                //
                // When creating the CDriver set the Win32Error to 0xFFFFFFFF
                // if the user is loged in as a guest.  This is because we
                // cannot tell if a file is digitally signed if the user is
                // a guest.  If the user is not a guest then use the Win32Error
                // returned from setupapi.
                //
                if (pDrvFile->Create((LPCTSTR)((PFILEPATHS_SIGNERINFO)Param1)->Target,
                                     pDriver->IsLocal(),
                                     pDriver->m_pDevice->m_pMachine->IsUserAGuest()
                                       ? 0xFFFFFFFF
                                       : ((PFILEPATHS_SIGNERINFO)Param1)->Win32Error,
                                     ((PFILEPATHS_SIGNERINFO)Param1)->DigitalSigner,
                                     pDriver->m_hSDBDrvMain
                                     ))
                {
                    pDriver->AddDriverFile(pDrvFile);
                    DrvFilePtr.Detach();
                }
            }
        }
    }

    catch (CMemoryException* e)
    {
        e->Delete();
        return ERROR_NOT_ENOUGH_MEMORY;
    }

    return NO_ERROR;
}

BOOL
CDriver::GetFirstDriverFile(
    CDriverFile** ppDrvFile,
    PVOID&  Context
    )
{
    ASSERT(ppDrvFile);

    if (!m_listDriverFile.IsEmpty())
    {
        POSITION pos = m_listDriverFile.GetHeadPosition();
        *ppDrvFile = m_listDriverFile.GetNext(pos);
        Context = pos;
        return TRUE;
    }

    Context = NULL;
    *ppDrvFile = NULL;

    return FALSE;
}

BOOL
CDriver::GetNextDriverFile(
    CDriverFile** ppDrvFile,
    PVOID&  Context
    )
{
    ASSERT(ppDrvFile);

    POSITION pos = (POSITION)Context;

    if (NULL != pos)
    {
        *ppDrvFile = m_listDriverFile.GetNext(pos);
        Context = pos;
        return TRUE;
    }

    *ppDrvFile = NULL;
    return FALSE;
}

void
CDriver::GetDriverSignerString(
    String& strDriverSigner
    )
{
    if (m_DigitalSigner.IsEmpty()) {

        strDriverSigner.LoadString(g_hInstance, IDS_NO_DIGITALSIGNATURE);

    } else {

        strDriverSigner = m_DigitalSigner;
    }
}

BOOL
CDriver::GetFullPathFromImagePath(
    LPCTSTR ImagePath,
    LPTSTR  FullPath,
    UINT    FullPathLength
    )
{
    TCHAR OriginalCurrentDirectory[MAX_PATH];
    LPTSTR pRelativeString;
    LPTSTR lpFilePart;

    if (!ImagePath || (ImagePath[0] == TEXT('\0'))) {
        return FALSE;
    }

    //
    // If we aren't on a local machine then just return the file name and not
    // the full path.
    //
    if (!m_OnLocalMachine) {
        lstrcpyn(FullPath, MyGetFileTitle(ImagePath), FullPathLength);
        return TRUE;
    }

    //
    // First check if the ImagePath happens to be a valid full path.
    //
    if (GetFileAttributes(ImagePath) != 0xFFFFFFFF) {
        ::GetFullPathName(ImagePath, FullPathLength, FullPath, &lpFilePart);
        return TRUE;
    }

    pRelativeString = (LPTSTR)ImagePath;

    //
    // If the ImagePath starts with "\SystemRoot" or "%SystemRoot%" then
    // remove those values.
    //
    if (StrCmpNI(ImagePath, TEXT("\\SystemRoot\\"), lstrlen(TEXT("\\SystemRoot\\"))) == 0) {
        pRelativeString += lstrlen(TEXT("\\SystemRoot\\"));
    } else if (StrCmpNI(ImagePath, TEXT("%SystemRoot%\\"), lstrlen(TEXT("%SystemRoot%\\"))) == 0) {
        pRelativeString += lstrlen(TEXT("%SystemRoot%\\"));
    }

    //
    // At this point pRelativeString should point to the image path relative to
    // the windows directory.
    //
    if (!GetSystemWindowsDirectory(FullPath, FullPathLength)) {
        return FALSE;
    }

    if (!GetCurrentDirectory(ARRAYLEN(OriginalCurrentDirectory), OriginalCurrentDirectory)) {
        OriginalCurrentDirectory[0] = TEXT('\0');
    }

    if (!SetCurrentDirectory(FullPath)) {
        return FALSE;
    }

    ::GetFullPathName(pRelativeString, FullPathLength, FullPath, &lpFilePart);

    if (OriginalCurrentDirectory[0] != TEXT('\0')) {
        SetCurrentDirectory(OriginalCurrentDirectory);
    }

    return TRUE;
}

BOOL
CDriverFile::Create(
    LPCTSTR ServiceName,
    BOOL LocalMachine,
    DWORD Win32Error,
    LPCTSTR DigitalSigner,
    HSDB hSDBDrvMain
    )
{
    if (!ServiceName || (TEXT('\0') == ServiceName[0]))
    {
        return FALSE;
    }

    m_Win32Error = Win32Error;

    if (DigitalSigner) {
        m_strDigitalSigner = DigitalSigner;
    }

    //
    // For remote machine, we can not verify if the driver file exits.
    // we only show the driver name.
    //
    if (LocalMachine) {
        m_Attributes = GetFileAttributes(ServiceName);

        if (0xFFFFFFFF != m_Attributes) {
            m_strFullPathName = ServiceName;

        } else {
            //
            // The driver is a service. Do not search for the current director --
            // GetFullPathName is useless here.
            // Search for Windows dir and System directory
            //
            TCHAR BaseDir[MAX_PATH];

            BaseDir[0] = TEXT('\0');

            if (GetSystemWindowsDirectory(BaseDir, ARRAYLEN(BaseDir))) {

                int Len;

                Len = lstrlen(BaseDir);

                if (Len)
                {
                    if (_T('\\') != BaseDir[Len - 1])
                    {
                        lstrcat(BaseDir, TEXT("\\"));
                    }

                    lstrcat(BaseDir, MyGetFileTitle(ServiceName));
                    m_Attributes = GetFileAttributes(BaseDir);
                }

                if (0xFFFFFFFF == m_Attributes)
                {
                    if (GetSystemDirectory(BaseDir, ARRAYLEN(BaseDir))) {

                        Len = lstrlen(BaseDir);

                        if (Len)
                        {
                            if (_T('\\') != BaseDir[Len - 1])
                            {
                                lstrcat(BaseDir, TEXT("\\"));
                            }

                            lstrcat(BaseDir, MyGetFileTitle(ServiceName));
                            m_Attributes = GetFileAttributes(BaseDir);
                        }
                    }
                }

                //
                // hopeless, we could find the path
                //
                if (0xFFFFFFFF == m_Attributes)
                {
                    return FALSE;
                }

                m_strFullPathName = BaseDir;

            } else {

                return FALSE;
            }
        }

        m_HasVersionInfo = GetVersionInfo();
    }

    else {
        m_strFullPathName = ServiceName;

        //
        //we do not have version info
        //
        m_HasVersionInfo = FALSE;
    }

    if (!m_strFullPathName.IsEmpty() && hSDBDrvMain != NULL) {
        TAGREF tagref = TAGREF_NULL;
        HAPPHELPINFOCONTEXT hAppHelpInfoContext = NULL;
        SDBENTRYINFO entryinfo;
        DWORD cbSize;

        tagref = SdbGetDatabaseMatch(hSDBDrvMain,
                                     (LPTSTR)m_strFullPathName,
                                     INVALID_HANDLE_VALUE,
                                     NULL,
                                     0
                                     );

        if (tagref != TAGREF_NULL) {
            //
            // This driver is in the database.
            //
            m_IsDriverBlocked = TRUE;

            //
            // Call SdbReadDriverInformation to get the database GUID and the
            // driver GUID for this entry.
            //
            ZeroMemory(&entryinfo, sizeof(entryinfo));
            if (SdbReadDriverInformation(hSDBDrvMain,
                                         tagref,
                                         &entryinfo)) {
                //
                // Open up the App help information database and query for the
                // html link.
                //
                hAppHelpInfoContext = SdbOpenApphelpInformation(&(entryinfo.guidDB),
                                                                &(entryinfo.guidID));

                if (hAppHelpInfoContext) {

                    cbSize = 0;
                    PBYTE pBuffer = NULL;

                    cbSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
                                                        ApphelpHelpCenterURL,
                                                        NULL,
                                                        0);

                    if (cbSize &&
                        (pBuffer = new BYTE[cbSize])) {

                        cbSize = SdbQueryApphelpInformation(hAppHelpInfoContext,
                                                            ApphelpHelpCenterURL,
                                                            (LPVOID)pBuffer,
                                                            cbSize);

                        if (cbSize) {
                            m_strHtmlHelpID = (LPTSTR)pBuffer;
                        }

                        delete pBuffer;
                    }

                    SdbCloseApphelpInformation(hAppHelpInfoContext);
                }
            }
        }
    }


    return TRUE;
}
BOOL
CDriverFile::GetVersionInfo()
{
    DWORD Size, dwHandle;

    Size = GetFileVersionInfoSize((LPTSTR)(LPCTSTR)m_strFullPathName, &dwHandle);

    if (!Size)
    {
        return FALSE;
    }

    BufferPtr<BYTE> BufPtr(Size);
    PVOID pVerInfo = BufPtr;

    if (GetFileVersionInfo((LPTSTR)(LPCTSTR)m_strFullPathName, dwHandle, Size,
                pVerInfo))
    {
        // get VarFileInfo\Translation
        PVOID pBuffer;
        UINT Len;
        String strStringFileInfo;

        if (!VerQueryValue(pVerInfo, (LPTSTR)tszTranslation, &pBuffer, &Len))
        {
            strStringFileInfo = tszStringFileInfoDefault;
        }

        else
        {
            strStringFileInfo.Format(tszStringFileInfo, *((WORD*)pBuffer),
                         *(((WORD*)pBuffer) + 1));
        }

        String str;
        str = strStringFileInfo + tszFileVersion;

        if (VerQueryValue(pVerInfo, (LPTSTR)(LPCTSTR)str, &pBuffer, &Len))
        {
            m_strVersion = (LPTSTR)pBuffer;
            str = strStringFileInfo + tszLegalCopyright;

            if (VerQueryValue(pVerInfo, (LPTSTR)(LPCTSTR)str, &pBuffer, &Len))
            {
                m_strCopyright = (LPTSTR)pBuffer;
                str = strStringFileInfo + tszCompanyName;

                if (VerQueryValue(pVerInfo, (LPTSTR)(LPCTSTR)str, &pBuffer, &Len))
                {
                    m_strProvider = (LPTSTR)pBuffer;
                }
            }
        }
    }

    return TRUE;
}


BOOL
CDriverFile::operator ==(
    CDriverFile& OtherDrvFile
    )
{
    return \
       m_HasVersionInfo == OtherDrvFile.HasVersionInfo() &&
       (GetFullPathName() == OtherDrvFile.GetFullPathName() ||
        (GetFullPathName() && OtherDrvFile.GetFullPathName() &&
         !lstrcmpi(GetFullPathName(), OtherDrvFile.GetFullPathName())
        )
       ) &&
       (GetProvider() == OtherDrvFile.GetProvider() ||
        (GetProvider() && OtherDrvFile.GetProvider() &&
         !lstrcmpi(GetProvider(), OtherDrvFile.GetProvider())
        )
       ) &&
       (GetCopyright() == OtherDrvFile.GetCopyright() ||
        (GetCopyright() && OtherDrvFile.GetCopyright() &&
         !lstrcmpi(GetCopyright(), OtherDrvFile.GetCopyright())
        )
       ) &&
       (GetVersion() == OtherDrvFile.GetVersion() ||
        (GetVersion() && OtherDrvFile.GetVersion() &&
         !lstrcmpi(GetVersion(), OtherDrvFile.GetVersion())
        )
       );
}