Товарисчи! Помогите!
Вообщем, тема работы с 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