//---------------------------------------------------------------------------
// ClassExplorer Pro generated source file
// Created by Jean-Marc on 24.12.2003, 10:02:15
//---------------------------------------------------------------------------
#include <windows.h>
#include <stdlib.h>
#pragma hdrstop
#include "LdriverX.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Constants
//---------------------------------------------------------------------------
// DriverLINX DLL filename
const AnsiString LIBRARY_FILENAME = "DLPortIO.dll";

// WinNT DriverLINX Information
const AnsiString DRIVER_NAME = "DLPortIO";
const AnsiString DISPLAY_NAME = "DriverLINX Port I/O Driver";
const AnsiString DRIVER_GROUP = "SST miniport drivers";
// Define to do a little less error checking
#define FAST
//---------------------------------------------------------------------------


__fastcall TLdriverX::TLdriverX()
  :FLPTNumber(0),    // No LPT selected
   FLPTBase(0),      // No base address
   FLPTCount(0)      // No printer ports counted
{
   unsigned long OsVersion;
   OSVERSIONINFO os;
   OsVersion=GetVersion();
   if(OsVersion < 0x80000000)
   {
     memset(&os, NULL, sizeof(OSVERSIONINFO));
     os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
     GetVersionEx(&os);
     switch (os.dwMajorVersion)
      {
        case 4:FRunningWinNT=true;
        break;
        case 5:FRunningWin2K=true ;
        break;
      }
    }
    else
    FRunningW95=true;
 //  FRunningWinNT=(os.dwPlatformId==VER_PLATFORM_WIN32_NT);

   // Set default WinNT driver path
   char Buffer[MAX_PATH];
   GetSystemDirectory(Buffer, MAX_PATH);
   FDriverPath = AnsiString(Buffer)+"\\DRIVERS";

   // Set the default DLL path
   FDLLPath="";

   FActiveHW=false;  // DLL/Driver not loaded
   FHardAccess=true; // Not used, default true

   FLastError="";    // No errors yet

}
//---------------------------------------------------------------------------

__fastcall TLdriverX::~TLdriverX()
{
     if (IsLoaded()) CloseDriver();
}
//---------------------------------------------------------------------------
bool __fastcall TLdriverX::ConnectSCM()
{
   DWORD dwStatus = 0; // Assume success, until we prove otherwise
   DWORD scAccess;     // Access mode when connecting to SCM

   // Try and connect as administrator
   scAccess = SC_MANAGER_CONNECT |
              SC_MANAGER_QUERY_LOCK_STATUS |
              SC_MANAGER_ENUMERATE_SERVICE |
              SC_MANAGER_CREATE_SERVICE;      // Admin only

   // Connect to the SCM
   hSCMan = OpenSCManager(NULL, NULL, scAccess);

   // If we're not in administrator mode, try and reconnect
   if (hSCMan==NULL && GetLastError()==ERROR_ACCESS_DENIED)
   {
      scAccess = SC_MANAGER_CONNECT |
                 SC_MANAGER_QUERY_LOCK_STATUS |
                 SC_MANAGER_ENUMERATE_SERVICE;

      // Connect to the SCM
      hSCMan = OpenSCManager(NULL, NULL, scAccess);
   }

   // Did it succeed?
   if (hSCMan==NULL)
   {
      // Failed, save error information
      dwStatus=GetLastError();
      FLastError="ConnectSCM: Error #"+IntToStr(dwStatus);
   }

   return dwStatus==0; // Success == 0
}
//---------------------------------------------------------------------------

void __fastcall TLdriverX::DisconnectSCM()
{
  if (hSCMan != NULL)
   {
      // Disconnect from our local Service Control Manager
      CloseServiceHandle(hSCMan);
      hSCMan=NULL;
   }
}
//---------------------------------------------------------------------------

bool __fastcall TLdriverX::DriverInstall()
{
   SC_HANDLE hService; // Handle to the new service
   DWORD dwStatus = 0; // Assume success, until we prove otherwise

   FDrvPrevInst=false; // Assume the driver wasn't installed previously

   // Path including filename
   AnsiString DriverPath = FDriverPath+"\\"+DRIVER_NAME+".SYS";

   // Is the DriverLINX driver already in the SCM? If so,
   // indicate success and set FDrvPrevInst to true.
   hService=OpenService(hSCMan, DRIVER_NAME.c_str(), SERVICE_QUERY_STATUS);
   if (hService!=NULL)
   {
      FDrvPrevInst=true;            // Driver previously installed, don't remove
      CloseServiceHandle(hService); // Close the service
      return true;                  // Success
   }

   // Add to our Service Control Manager's database
   hService=CreateService(
               hSCMan,
               DRIVER_NAME.c_str(),
               DISPLAY_NAME.c_str(),
               SERVICE_START | SERVICE_STOP | DELETE | SERVICE_QUERY_STATUS,
               SERVICE_KERNEL_DRIVER,
               SERVICE_DEMAND_START,
               SERVICE_ERROR_NORMAL,
               DriverPath.c_str(),
               DRIVER_GROUP.c_str(),
               NULL, NULL, NULL, NULL);

   if (hService==NULL)
      dwStatus=GetLastError();
   else
      // Close the service for now...
      CloseServiceHandle(hService);

   if (dwStatus!=0)
      FLastError="DriverInstall: Error #"+IntToStr(dwStatus);

   return dwStatus==0; // Success == 0
}
//---------------------------------------------------------------------------

bool __fastcall TLdriverX::DriverStart()
{
    SC_HANDLE hService; // Handle to the service to start
   DWORD dwStatus = 0; // Assume success, until we prove otherwise

   SERVICE_STATUS sStatus;

   FDrvPrevStart=false; // Assume the driver was not already running

   hService = OpenService(hSCMan, DRIVER_NAME.c_str(), SERVICE_QUERY_STATUS);
   if (hService!=NULL && QueryServiceStatus(hService, &sStatus))
   {
      // Got the service status, now check it
      if (sStatus.dwCurrentState==SERVICE_RUNNING)
      {
         FDrvPrevStart=true;           // Driver was previously started
         CloseServiceHandle(hService); // Close service
         return true;                  // Success
      }
      else if (sStatus.dwCurrentState==SERVICE_STOPPED)
      {
         // Driver was stopped. Start the driver.
         CloseServiceHandle(hService);
         hService = OpenService(hSCMan, DRIVER_NAME.c_str(), SERVICE_START);
         if (!StartService(hService, 0, NULL))
            dwStatus=GetLastError();
         CloseServiceHandle(hService); // Close service
      }
      else dwStatus=-1; // Can't run the service
   }
   else
      dwStatus=GetLastError();

   if (dwStatus!=0)
      FLastError="DriverStart: Error #"+IntToStr(dwStatus);

   return dwStatus==0; // Success == 0
}
//---------------------------------------------------------------------------

bool __fastcall TLdriverX::DriverStop()
{
   SC_HANDLE hService; // Handle to the service to start
   DWORD dwStatus = 0; // Assume success, until we prove otherwise

   // If we didn't start the driver, then don't stop it.
   // Pretend we stopped it, by indicating success.
   if (FDrvPrevStart) return true;

   // Get a handle to the service to stop
   hService = OpenService(
                 hSCMan,
                 DRIVER_NAME.c_str(),
                 SERVICE_STOP | SERVICE_QUERY_STATUS);

   if (hService!=NULL)
   {
      // Stop the driver, then close the service
      SERVICE_STATUS sStatus;

      if (!ControlService(hService, SERVICE_CONTROL_STOP, &sStatus))
         dwStatus = GetLastError();

      // Close the service
      CloseServiceHandle(hService);
   }
   else
      dwStatus = GetLastError();

   if (dwStatus!=0)
      FLastError="DriverStop: Error #"+IntToStr(dwStatus);

   return dwStatus==0; // Success == 0
}

//---------------------------------------------------------------------------
bool __fastcall TLdriverX::DriverRemove()
{
   SC_HANDLE hService; // Handle to the service to start
   DWORD dwStatus = 0; // Assume success, until we prove otherwise

   // If we didn't install the driver, then don't remove it.
   // Pretend we removed it, by indicating success.
   if (FDrvPrevInst) return true;

   // Get a handle to the service to remove
   hService = OpenService(
                 hSCMan,
                 DRIVER_NAME.c_str(),
                 DELETE);

   if (hService!=NULL)
   {
      // Remove the driver then close the service again
      if (!DeleteService(hService))
         dwStatus = GetLastError();

      // Close the service
      CloseServiceHandle(hService);
   }
   else
      dwStatus = GetLastError();

   if (dwStatus!=0)
      FLastError="DriverRemove: Error #"+IntToStr(dwStatus);

   return dwStatus==0; // Success == 0
}
//---------------------------------------------------------------------------

void __fastcall TLdriverX::OpenDriver()
{
     // If the DLL/driver is already open, then forget it!
   if (IsLoaded()) return;

   // If we're running Windows NT, install the driver then start it
   if (FRunningWinNT ||FRunningWin2K)
   {
      // Connect to the Service Control Manager
      if (!ConnectSCM()) return;

      // Install the driver
      if (!DriverInstall())
      {
         // Driver install failed, so disconnect from the SCM
         DisconnectSCM();
         return;
      }

      // Start the driver
      if (!DriverStart())
      {
         // Driver start failed, so remove it then disconnect from SCM
         DriverRemove();
         DisconnectSCM();
         return;
      }
   }
     // Load DLL library
   AnsiString LibraryFileName = LIBRARY_FILENAME;

   if (FDLLPath.Length()>0)
      LibraryFileName = FDLLPath+"\\"+LIBRARY_FILENAME;

   FDLLInst=LoadLibrary(LibraryFileName.c_str());
   if (FDLLInst!=NULL)
   {
      DlReadByte=(TDlPortReadPortUchar)
                  GetProcAddress(FDLLInst,"DlPortReadPortUchar");
      DlReadWord=(TDlPortReadPortUshort)
                  GetProcAddress(FDLLInst,"DlPortReadPortUshort");
      DlReadDWord=(TDlPortReadPortUlong)
                   GetProcAddress(FDLLInst,"DlPortReadPortUlong");

      DlWriteByte=(TDlPortWritePortUchar)
                   GetProcAddress(FDLLInst,"DlPortWritePortUchar");
      DlWriteWord=(TDlPortWritePortUshort)
                   GetProcAddress(FDLLInst,"DlPortWritePortUshort");
      DlWriteDWord=(TDlPortWritePortUlong)
                    GetProcAddress(FDLLInst,"DlPortWritePortUlong");

      DlReadBufferByte=(TDlPortReadPortBufferUchar)
                        GetProcAddress(FDLLInst,"DlPortReadPortBufferUchar");
      DlReadBufferWord=(TDlPortReadPortBufferUshort)
                        GetProcAddress(FDLLInst,"DlPortReadPortBufferUshort");
      DlReadBufferDWord=(TDlPortReadPortBufferUlong)
                         GetProcAddress(FDLLInst,"DlPortReadPortBufferUlong");

      DlWriteBufferByte=(TDlPortWritePortBufferUchar)
                         GetProcAddress(FDLLInst,"DlPortWritePortBufferUchar");
      DlWriteBufferWord=(TDlPortWritePortBufferUshort)
                         GetProcAddress(FDLLInst,"DlPortWritePortBufferUshort");
      DlWriteBufferDWord=(TDlPortWritePortBufferUlong)
                          GetProcAddress(FDLLInst,"DlPortWritePortBufferUlong");

      // Make sure all our functions are there
      if (DlReadByte!=NULL && DlReadWord!=NULL && DlReadDWord!=NULL &&
          DlWriteByte!=NULL && DlWriteWord!=NULL && DlWriteDWord!=NULL &&
          DlReadBufferByte!=NULL && DlReadBufferWord!=NULL &&
          DlReadBufferDWord!=NULL && DlWriteBufferByte!=NULL &&
          DlWriteBufferWord!=NULL && DlWriteBufferDWord!=NULL)
         FActiveHW=true; // Success
   }

   // Did we fail?
   if (!FActiveHW)
   {
      // If we're running Windows NT, stop the driver then remove it
      // Forget about any return (error) values we might get...
      if (FRunningWinNT ||FRunningWin2K)
      {
         DriverStop();
         DriverRemove();
         DisconnectSCM();
      }

      // Free the library
      if (FDLLInst!=NULL)
      {
         FreeLibrary(FDLLInst);
         FDLLInst=NULL;
      }
    }
}
//---------------------------------------------------------------------------

void __fastcall TLdriverX::CloseDriver()
{
     // Don't close anything if it wasn't opened previously
   if (!IsLoaded()) return ;

   // If we're running Windows NT, stop the driver then remove it
   if (FRunningWinNT ||FRunningWin2K)
   {
      if (!DriverStop()) return ;
      if (!DriverRemove()) return ;
      DisconnectSCM();
   }

   // Free the library
   if (FreeLibrary(FDLLInst)==0) return ;
   FDLLInst=NULL;
   FActiveHW=false; // Success

}
//---------------------------------------------------------------------------
void __fastcall TLdriverX::DetectPorts()
{
   // Detect the printer ports available
   if (FRunningWinNT)
       DetectPortsNT(); // WinNT version
   if (FRunningWin2K)
      DetectPorts2k(); // WinNT version
   if (FRunningW95)
      DetectPorts9x(); // Win9x version
}
//---------------------------------------------------------------------------
void __fastcall TLdriverX::DetectPorts9x()
{
    const char *BASE_KEY = "Config Manager\\Enum";
   const char *PROBLEM = "Problem";
   const char *ALLOCATION = "Allocation";
   const char *PORTNAME = "PortName";
   const char *HARDWARE_KEY = "HardwareKey";

   const REGSAM KEY_PERMISSIONS = KEY_ENUMERATE_SUB_KEYS |
                                  KEY_QUERY_VALUE;

   HKEY CurKey;               // Current key when using the registry
   char KeyName[MAX_PATH];    // A key name when using the registry

   char **KeyList;            // List of keys
   ULONG KeyCount;            // Count of the number of keys in KeyList

   // Clear the port count
   FLPTCount = 0;

   // Clear the port array
   for (int index=0; index<=MAX_LPT_PORTS; index++)
      FLPTAddress[index] = 0;

   // Open the registry
   RegOpenKeyEx(HKEY_DYN_DATA, BASE_KEY, 0, KEY_PERMISSIONS, &CurKey);

   // Grab all the key names under HKEY_DYN_DATA
   //
   // Do this by first counting the number of keys,
   // then creating an array big enough to hold them
   // using the KeyList pointer.

   FILETIME DummyFileTime;
   ULONG DummyLength = MAX_PATH;
   KeyCount = 0;
   while (RegEnumKeyEx(
            CurKey, KeyCount++, KeyName, &DummyLength,
            NULL, NULL, NULL, &DummyFileTime
                       ) != ERROR_NO_MORE_ITEMS)
   {
      DummyLength = MAX_PATH;
   }

   KeyList = new char*[KeyCount];

   KeyCount = 0;
   DummyLength = MAX_PATH;
   while (RegEnumKeyEx(
            CurKey, KeyCount, KeyName, &DummyLength,
            NULL, NULL, NULL, &DummyFileTime
                       ) != ERROR_NO_MORE_ITEMS)
   {
      KeyList[KeyCount] = new char[DummyLength+1];
      strcpy(KeyList[KeyCount], KeyName);
      DummyLength = MAX_PATH;
      KeyCount++;
   }

   // Close the key
   RegCloseKey(CurKey);

   // Cycle through all keys; looking for a string valued subkey called
   // 'HardWareKey' which is not NULL, and another subkey called 'Problem'
   // whose fields are all valued 0.
   for (ULONG KeyIndex=0; KeyIndex<KeyCount; KeyIndex++)
   {
      bool HasProblem = false; // Is 'Problem' non-zero? Assume it is Ok

      // Open the key
      strcpy(KeyName, BASE_KEY);
      strcat(KeyName, "\\");
      strcat(KeyName, KeyList[KeyIndex]);
      if (RegOpenKeyEx(
            HKEY_DYN_DATA, KeyName, 0, KEY_PERMISSIONS, &CurKey
                        ) != ERROR_SUCCESS)
         continue;

      // Test for a 0 valued Problem sub-key,
      // which must only consist of raw data
      ULONG DataType, DataSize;
      RegQueryValueEx(CurKey, PROBLEM, NULL, &DataType, NULL, &DataSize);
      if (DataType == REG_BINARY)
      {
         // We have a valid, binary "Problem" sub-key
         // Test to see if the fields are zero

         char HardwareSubKey[MAX_PATH];
               // Data from the "Hardware" sub-key

         UCHAR *Data = new UCHAR[DataSize];
               // Data from "Problem" sub-key

         // Read the data from the "Problem" sub-key
         if (RegQueryValueEx(
                  CurKey, PROBLEM, NULL,
                  NULL, Data, &DataSize
                             ) == ERROR_SUCCESS)
         {
            // See if it has any problems
            for (ULONG index=0; index<DataSize; index++)
               HasProblem |= Data[index];
         }
         else
            HasProblem = true; // No good

         delete[] Data;

         // Now try and read the Hardware sub-key
         DataSize = MAX_PATH;
         RegQueryValueEx(
            CurKey, HARDWARE_KEY, NULL, &DataType, HardwareSubKey, &DataSize
                         );
         if (DataType != REG_SZ)
            HasProblem = true; // No good

         // Do we have no problem, and a non-null Hardware sub-key?
         if (!HasProblem && strlen(HardwareSubKey) > 0)
         {
            // Now open the key which is "pointed at" by HardwareSubKey
            RegCloseKey(CurKey);

            strcpy(KeyName, "Enum\\");
            strcat(KeyName, HardwareSubKey);
            if (RegOpenKeyEx(
                  HKEY_LOCAL_MACHINE, KeyName, 0, KEY_PERMISSIONS, &CurKey
                              ) != ERROR_SUCCESS)
               continue;

            // Now read in the PortName and obtain the LPT number from it
            char PortName[MAX_PATH];
            DataSize = MAX_PATH;
            RegQueryValueEx(
               CurKey, PORTNAME, NULL, &DataType, PortName, &DataSize
                            );
            if (DataType != REG_SZ)
               strcpy(PortName, ""); // No good

            // Make sure it has LPT in it
            if (strstr(PortName, "LPT") != NULL)
            {
               int PortNumber;
                     // The nubmer of the port
               char PortNumberStr[MAX_PATH];
                     // Holds the number of the port as a string

               WORD Allocation[64];
                     // Holds the registry data for the port address allocation

               memset(PortNumberStr, '\0', MAX_PATH);
               strncpy(PortNumberStr,
                       strstr(PortName, "LPT")+3,
                       strlen(PortName)-(strstr(PortName, "LPT")-PortName)-2);

               // Find the port number
               PortNumber = atoi(PortNumberStr);

               // Find the address
               RegCloseKey(CurKey);

               strcpy(KeyName, BASE_KEY);
               strcat(KeyName, "\\");
               strcat(KeyName, KeyList[KeyIndex]);
               RegOpenKeyEx(HKEY_DYN_DATA, KeyName, 0, KEY_PERMISSIONS, &CurKey);

               DataSize = sizeof(Allocation);
               RegQueryValueEx(
                  CurKey, ALLOCATION, NULL, &DataType,
                  (unsigned char*)Allocation, &DataSize
                               );
               if (DataType == REG_BINARY)
               {
                  // Decode the Allocation data: the port address is present
                  // directly after a 0x000C entry (which doesn't have 0x0000
                  // after it).
                  for (int pos=0; pos<63; pos++)
                     if (Allocation[pos] == 0x000C &&
                         Allocation[pos+1] != 0x0000 &&
                         PortNumber<=MAX_LPT_PORTS)
                     {
                        // Found a port; add it to the list
                        FLPTAddress[PortNumber] = Allocation[pos+1];
                        FLPTCount++;
                        break;
                     }

               }

            }

         }
      }

      RegCloseKey(CurKey);
   }

   // Destroy our key list
   for (ULONG index=0; index<KeyCount; index++)
      delete[] KeyList[index];
   delete KeyList;
}
//---------------------------------------------------------------------------
void __fastcall TLdriverX::DetectPortsNT()
{
    const char *BASE_KEY = "HARDWARE\\DEVICEMAP\\PARALLEL PORTS";
   const char *LOADED_KEY = "HARDWARE\\RESOURCEMAP\\LOADED PARALLEL DRIVER RESOURCES\\Parport";
   const char *DOS_DEVICES = "\\DosDevices\\LPT";
   const char *DEVICE_PARALLEL = "\\Device\\Parallel";

   const REGSAM KEY_PERMISSIONS = KEY_ENUMERATE_SUB_KEYS |
                                  KEY_QUERY_VALUE;

   HKEY CurKey;               // Current key when using the registry
   char KeyName[MAX_PATH];    // A key name when using the registry

   char **ValueList;          // List of value names
   ULONG ValueCount;          // Count of the number of value names in ValueList

   // Clear the port count
   FLPTCount = 0;

   // Clear the port array
   for (int index=0; index<MAX_LPT_PORTS; index++)
      FLPTAddress[index] = 0;


   // Open the registry
   if (RegOpenKeyEx(
         HKEY_LOCAL_MACHINE, BASE_KEY, 0, KEY_PERMISSIONS, &CurKey
                     ) != ERROR_SUCCESS)
      return; // Can't do anything without this BASE_KEY

   // Grab all the value names under HKEY_LOCAL_MACHINE
   //
   // Do this by first counting the number of value names,
   // then creating an array big enough to hold them
   // using the ValueList pointer.

   ULONG DummyLength = MAX_PATH;
   ULONG ValueType;
   ValueCount = 0;
   while (RegEnumValue(
            CurKey, ValueCount++, KeyName, &DummyLength,
            NULL, &ValueType, NULL, NULL
                       ) != ERROR_NO_MORE_ITEMS)
   {
      DummyLength = MAX_PATH;
   }

   ValueList = new char*[ValueCount];

   ValueCount = 0;
   DummyLength = MAX_PATH;
   while (RegEnumValue(
            CurKey, ValueCount, KeyName, &DummyLength,
            NULL, &ValueType, NULL, NULL
                       ) != ERROR_NO_MORE_ITEMS)
   {
      ValueList[ValueCount] = new char[DummyLength+1];
      strcpy(ValueList[ValueCount], KeyName);
      DummyLength = MAX_PATH;
      ValueCount++;
   }

   // Close the key
   RegCloseKey(CurKey);

   for (ULONG index=0; index<ValueCount; index++)
   {
      char DosDev[MAX_PATH];    // Key value for \DosDevices\LPT
      ULONG DataType, DataSize; // Type and size of data read from the registry

      // Is it a \DosDevices\LPT key?
      strcpy(KeyName, BASE_KEY);
      if (RegOpenKeyEx(
            HKEY_LOCAL_MACHINE, KeyName, 0, KEY_PERMISSIONS, &CurKey
                        ) == ERROR_SUCCESS)
      {
         DataSize = MAX_PATH;
         RegQueryValueEx(
            CurKey, ValueList[index], NULL, &DataType, DosDev, &DataSize
                         );
         RegCloseKey(CurKey);

         // Make sure it was a string
         if (DataType != REG_SZ)
            strcpy(DosDev, "");
      }
      else
         strcpy(DosDev, "");

      if (strstr(DosDev, DOS_DEVICES) != NULL)
      {
         int PortNumber;                  // The nubmer of the port
         char PortNumberStr[MAX_PATH];    // String version of PortNumber
         char PortIDStr[MAX_PATH];        // PortID

         memset(PortNumberStr, '\0', MAX_PATH);
         strncpy(PortNumberStr,
                 strstr(DosDev, DOS_DEVICES) + strlen(DOS_DEVICES),
                 strlen(DosDev) - (strstr(DosDev, DOS_DEVICES)-DosDev)
                                - strlen(DOS_DEVICES) + 1
                 );

         // Get the Port ID
         memset(PortIDStr, '\0', MAX_PATH);
         strncpy(PortIDStr,
                 strstr(ValueList[index], DEVICE_PARALLEL) + strlen(DEVICE_PARALLEL),
                 strlen(ValueList[index])
                     - (strstr(ValueList[index], DEVICE_PARALLEL)-ValueList[index])
                     - strlen(DEVICE_PARALLEL) + 1
                 );

         // Get the port number
         PortNumber = atoi(PortNumberStr);

         // Get the port address
         RegOpenKeyEx(HKEY_LOCAL_MACHINE, LOADED_KEY, 0, KEY_PERMISSIONS, &CurKey);

         strcpy(DosDev, "\\Device\\ParallelPort");
         strcat(DosDev, PortIDStr);
         strcat(DosDev, ".Raw");

         if (RegQueryValueEx(
               CurKey, DosDev, NULL, &DataType, NULL, NULL
                             ) == ERROR_SUCCESS &&
             DataType == REG_RESOURCE_LIST)
         {
            USHORT Allocation[64]; // Binary data with port number inside

            // Read in the binary data
            DataSize = sizeof(Allocation);
            RegQueryValueEx(
               CurKey, DosDev, NULL, NULL,
               (unsigned char*)Allocation, &DataSize
                            );

            // Found a port; add it to the list
            if (DataSize>0 && PortNumber<MAX_LPT_PORTS)
            {
               FLPTAddress[PortNumber] = Allocation[12];
               FLPTCount++;
            }
         }

         RegCloseKey(CurKey);
      }
   }

   // Destroy our key value list
   // Destroy our key list
   for (ULONG index=0; index<ValueCount; index++)
      delete[] ValueList[index];
   delete ValueList;
}
//---------------------------------------------------------------------------
void __fastcall TLdriverX::DetectPorts2k()
{
   const char *SRV_Key ="SYSTEM\\CurrentControlSet\\Services\\Parport\\Enum";
   const char *ACPI_KEY="SYSTEM\\CurrentControlSet\\Enum";
   const REGSAM KEY_PERMISSIONS = KEY_READ;
   const int BuffBlock=256;
   const int BuffSize=100;

   HKEY CurKey;               // Current key when using the registry
   char KeyName[MAX_PATH];    // A key name when using the registry

  // Clear the port count
   FLPTCount = 0;
   // Open the registry
   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                    SRV_Key,
                    0,
                    KEY_PERMISSIONS,
                    &CurKey) != ERROR_SUCCESS)
      return; // Can't do anything without this BASE_KEY
   unsigned long DataSize=sizeof(unsigned long);
   unsigned long  ValueType;
   ValueType=REG_DWORD;
   if(RegQueryValueEx(CurKey,    // get KeyValueEntry
                      "Count",
                      NULL,
                     &ValueType,
                     &FLPTCount,
                     &DataSize)!= ERROR_SUCCESS) return;

   // GetKEyNames and store it in KeyList
   char* KeyValue;
   char mstring[2];
   char **KeyList= new char*[FLPTCount];
   ValueType=REG_SZ;
   for(int n=0;n<FLPTCount;n++)
   {
      itoa(n,mstring,10);
      KeyValue = new char[BuffSize];
      DataSize=BuffSize;
      if(RegQueryValueEx(CurKey,    // get KeyValueEntry
                        mstring,
                        NULL,
                        &ValueType,
                        KeyValue,
                        &DataSize)!= ERROR_SUCCESS)
      {
       Clean(CurKey,KeyList,n);
       return;
      }
      KeyList[n]=KeyValue;
   }
   RegCloseKey(CurKey);
   // open ACPYKEY
   char Buffer[BuffBlock];
   DataSize=BuffBlock;
   ValueType=REG_RESOURCE_LIST;
   for(int n=0;n<FLPTCount;n++)
   {
    strcpy(KeyName,ACPI_KEY);
    strcat(KeyName,"\\");
    strcat(KeyName,KeyList[n]);
    strcat(KeyName,"\\Control");
    // open each ACPIKEy for each entry in  KeyList
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                      KeyName,
                      0,
                      KEY_PERMISSIONS,
                      &CurKey) != ERROR_SUCCESS)  // Can't do anything without this BASE_KEY
    {
      Clean(CurKey,KeyList,n);
      return;
    }
    // getValue
    if(RegQueryValueEx(CurKey,
                        "AllocConfig",
                        NULL,
                        &ValueType,
                        Buffer,
                        &DataSize)!= ERROR_SUCCESS)
    {
      Clean(CurKey,KeyList,n);
      return;
    }
    FLPTAddress[n+1]=Buffer[24];                // store Value In Buffer
    FLPTAddress[n+1]+=Buffer[25]*256;
    RegCloseKey(CurKey);
   }
   for(int n=0;n<FLPTCount;n++)
     delete []KeyList[n];
   delete  KeyList;
}
//---------------------------------------------------------------------------
void __fastcall TLdriverX::Clean(HKEY OpenKey, char** Buffer, long Count)
{
    RegCloseKey(OpenKey);
    for(int n=0;n<Count;n++)
     delete []Buffer[n];
    delete  Buffer;
}
//---------------------------------------------------------------------------
