引言裝置驅動程式的動態載入主要是由服務控制管理程式(Service Control Manager,SCM)系統組件完成,SCM組件可以提供許多服務,如,啟動、停止和控制服務。編寫載入驅動程式,主要是操作SCM組件。一般,操作SCM組件的相關API函數有如下幾個:SC_HANDLE WINAPI OpenSCManager(
__in_opt LPCTSTR lpMachineName,//電腦名稱
__in_opt LPCTSTR lpDatabaseName,//SCM資料庫名稱
__in DWORD dwDesiredAccess//使用許可權);
BOOL WINAPI CloseServiceHandle(
__in SC_HANDLE hSCObject //要關閉的SCM控制代碼
);
SC_HANDLE WINAPI CreateService(
__in SC_HANDLE hSCManager, //SCM管理器的控制代碼
__in LPCTSTR lpServiceName, //服務名稱
__in_opt LPCTSTR lpDisplayName, //服務顯示出的名稱
__in DWORD dwDesiredAccess, //開啟許可權
__in DWORD dwServiceType, //服務類型
__in DWORD dwStartType, //開啟服務的時間
__in DWORD dwErrorControl, //關於錯誤處理的代碼
__in_opt LPCTSTR lpBinaryPathName, //二進位檔案的代碼
__in_opt LPCTSTR lpLoadOrderGroup, //用什麼使用者組開發服務
__out_opt LPDWORD lpdwTagId, //輸出驗證標籤
__in_opt LPCTSTR lpDependencies, //所依賴的服務名稱
__in_opt LPCTSTR lpServiceStartName,//使用者賬戶名稱
__in_opt LPCTSTR lpPassword //使用者口令
);
SC_HANDLE WINAPI OpenService(
__in SC_HANDLE hSCManager, //SCM資料庫的控制代碼
__in LPCTSTR lpServiceName, //服務名稱
__in DWORD dwDesiredAccess //存取權限
);
BOOL WINAPI ControlService(
__in SC_HANDLE hService, //服務的控制代碼
__in DWORD dwControl, //控制碼
__out LPSERVICE_STATUS lpServiceStatus//返回狀態代碼
); 檔案拖拽要使對話方塊支援檔案拖拽功能,只需3步即可實現1> 對話方塊模版的 Accept Files 屬性設定成 True
2> 響應主對話方塊類的 WM_DROPFILES 訊息
3> 添加如下範例程式碼:
TCHAR szPath[MAX_PATH] = {0};UINT nCount = DragQueryFile(hDropInfo,0xFFFFFFFF, NULL, 0);//檔案個數for(UINT idx = 0; idx < nCount; ++idx) {DragQueryFile(hDropInfo, idx, szPath, MAX_PATH);TCHAR * pFind = _tcschr((TCHAR *)szPath, '\\');m_strSysFileName=pFind+1;m_strSysFilePath=szPath;}SetDlgItemText(IDC_STATIC_DRIVERPATH,m_strSysFilePath);DragFinish(hDropInfo);CDialog::OnDropFiles(hDropInfo);
其中,
CString m_strSysFileName;//驅動名
CString m_strSysFilePath;//驅動路徑
均為類的私人成員變數
當API函數DragQueryFile的第二個參數設定為:0xFFFFFFFF時,則函數返回拖動檔案的數量
通過DragQueryFile的第三個參數用於儲存擷取的檔案名稱路徑資訊,如:C:\test.sys
為了截取檔案名稱(test.sys),可以函數_tcschr進行字串的截取。
_tcschr函數返回目標字元在指定的字串中出現的地址(包括目標字元),因此為了去掉反斜線'\',需要對返回的結果進行加1。
安裝驅動LoadNtSys函數的作用是安裝驅動,該函數的執行步驟如下:
- 調用OpenSCManager,開啟SCM管理器,如果返回NULL,則返回失敗,否則繼續
- 調用CreateService,建立服務
- 根據CreateService的返回結果,如果返回NULL,則調用GetLastError擷取失敗資訊,否則建立服務成功
//安裝驅動void CLoadSYSDlg::LoadNtSys(){SC_HANDLE schSCManager;//SCM管理器的控制代碼SC_HANDLE schService;//NT驅動程式的服務控制代碼TCHAR szPath[MAX_PATH]={0}; //開啟SCM管理器schSCManager = OpenSCManager(NULL,//電腦名稱 NULL,//SCM資料區塊名稱 SC_MANAGER_ALL_ACCESS);//使用許可權if (NULL==schSCManager){CString str;str.Format(TEXT("OpenSCManager時出錯:(%d)"),GetLastError());MessageBox(str); return;}//建立驅動所對應的服務schService = CreateService(schSCManager,// SCM database m_strSysFileName,// 驅動程式的在註冊表中的名字m_strSysFileName,// 註冊表驅動程式的 DisplayName 值 SERVICE_ALL_ACCESS,// 載入驅動程式的存取權限 SERVICE_KERNEL_DRIVER,// 表示載入的服務是驅動程式 SERVICE_DEMAND_START,// 註冊表驅動程式的 Start 值 SERVICE_ERROR_IGNORE,// 註冊表驅動程式的 ErrorControl 值 m_strSysFilePath,// 註冊表驅動程式的 ImagePath 值 NULL,// no load ordering group NULL,// no tag identifier NULL,// no dependencies NULL,// LocalSystem account NULL);// no password if (!schService){if(ERROR_SERVICE_EXISTS == GetLastError()) //如果服務已經存在{SetDlgItemText(IDC_STATIC_STATE,TEXT("狀態:指定的服務已經存在!"));}else{SetDlgItemText(IDC_STATIC_STATE, TEXT("狀態:CreateService時出錯!")) ;}return;}elseSetDlgItemText(IDC_STATIC_STATE,TEXT("狀態:安裝服務成功!!"));if(schService)CloseServiceHandle(schService) ;if(schSCManager)CloseServiceHandle(schSCManager) ;}
啟動驅動StartNTSys函數的作用是啟動驅動,該函數的執行步驟如下:
- 調用OpenSCManager,開啟SCM管理器,如果返回NULL,則返回失敗,否則繼續
- 調用OpenService,根據服務名和SCM管理器的控制代碼,開啟一個服務。如果返回NULL,則輸出失敗資訊,否則繼續
- 調用StartService,讓指定的服務處於運行狀態
- 退出前,關閉服務控制代碼
//啟動驅動void CLoadSYSDlg::StartNTSys(){SC_HANDLE schSCManager;//SCM管理器的控制代碼SC_HANDLE schService;//NT驅動程式的服務控制代碼//開啟SCM管理器schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (NULL==schSCManager){CString str;str.Format(TEXT("OpenSCManager時出錯:(%d)"),GetLastError());MessageBox(str); return;}schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);if(!schService){DWORD dwErrorCode = GetLastError() ; //擷取錯誤資訊if(ERROR_INVALID_NAME == dwErrorCode){SetDlgItemText(IDC_STATIC_STATE,_T("狀態:服務名無效!"));}else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode){SetDlgItemText(IDC_STATIC_STATE,_T("狀態:不存在此服務!"));}else{ SetDlgItemText(IDC_STATIC_STATE,_T("狀態:OpenService時出錯!"));}CloseServiceHandle(schService); //關閉服務控制代碼schSCManager = NULL ;return;}if (StartService(schService, 0, NULL)){SetDlgItemText(IDC_STATIC_STATE,_T("狀態:驅動服務啟動成功!"));}else{DWORD dwRet = GetLastError();if (ERROR_SERVICE_ALREADY_RUNNING==dwRet)SetDlgItemText(IDC_STATIC_STATE,_T("狀態:指定的服務已經運行!"));elseSetDlgItemText(IDC_STATIC_STATE,_T("狀態:運行指定服務出錯!"));}if(schService)CloseServiceHandle(schService) ;if(schSCManager)CloseServiceHandle(schSCManager) ;}
停止驅動StopNTSys函數的作用是停止驅動,該函數的執行步驟如下:
- 調用OpenSCManager,開啟SCM管理器,如果返回NULL,則返回失敗,否則繼續
- 調用OpenService,根據服務名和SCM管理器的控制代碼,開啟一個服務。如果返回NULL,則輸出失敗資訊,否則繼續
- 調用ControlService對指定的服務發送控制碼
- 關閉服務控制代碼
BOOL WINAPI ControlService(__in SC_HANDLE hService, //服務的控制代碼__in DWORD dwControl, //控制碼__out LPSERVICE_STATUS lpServiceStatus //返回狀態代碼);ControlService函數的作用是對相應的服務,發送控制碼,根據不同的控制碼操作服務,比如:SERVICE_CONTROL_CONTINUE:繼續服務SERVICE_CONTROL_PAUSE:暫停服務SERVICE_CONTROL_STOP:停止服務
//停止驅動void CLoadSYSDlg::StopNTSys(){SC_HANDLE schSCManager;//SCM管理器的控制代碼SC_HANDLE schService;//NT驅動程式的服務控制代碼SERVICE_STATUS status;//開啟SCM管理器schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (NULL==schSCManager){CString str;str.Format(TEXT("OpenSCManager時出錯:(%d)"),GetLastError());MessageBox(str); return;}schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);if(!schService){DWORD dwErrorCode = GetLastError() ; //擷取錯誤資訊if(ERROR_INVALID_NAME == dwErrorCode)SetDlgItemText(IDC_STATIC_STATE,_T("狀態:服務名無效!"));else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode)SetDlgItemText(IDC_STATIC_STATE,_T("狀態:不存在此服務!"));elseSetDlgItemText(IDC_STATIC_STATE,_T("狀態:OpenService時出錯!"));CloseServiceHandle(schService); //關閉服務控制代碼schSCManager = NULL ;return;}if(!ControlService(schService, SERVICE_CONTROL_STOP, &status))//停止服務{DWORD dwRet = GetLastError();if (ERROR_SERVICE_NOT_ACTIVE==dwRet)SetDlgItemText(IDC_STATIC_STATE,_T("狀態:指定的服務並未啟動!"));elseSetDlgItemText(IDC_STATIC_STATE,_T("狀態:不能停止服務!"));}elseSetDlgItemText(IDC_STATIC_STATE,_T("狀態:成功停止服務!")); if(schService)CloseServiceHandle(schService) ;if(schSCManager)CloseServiceHandle(schSCManager) ;}
卸載驅動UnLoadNtSys函數的作用是卸載驅動,該函數的執行步驟如下:
- 調用OpenSCManager,開啟SCM管理器,如果返回NULL,則返回失敗,否則繼續
- 調用OpenService,根據服務名和SCM管理器的控制代碼,開啟一個服務。如果返回NULL,則輸出失敗資訊,否則繼續
- 調用DeleteService卸載指定的服務
- 關閉服務控制代碼
//卸載驅動void CLoadSYSDlg::UnLoadNtSys(){SC_HANDLE schSCManager;//SCM管理器的控制代碼SC_HANDLE schService;//NT驅動程式的服務控制代碼//開啟SCM管理器schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (NULL==schSCManager){CString str;str.Format(TEXT("OpenSCManager時出錯:(%d)"),GetLastError());MessageBox(str); return;}schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);if(!schService){DWORD dwErrorCode = GetLastError() ; //擷取錯誤資訊if(ERROR_INVALID_NAME == dwErrorCode){ SetDlgItemText(IDC_STATIC_STATE,_T("狀態:服務名無效!"));}else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode){SetDlgItemText(IDC_STATIC_STATE,_T("狀態:不存在此服務!"));}else{SetDlgItemText(IDC_STATIC_STATE,_T("狀態:OpenService時出錯!"));}}else{if (!DeleteService(schService))//移除服務SetDlgItemText(IDC_STATIC_STATE,_T("狀態:驅動服務卸載失敗!"));elseSetDlgItemText(IDC_STATIC_STATE,_T("狀態:驅動服務卸載成功!"));} if(schService)CloseServiceHandle(schService) ;if(schSCManager)CloseServiceHandle(schSCManager) ;} 附件
NT式驅動載入器
著作權,歡迎轉載,但轉載請註明:
轉載自 曾是土木人