今天介紹Non-PnP dirver sample中用來安裝及測試驅動程式的windows console app,應用程式主體為testapp.c,相關函式定義在install.c,這個應用程式有安裝及移除驅動程式的流程,下面依序介紹。
在main函式裡首先會嘗試用先前定義的裝置名稱去建立檔案,之後會以檔案的形式去存取裝置。
//
// open the device
//
hDevice = CreateFile(DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
如果開啟失敗,則去讀取錯誤碼,確定是不是檔案未找到或路徑未找到,如果是的話則繼續進行安裝驅動程式的步驟。
errNum = GetLastError();
if (!(errNum == ERROR_FILE_NOT_FOUND ||
errNum == ERROR_PATH_NOT_FOUND)) {
printf("CreateFile failed! ERROR_FILE_NOT_FOUND = %d\n",
errNum);
return ;
}
SetupDriverName
會將Non-PnP驅動程式複製到%windir%\system32\drivers
。
//
// The driver is not started yet so let us install the driver.
// First setup full path to driver name.
//
ok = SetupDriverName( driverLocation, MAX_PATH );
再來進入ManageDriver
。
ok = ManageDriver( DRIVER_NAME,
driverLocation,
DRIVER_FUNC_INSTALL );
由於ManageDriver
傳入的參數是DRIVER_FUNC_INSTALL
,會進行InstallDriver
。
//
// Install the driver service.
//
if (InstallDriver(schSCManager,
DriverName,
ServiceName
)) {
在InstallDriver
內會先開啟Service Control Manager。
//
// Connect to the Service Control Manager and open the Services database.
//
schSCManager = OpenSCManager(NULL, // local machine
NULL, // local database
SC_MANAGER_ALL_ACCESS // access required
);
再來使用上一步開啟的Service Control Manager去建立服務,DriverName
為之前在public.h
定義的名稱。
schService = CreateService(SchSCManager, // handle of service control manager database
DriverName, // address of name of service to start
DriverName, // address of display name
SERVICE_ALL_ACCESS, // type of access to service
SERVICE_KERNEL_DRIVER, // type of service
SERVICE_DEMAND_START, // when to start service
SERVICE_ERROR_NORMAL, // severity if service fails to start
ServiceExe, // address of name of binary file
NULL, // service does not belong to a group
NULL, // no tag requested
NULL, // no dependency names
NULL, // use LocalSystem account
NULL // no password for service account
);
建立服務完成後進入StartDriver
。
//
// Start the driver service (i.e. start the driver).
//
rCode = StartDriver(schSCManager,
DriverName
);
StartDriver
會先開啟服務,也是利用DriverName
去開啟。
//
// Open the handle to the existing service.
//
schService = OpenService(SchSCManager,
DriverName,
SERVICE_ALL_ACCESS
);
最後則是啟動服務讓裝置能讓應用程式使用。
//
// Start the execution of the service (i.e. start the driver).
//
ok = StartService( schService, 0, NULL );
以上安裝驅動程式結束後,就會來到DoIoctls
,此函式為測試驅動程式的主要函式。
DoIoctls(hDevice);
這裡我們以METHOD_BUFFERED
介紹,DeviceIoControl
會對裝置傳入自行定義的IO control code,並傳入InputBuffer
、OutputBuffer
和bytesReturned
,驅動程式的EvtIoDeviceControl
就會依據IO control code對InputBuffer
或OutputBuffer
做對應的動作。
//
// Performing METHOD_BUFFERED
//
if(FAILED(StringCchCopy(InputBuffer, sizeof(InputBuffer),
"this String is from User Application; using METHOD_BUFFERED"))){
return;
}
printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n");
memset(OutputBuffer, 0, sizeof(OutputBuffer));
bRc = DeviceIoControl ( hDevice,
(DWORD) IOCTL_NONPNP_METHOD_BUFFERED,
InputBuffer,
(DWORD) strlen( InputBuffer )+1,
OutputBuffer,
sizeof( OutputBuffer),
&bytesReturned,
NULL
);
在測試完成後就將裝置關閉。
//
// Close the handle to the device before unloading the driver.
//
CloseHandle ( hDevice );
然後接著傳入DRIVER_FUNC_REMOVE
到ManageDriver
移除驅動程式。
//
// Unload the driver. Ignore any errors.
//
ManageDriver( DRIVER_NAME,
driverLocation,
DRIVER_FUNC_REMOVE );
首先停止驅動程式。
//
// Stop the driver.
//
StopDriver(schSCManager,
DriverName
);
先嘗試將服務開啟。
//
// Open the handle to the existing service.
//
schService = OpenService(SchSCManager,
DriverName,
SERVICE_ALL_ACCESS
);
若服務可以開啟就利用ControlService
配合參數SERVICE_CONTROL_STOP
去停止服務。
//
// Request that the service stop.
//
if (ControlService(schService,
SERVICE_CONTROL_STOP,
&serviceStatus
)) {
//
// Indicate success.
//
rCode = TRUE;
}
最後移除驅動程式。
//
// Remove the driver service.
//
RemoveDriver(schSCManager,
DriverName
);
也是先嘗試將服務開啟。
//
// Open the handle to the existing service.
//
schService = OpenService(SchSCManager,
DriverName,
SERVICE_ALL_ACCESS
);
若服務可以開啟則刪除服務。
//
// Mark the service for deletion from the service control manager database.
//
if (DeleteService(schService)) {
//
// Indicate success.
//
rCode = TRUE;
}
以上就是針對Non-PnP測試程式中,安裝及移除Non-PnP驅動程式的流程,這個流程對之後實作動態連結函庫(DLL)非常有幫助。
啟動服務 - Win32 apps | Microsoft Learn