Re: Еще раз Еще раз Еща много много раз про LPT под NT/XP
От: N_i_t_r_o  
Дата: 30.08.06 12:52
Оценка:
Товарисчи! Помогите!
Вообщем, тема работы с LPT обсуждалась не раз везде где можно.
Я пошел по следующему пути: скачал LPTIO.pas и бинарник lptwdmio.sys, и попытался переложить написанный в дельфи LPTIO.pas на С++, динамически подключив ADVAPI32.DLL. Но возникла проблема с созданием и открытием сервиса. Прошу помощи. Может у кого-нибудь есть готовый класс для работы с LPT на С++... не откажите.
Здесь представлен класс для работы с LPT (*.cpp и ниже *.h), но! не могу понять, как исправить 2 ошибки: 1078 и 1060(!). Они обозначены в коде (ф-я Init()).
// CPP-File
#include <vcl.h>
#include <stdio.h>
#include <Winsvc.h>
#pragma hdrstop

#include <LptPortClass.h>
#pragma package(smart_init)

TLptPort::TLptPort()
{
    hDll = 0;
    UnregisterService = false;

    // Имя символuческой связи
    sprintf(DRV_LINK_NAME, "\\.\LptAccessAgent");

    sprintf(SWC_NAME, "lptwdmio"); //Системное имя сервиса
    sprintf(SWC_DISPLAY_NAME, "LPT port direct access service"); // Название сервиса, чтобы показать пользователю

    IOCTL_READ_PORTS = 0x00220050; // Чтение регистров LPT
    IOCTL_WRITE_PORTS =    0x00220060; // Запись в регистры LPT

    LPT1 = 0x10; // база $3BC
    LPT2 = 0x20; //      $378
    LPT3 = 0x30; //      $278

     // Смещения регистров порта
    LPT_DATA_REG    = 0; // Регистр данных
    LPT_STATE_REG   = 1; // Регистр состояния
    LPT_CONTROL_REG = 2; // Регистр управления
    LPT_EPP_ADDRESS = 3; // Регистр адреса EPP
    LPT_EPP_DATA    = 4; // Регистр данных EPP

    Port = INVALID_HANDLE_VALUE;
    Init();
}
TLptPort::~TLptPort()
{
    Release();
}
//==============================================================================
void TLptPort::Init()
{
    SC_HANDLE    hSCMahager;          // Хэндл менеджера сервисов
    SC_HANDLE   hServiceHandle;     // Хэндл сервиса lptwdmio
    AnsiString SysBinaryName;
    
     // --- Попытка связаться с драйвером ---
    //открываем порт
    Port = CreateFile(DRV_LINK_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    // если ошибка - выходим
    if (Port == INVALID_HANDLE_VALUE)
    {
        // Не удалось связаться с драйвером. Он не был установлен вручную.
        // Windows NT -- пробуем запустить драйвер через менеджер управления сервисами
        hDll = LoadLibrary("ADVAPI32.DLL"); // Получим указатели на ф-и менеджера сервисов.
        if(hDll != 0)
        {
            // Re: чтобы программа работала и на NT, и на 9x, используем динамическую загрузку AdvApi32.dll
            // Получим указатели на ф-и в AdvApi32.dll
            OpenSCManager_      = POpenSCManager(GetProcAddress(hDll, "OpenSCManagerA"));
            CloseServiceHandle_ = PCloseServiceHandle(GetProcAddress(hDll, "CloseServiceHandle"));
            CreateService_      = PCreateService(GetProcAddress(hDll, "CreateServiceA"));
            StartService_       = PStartService (GetProcAddress(hDll, "StartServiceA"));
            OpenService_        = POpenService  (GetProcAddress(hDll, "OpenServiceA"));
            DeleteService_      = PDeleteService(GetProcAddress(hDll, "DeleteService"));

            // Свяжемся с менеджером сервисов
            hSCMahager = OpenSCManager_(NULL, NULL, SC_MANAGER_CREATE_SERVICE /*0xF003F = SC_MANAGER_ALL_ACCESS */);
            if(hSCMahager != 0)
            {
                SysBinaryName = ExtractFilePath(Application->ExeName) + "LPTWDMIO.SYS" ; // имя бинарника sys
                 // Попытка создания сервиса
                SetLastError(0);
                hServiceHandle = CreateService_(hSCMahager,
                                                SWC_NAME,            // имя сервиса
                                                SWC_DISPLAY_NAME,     // отображаемое имя
                                                0xF01FF,               // права доступа  SERVICE_ALL_ACCESS
                                                1,                       // SERVICE_KERNEL_DRIVER
                                                3,                     // SERVICE_DEMAND_START
                                                1,                     // SERVICE_ERROR_NORMAL
                                                SysBinaryName.c_str(),
                                                NULL,
                                                NULL,
                                                NULL,
                                                NULL,
                                                NULL);
                RezLastError = GetLastError(); <<< ERROR! 1078 - Такой сервис уже запущен (хотя это неправда) <<< Почему???
                if (hServiceHandle == 0)
                {// Возможно, сервис был создан ранее
                    SetLastError(0);
                    hServiceHandle = OpenService_(hSCMahager, SWC_NAME, SERVICE_ALL_ACCESS); // откроем его
                    RezLastError = GetLastError(); <<< ERROR! 1060 - ERROR_SERVICE_DOES_NOT_EXIST - The specified service does not exist as an installed service. <<< Почему???????????
                }
                if(hServiceHandle != 0)
                {// ОК, запускаем сервис

                    SetLastError(0);
                    if( !StartService_(hServiceHandle, 0, NULL) ) // Наш драйвер должен загрузиться...
                    {
                        RezLastError = GetLastError();
                    }
                    else
                    {
                        UnregisterService = true;             // При разрушении объекта не забыть пометить сервис для удаления
                        CloseServiceHandle_(hServiceHandle); // Освобождаем хэндл
                    }
                }

                   CloseServiceHandle_(hSCMahager); // Освобождаем хэндл
            }
           }

           // Вторично пытаемся связаться с драйвером
          Port = CreateFile("\\.\LptAccessAgent", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     }

    // Флаги наличия портов
    bool PortPresent[3];
     if( Ready() )
       {
      // Определим порты, представленные в системе
      PortPresent[0] = IsPortPresent(LPT1);
      PortPresent[1] = IsPortPresent(LPT2);
      PortPresent[2] = IsPortPresent(LPT3);
       }                                        //*/
}

void TLptPort::Release()
{
    SC_HANDLE    hSCMahager;          // Хэндл менеджера сервисов
    SC_HANDLE   hServiceHandle;     // Хэндл сервиса lptwdmio
    
    if (Port != INVALID_HANDLE_VALUE) CloseHandle(Port);
    if(UnregisterService)
    {// разрегистрировать сервис
          if(hDll != 0)
        {
               hSCMahager = OpenSCManager_(NULL, NULL, SC_MANAGER_ALL_ACCESS); // Связаться с менеджером сервисов
            if(hSCMahager != 0)
            {
                hServiceHandle = OpenService_(hSCMahager, SWC_NAME, SERVICE_ALL_ACCESS); // Получить хэндл сервиса lptwdmio
                if(hServiceHandle != 0)
                {
                     DeleteService_(hServiceHandle);      // Пометить сервис как подлежащий удалению. Драйвер останется в памяти до ближайшей перезагрузки.
                     CloseServiceHandle_(hServiceHandle); // Освобождаем хэндл
                }
                CloseServiceHandle_(hSCMahager); // Высвободить хэндл менеджера сервисов
               }
              FreeLibrary(hDll); // Высвободить хэндл библиотеки AdvApi32.dll
          }
     }
}

// Возвращает признак готовности/неготовности
bool TLptPort::Ready()
{
    return (Port != INVALID_HANDLE_VALUE ); // Загружен драйвер
}

// Функция для чтения регистров LPT. Возвращает true, если чтение прошло успешно.
bool TLptPort::ReadPorts(ADRDATASTRUCT* PairArray, DWORD PairCount)
{
    DWORD cb;
     ADRDATASTRUCT* Pair;
    DWORD ct;
    WORD adr;

    if( Ready() && (Port != INVALID_HANDLE_VALUE) )
    {// Чтение через драйвер
        cb = 0;
        if( DeviceIoControl( Port, IOCTL_READ_PORTS, PairArray, PairCount*2, PairArray, PairCount*2, &cb, NULL ) ) return true;
        else return false;
    }
      else    return false;
}

// Функция для вывода данных в регистры LPT. Возвращает true, если запись прошла успешно.
bool TLptPort::WritePorts(ADRDATASTRUCT* PairArray, DWORD PairCount)
{
    DWORD cb;
     ADRDATASTRUCT* Pair;
    DWORD ct;
    WORD adr;

    if( Ready() && (Port != INVALID_HANDLE_VALUE) )
    {// Запись через драйвер
        cb = 0;
        if( DeviceIoControl(Port, IOCTL_WRITE_PORTS, PairArray, PairCount*2, PairArray, PairCount*2, &cb, NULL ) ) return true;
        else false;
      }
    return false;
}

// Функция для чтения одного регистра указанного порта
BYTE TLptPort::ReadPort  (BYTE LptNumber, BYTE RegOffset)
{
    ADRDATASTRUCT Pair;
     Pair.Adr = LptNumber;    // or RegOffset;
     Pair.Data = 0;
     ReadPorts(&Pair,1);
     return Pair.Data;
}

// Процедура для вывода значения в регистр порта
BYTE TLptPort::WritePort (BYTE LptNumber, BYTE RegOffset, BYTE Value)
{
    ADRDATASTRUCT Pair;
     Pair.Adr = LptNumber;    // or RegOffset;
     Pair.Data = Value;
     WritePorts(&Pair,1);
    return Pair.Data;
}

// Ф-я тестирования наличия порта. Возвратит true, если порт присутствует.
bool TLptPort::IsPortPresent(BYTE LptNumber)
{
    BYTE data;
    bool present = true;

    data = ReadPort(LptNumber, LPT_DATA_REG); // Сохраняем текущее значение регистра данных
     WritePort(LptNumber,LPT_DATA_REG,0x00); // Пишем 0
    if(ReadPort(LptNumber,LPT_DATA_REG) == 0) // Проверим -- что записали, то и прочитали?
    {
        WritePort(LptNumber,LPT_DATA_REG,0x55); // Пишем 0x55
        if(ReadPort(LptNumber,LPT_DATA_REG) == 0x55)
        {
             WritePort(LptNumber,LPT_DATA_REG,0xAA); // Пишем 0xAA
             if(ReadPort(LptNumber,LPT_DATA_REG) == 0xAA)
            {
                WritePort(LptNumber,LPT_DATA_REG,data); // Восстанавливаем прежнее значение регистра данных
            }
            else present = false;
        }
        else present = false;
    }
    else present = false;
    // Проверим наличие регистров управления и данных, если порт не обнаружен (в случае однонаправленного порта)
    if(!present)
    {
        data = ReadPort(LptNumber,LPT_CONTROL_REG);  // Читаем регистр управления
        if((data != 0x00) && (data != 0xFF)) present = true;    // Не пустое значение? -- порт присутствует
        if(!present)
        {
            data = ReadPort(LptNumber,LPT_STATE_REG);             // Читаем регистр состояния
            if((data != 0x00) && (data != 0xFF)) present = true;
        }
    }
    return present;
}

//---------------------------------------------------------------------------------------------------------------

// H-File
#ifndef LptPortClassH
#define LptPortClassH

struct ADRDATASTRUCT
{
    BYTE Adr;
    BYTE Data;
};

class TLptPort
{
private:
    HANDLE Port;
    HINSTANCE     hDll;
    
    char DRV_LINK_NAME[100];     // Имя символuческой связи

    // Константы для работы с менеджером сервисов
    char         SWC_NAME[100];                 //Системное имя сервиса
    char         SWC_DISPLAY_NAME[100];         // Название сервиса, чтобы показать пользователю

    bool         UnregisterService;           // флаг, показывающий необходимость удаления
    char         ServiceArgVectors[100];      // Вспомогательная переменная для вызова StartService

    // Коды сообщений драйверу
    DWORD         IOCTL_READ_PORTS; // Чтение регистров LPT
    DWORD         IOCTL_WRITE_PORTS; // Запись в регистры LPT

    // Номера портов LPT
    BYTE LPT1; // база $3BC
    BYTE LPT2; //      $378
    BYTE LPT3; //      $278

    // Смещения регистров порта
    BYTE LPT_DATA_REG;         // Регистр данных
    BYTE LPT_STATE_REG;     // Регистр состояния
    BYTE LPT_CONTROL_REG;     // Регистр управления
    BYTE LPT_EPP_ADDRESS;     // Регистр адреса EPP
    BYTE LPT_EPP_DATA;         // Регистр данных EPP

    typedef SC_HANDLE    (*POpenSCManager)        (char* lpMachineName, char* lpDatabaseName, DWORD dwDesiredAccess);
    typedef bool           (*PCloseServiceHandle)    (SC_HANDLE hSCObject);
    typedef SC_HANDLE     (*PCreateService)        (SC_HANDLE hSCManager, char* lpServiceName, char* lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, char* lpBinaryPathName, char* lpLoadOrderGroup, LPDWORD lpdwTagId, char* lpDependencies, char* lpServiceStartName, char* lpPassword);
    typedef bool           (*PStartService)        (SC_HANDLE hService, DWORD dwNumServiceArgs, char* lpServiceArgVectors);
    typedef SC_HANDLE    (*POpenService)            (SC_HANDLE hSCManager, char* lpServiceName, DWORD dwDesiredAccess);
    typedef bool           (*PDeleteService)        (SC_HANDLE hService);

    POpenSCManager        OpenSCManager_;
    PCloseServiceHandle CloseServiceHandle_;
    PCreateService      CreateService_;
    PStartService       StartService_;
    POpenService        OpenService_;
    PDeleteService      DeleteService_;

protected:

  virtual void Init();
  virtual void Release();

public:
  TLptPort();
  ~TLptPort();

      bool Ready();
      bool ReadPorts(ADRDATASTRUCT* PairArray, DWORD PairCount);
      bool WritePorts(ADRDATASTRUCT* PairArray, DWORD PairCount);
      BYTE ReadPort(BYTE LptNumber, BYTE RegOffset);
    BYTE WritePort(BYTE LptNumber, BYTE RegOffset, BYTE Value);
      bool IsPortPresent(BYTE LptNumber);
};
#endif
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.