C++程式安裝解除安裝WDM驅動
編譯環境:VS2012 + WIN8 64
測試環境:VM WIN7
測試物件:WDM驅動 (sys檔案 和 inf檔案)
專案型別:Win32 Console Application
其它說明:程式碼來源於網路,經小修改而成,載入驅動方法還有很多(如SetupCopyOEMInf等OEM系列函式),但是逆向EzDriverInstaller驅動載入器,發現和下面程式碼邏輯基本一致,所以最終記錄以下程式碼,以便日後使用。
程式碼如下:
// WinInstallWin.cpp :
//
#include "stdafx.h"
#include <windows.h>
#include <newdev.h>
#include <setupapi.h>
#include <locale.h>
#pragma comment(lib, "newdev.lib")
#pragma comment(lib, "setupapi.lib")
#ifndef MAX_DEVICE_ID_LEN
#define MAX_DEVICE_ID_LEN 200
#define MAX_DEVNODE_ID_LEN MAX_DEVICE_ID_LEN
#define MAX_GUID_STRING_LEN 39 // 38 chars + terminator null
#define MAX_CLASS_NAME_LEN 32
#endif
WORD g_wVender = 0;
WORD g_wHardware = 0;
TCHAR g_strVender[20][64] = {0};
TCHAR g_strHardware[20][64] = {0};
TCHAR g_strHID[MAX_PATH+1] = {0};
//列印錯誤
VOID ShowErrorMsg(DWORD Count,LPCWSTR szData)
{
printf("%d\n%s",&Count,&szData);
}
//過濾字元
VOID FindComma(LPSTR szData)
{
WORD wLen = (WORD)strlen(szData);
WORD wIdx;
WORD wLoop;
CHAR szTmp[128] = {0};
for (wIdx = 0, wLoop = 0; wLoop < wLen; wLoop++)
{
if (szData[wLoop] == ',')
szData[wLoop] = '.';
else if (szData[wLoop] == ' ')
continue;
szTmp[wIdx++] = szData[wLoop];
}
memcpy(szData, szTmp, wIdx*sizeof(char));
szData[wIdx] = 0;
}
//去除字串左邊的空格
VOID StrLTrim(LPSTR szData)
{
LPSTR ptr = szData;
//判斷是否為空格
while (isspace(*ptr))
ptr++;
if (strcmp(ptr, szData))
{
WORD wLen = (WORD)(strlen(szData) - (ptr - szData));
memmove(szData, ptr, (wLen+1)*sizeof(char));
}
}
//去除字串右邊的空格
VOID StrRTrim(LPSTR szData)
{
LPSTR ptr = szData;
LPSTR pTmp = NULL;
//debug模式下 使用isspace判斷中文 需要設定編碼
#if defined(WIN32) && defined(_DEBUG)
char* locale = setlocale( LC_ALL, ".OCP" );
#endif
while (*ptr != 0)
{
//判斷是否為空格
if (isspace(*ptr))
{
if (!pTmp)
pTmp = ptr;
}
else
pTmp = NULL;
ptr++;
}
if (pTmp)
{
*pTmp = 0;
memmove(szData, szData, strlen(szData) - strlen(pTmp));
}
}
//從字串右邊開始擷取字串
VOID StrRight(LPSTR szData, WORD wCount)
{
WORD wLen = (WORD)strlen(szData) - wCount;
if (wCount > 0x7FFF)//負數
wCount = 0;
if (wCount >= (WORD)strlen(szData))
return;
memmove(szData, szData + wLen, wCount * sizeof(char));
szData[wCount] = 0;
}
VOID ConvertGUIDToString(const GUID guid, LPSTR pData)
{
CHAR szData[30] = {0};
CHAR szTmp[3] = {0};
WORD wLoop;
sprintf_s(pData, _countof(szData), "%04X-%02X-%02X-", guid.Data1, guid.Data2, guid.Data3);
for (wLoop = 0; wLoop < 8; wLoop++)
{
if (wLoop == 2)
strcat_s(szData, "-");
sprintf_s(szTmp, _countof(szTmp), "%02X", guid.Data4[wLoop]);
strcat_s(szData, szTmp);
}
memcpy(pData + strlen(pData), szData, strlen(szData));
}
BOOL AnsiToUnicode(LPCSTR Source, const WORD sLen, LPWSTR Destination, const WORD wLen)
{
return MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Source, sLen, Destination, wLen);
}
BOOL UnicodeToAnsi(LPCWSTR Source, const WORD wLen, LPSTR Destination, const WORD sLen)
{
return WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, Source, wLen, Destination, sLen, 0L, 0L);
}
// 初始化全域性變數
__inline VOID InitialGlobalVar()
{
WORD wLoop;
g_wVender = g_wHardware = 0;
for (wLoop = 0; wLoop < 20; wLoop++)
{
RtlZeroMemory(g_strVender[wLoop], sizeof(TCHAR)*64);
RtlZeroMemory(g_strHardware[wLoop], sizeof(TCHAR)*64);
}
}
//安裝驅動功能
__inline BOOL IsInstalled()
{
HDEVINFO hDevInfo = 0L;
SP_DEVINFO_DATA spDevInfoData = {0L};
WORD wIdx;
BOOL bIsFound;
//得到裝置資訊結構的控制程式碼
hDevInfo = SetupDiGetClassDevs(0L, 0, 0, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
return FALSE;
}
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
wIdx = 0;
bIsFound = 0;
while (++wIdx)
{
//找到所有的硬體裝置,並且可以得到所有的硬體裝置的詳細資訊
if (SetupDiEnumDeviceInfo(hDevInfo, wIdx, &spDevInfoData))
{
LPTSTR ptr;
LPBYTE pBuffer = NULL;
DWORD dwData = 0L;
DWORD dwRetVal;
DWORD dwBufSize = 0L;
while (TRUE)
{
//可以在前面得到的指向某一個具體裝置資訊集合的指標中取出某一項資訊
dwRetVal = SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_HARDWAREID,
&dwData, (PBYTE)pBuffer, dwBufSize, &dwBufSize);
if (!dwRetVal)
dwRetVal = GetLastError();
else
break;
if (dwRetVal == ERROR_INVALID_DATA)
break;
else if (dwRetVal == ERROR_INSUFFICIENT_BUFFER)
{
if (pBuffer)
LocalFree(pBuffer);
pBuffer = (LPBYTE)LocalAlloc(LPTR, dwBufSize);
}
else
{
ShowErrorMsg(dwRetVal, _T("SetupDiGetDeviceRegistryProperty"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
return FALSE;
}
}
if (dwRetVal == ERROR_INVALID_DATA)
continue;
for (ptr = (LPTSTR)pBuffer; *ptr && (ptr < (LPTSTR)&pBuffer[dwBufSize]); ptr += _tcslen(ptr) + sizeof(TCHAR))
{
WORD wLoop;
for (wLoop = 0; wLoop < g_wHardware; wLoop++)
{
if (!_tcscmp(g_strHardware[wLoop], ptr))
{
bIsFound = TRUE;
break;
}
}
}
if (pBuffer)
LocalFree(pBuffer);
if (bIsFound)
break;
}
}
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
return bIsFound;
}
//尋找指定的節名 如果找到返回TRUE 反之返回FALSE
BOOL FindSectionName(FILE *pFile, const char *szKey)
{
char szData[256] = {0};
if (!pFile)
return FALSE;
//將檔案內部的位置指標重新指向一個流(資料流/檔案)的開頭
rewind(pFile);
//迴圈讀取檔案內容
while (!feof(pFile))
{
//讀取一行
fgets(szData, 255, pFile);
//去除前後空格
StrLTrim(szData);
StrRTrim(szData);
if (strcmp(szKey, szData) == 0)
return TRUE;
}
return FALSE;
}
//得到INF檔案中節的數量
__inline BOOL GetSectionData(FILE* pFile, const char* szKey, const char bIsVender)
{
char szData[128] = {0};
if (bIsVender)
strcpy_s(szData, szKey);
else
sprintf_s(szData, _countof(szData), "[%s]", szKey);
if (FindSectionName(pFile, szData) == FALSE)
return FALSE;
RtlZeroMemory(szData, sizeof(char)*128);
while (!feof(pFile))
{
char *str = NULL;
fgets(szData, 127, pFile);
szData[strlen(szData)-1] = 0;
StrLTrim(szData);
StrRTrim(szData);
if (!*szData)
continue;
if (szData[0] == ';')
continue;
if (strchr(szData, '['))
{
StrLTrim(szData);
if (szData[0] != ';')
return 1;
else
continue;
}
if (bIsVender)
str = strchr(szData, '=');
else
str = strchr(szData, ',');
if (*str)
{
char szTmp[128] = {0};
WORD pos = (WORD)(str - szData + 1);
StrRight(szData, (short)(strlen(szData)-pos));
StrLTrim(szData);
StrRTrim(szData);
FindComma(szData);
if (bIsVender)
{
AnsiToUnicode(szData, strlen(szData), g_strVender[g_wVender++], 64);
}
else
{
AnsiToUnicode(szData, strlen(szData), g_strHardware[g_wHardware++], 64);
}
}/* end if */
}
return TRUE;
}
//得到INF檔案相關資料
BOOL GetINFData(FILE *pFile)
{
WORD wLoop;
if (!g_wVender || !g_wHardware)
InitialGlobalVar();
if (GetSectionData(pFile, "[Manufacturer]", TRUE) == FALSE)
return 0;
for (wLoop = 0; wLoop < g_wVender; wLoop++)
{
CHAR szVender[64] = {0};
UnicodeToAnsi(g_strVender[wLoop], _tcslen(g_strVender[wLoop]), szVender, 64);
GetSectionData(pFile, szVender, FALSE);
}
if (g_wHardware != 0)
{
if (IsInstalled() == TRUE)//如果已經安裝
return FALSE;
else
return TRUE;
}
return FALSE;
}
//實質性的安裝驅動
__inline BOOL InstallClassDriver(LPCTSTR theINFName)
{
GUID guid = {0};
SP_DEVINFO_DATA spDevData = {0};
HDEVINFO hDevInfo = 0L;
TCHAR className[MAX_CLASS_NAME_LEN] = {0};
LPTSTR pHID = NULL;
WORD wLoop;
BOOL bRebootRequired;
//取得此驅動的GUID值
if (!SetupDiGetINFClass(theINFName, &guid, className, MAX_CLASS_NAME_LEN, 0))
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetINFClass"));
return FALSE;
}
//建立裝置資訊塊列表
hDevInfo = SetupDiCreateDeviceInfoList(&guid, 0);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
ShowErrorMsg(GetLastError(), _T("SetupDiCreateDeviceInfoList"));
return FALSE;
}
spDevData.cbSize = sizeof(SP_DEVINFO_DATA);
//建立裝置資訊塊
if (!SetupDiCreateDeviceInfo(hDevInfo, className, &guid, 0L, 0L, DICD_GENERATE_ID, &spDevData))
{
ShowErrorMsg(GetLastError(), _T("SetupDiCreateDeviceInfo"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
return FALSE;
}
for (wLoop = 0; wLoop < g_wHardware; wLoop++)
{
if (pHID)
LocalFree(pHID);
pHID = (LPTSTR)LocalAlloc(LPTR, _tcslen(g_strHardware[wLoop])*2*sizeof(TCHAR));
if (!pHID)
{
ShowErrorMsg(GetLastError(), _T("LocalAlloc"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
return FALSE;
}
_tcscpy_s(pHID, _tcslen(g_strHardware[wLoop])*2, g_strHardware[wLoop]);
//設定硬體ID
if (!SetupDiSetDeviceRegistryProperty(hDevInfo, &spDevData, SPDRP_HARDWAREID, (PBYTE)pHID,
(DWORD)(_tcslen(g_strHardware[wLoop])*2*sizeof(TCHAR))))
{
ShowErrorMsg(GetLastError(), _T("SetupDiSetDeviceRegistryProperty"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
LocalFree(pHID);
return FALSE;
}
//呼叫相應的類程式來註冊裝置
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &spDevData))
{
ShowErrorMsg(GetLastError(), _T("SetupDiCallClassInstaller"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
LocalFree(pHID);
return FALSE;
}
bRebootRequired = FALSE;
//安裝更新和硬體ID相匹配的驅動程式
if (!UpdateDriverForPlugAndPlayDevices(0L, g_strHardware[wLoop], theINFName,
INSTALLFLAG_FORCE, &bRebootRequired))
{
DWORD dwErrorCode = GetLastError();
//呼叫相應的類程式來移除裝置
if (!SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, &spDevData))
ShowErrorMsg(GetLastError(), _T("SetupDiCallClassInstaller(Remove)"));
ShowErrorMsg((WORD)dwErrorCode, _T("UpdateDriverForPlugAndPlayDevices"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
LocalFree(pHID);
return FALSE;
}
LocalFree(pHID);
pHID = NULL;
}
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
_tprintf(_T("Install Successed\n"));
return TRUE;
}
// 安裝WDM驅動的測試工作
BOOL StartInstallWDMDriver(LPCTSTR theInfName)
{
HDEVINFO hDevInfo = 0L;
GUID guid = {0L};
SP_DEVINSTALL_PARAMS spDevInst = {0L};
TCHAR strClass[MAX_CLASS_NAME_LEN] = {0L};
//取得此驅動的GUID值
if (!SetupDiGetINFClass(theInfName, &guid, strClass, MAX_CLASS_NAME_LEN, 0))
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetINFClass"));
return FALSE;
}
//得到裝置資訊結構的控制程式碼
hDevInfo = SetupDiGetClassDevs(&guid, 0L, 0L, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_PROFILE);
if (!hDevInfo)
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
return FALSE;
}
spDevInst.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
//獲得指定裝置的安裝資訊
if (!SetupDiGetDeviceInstallParams(hDevInfo, 0L, &spDevInst))
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetDeviceInstallParams"));
return FALSE;
}
spDevInst.Flags = DI_ENUMSINGLEINF;
spDevInst.FlagsEx = DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
_tcscpy_s(spDevInst.DriverPath, _countof(spDevInst.DriverPath), theInfName);
//為裝置資訊集或者是一個實際的裝置資訊單元設定或清除類安裝引數
if (!SetupDiSetDeviceInstallParams(hDevInfo, 0, &spDevInst))
{
ShowErrorMsg(GetLastError(), _T("SetupDiSetDeviceInstallParams"));
return FALSE;
}
//獲取這個裝置的驅動程式資訊列表
if (!SetupDiBuildDriverInfoList(hDevInfo, 0, SPDIT_CLASSDRIVER))
{
ShowErrorMsg(GetLastError(), _T("SetupDiDeviceInstallParams"));
return FALSE;
}
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
//進入安裝裝置驅動函式
return InstallClassDriver(theInfName);
}
// 解除安裝WDM驅動
VOID UninstallWDMDriver(LPCTSTR theHardware)
{
SP_DEVINFO_DATA spDevInfoData = {0};
HDEVINFO hDevInfo = 0L;
WORD wIdx, wCount = 0;
//得到裝置資訊結構的控制程式碼
hDevInfo = SetupDiGetClassDevs(0L, 0L, 0L, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
ShowErrorMsg(GetLastError(), _T("SetupDiGetClassDevs"));
return;
}
wIdx = 0;
while (TRUE)
{
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
//找到所有的硬體裝置,並且可以得到所有的硬體裝置的詳細資訊
if (SetupDiEnumDeviceInfo(hDevInfo, wIdx, &spDevInfoData))
{
char Buffer[2048] = {0};
//可以在前面得到的指向某一個具體裝置資訊集合的指標中取出某一項資訊
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_HARDWAREID,
0L, (PBYTE)Buffer, 2048, 0L))
{
if (!_tcscmp(theHardware, (LPTSTR)Buffer))
{
//從系統中刪除一個註冊的裝置介面
if (!SetupDiRemoveDevice(hDevInfo, &spDevInfoData))
ShowErrorMsg(GetLastError(), _T("SetupDiRemoveDevice"));
wCount++;
}
}
}
else
break;
wIdx++;
}
if (wCount != 0)
_tprintf(_T("UnInstall Successed\n"));
//銷燬一個裝置資訊集合
SetupDiDestroyDeviceInfoList(hDevInfo);
InitialGlobalVar();
return;
}
//INF檔案路徑
const LPTSTR g_pInfPath = _T("C:\\Windows\\System32\\DriverStore\\FileRepository\\mydriver1.inf_x86_neutral_15204d1ef3d409a0\\mydriver1.inf");
//入口函式
int _tmain(int argc, _TCHAR* argv[])
{
CHAR szInfPath[MAX_PATH] = {0};
UnicodeToAnsi(g_pInfPath, _tcslen(g_pInfPath), szInfPath, MAX_PATH);
FILE* pInf;
errno_t err;
if ((err=fopen_s(&pInf, szInfPath, "r"))!=0)
{
_tprintf(_T("can not open file %s\n"), g_pInfPath);
return 0;
}
// 獲取INF檔案資料
GetINFData(pInf);
fclose(pInf);
// 安裝WDM驅動
if(_tcscmp(argv[1], TEXT("-Install"))==0)
{
if (StartInstallWDMDriver(g_pInfPath) == FALSE)
{
_tprintf(_T("Start Install WMD Driver failed\n"));
return 0;
}
}
// 解除安裝WDM驅動
else if(_tcscmp(argv[1], TEXT("-UnInstall"))==0)
{
for (WORD wLoop = 0; wLoop < g_wHardware; wLoop++)
UninstallWDMDriver(g_strHardware[wLoop]);
}
return 1;
}
具體的SYS 和 INF檔案 可參考:http://blog.csdn.net/whatday/article/details/9384577
測試結果:
把相應EXE及其SYS INF檔案拷貝的WIN7虛擬機器,開啟CMD執行WinInstallWin.exe -Install 顯示安裝成功如圖:
再用DeviceTree檢視結果:
可以看到裝置已經新增成功
在CMD中執行 WinInstallWin.exe -UnInstall 顯示解除安裝成功 如圖:
再次使用DeviceTree檢視裝置 需要重新整理一下DeviceTree 結果如圖:
先前的裝置已經解除安裝掉了,到此WDM驅動的安裝解除安裝就全部結束了。
相關文章
- WDM驅動程式設計之編譯安裝篇 (轉)程式設計編譯
- 在Linux中,什麼是裝置驅動程式?如何安裝和解除安裝裝置驅動程式?Linux
- Ubuntu Nvidia driver驅動安裝及解除安裝Ubuntu
- Mac怎麼解除安裝印表機驅動程式Mac
- 活用WinXP安全模式解除安裝驅動程式(轉)模式
- 如何把印表機驅動解除安裝乾淨 印表機驅動解除安裝乾淨的教程
- Ubuntu18.04安裝/解除安裝NVIDIA顯示卡驅動Ubuntu
- win10驅動解除安裝不了怎麼辦_win10驅動解除安裝不掉如何解決Win10
- win10怎麼解除安裝印表機驅動 win10解除安裝印表機驅動的方法Win10
- 印表機驅動怎麼解除安裝刪除 win10印表機驅動解除安裝不乾淨Win10
- win10如何強制解除安裝驅動精靈_win10解除安裝驅動精靈的方法Win10
- win10解除安裝顯示卡驅動怎麼重灌 win10顯示卡驅動解除安裝重灌操作方法Win10
- Thinkpad 驅動安裝-傻瓜安裝ThinkPad
- docker安裝及解除安裝Docker
- Ubuntu解除安裝和安裝Ubuntu
- Oracle 安裝與解除安裝Oracle
- solaris mysql 安裝 解除安裝MySql
- JDK安裝和解除安裝JDK
- android 程式碼安裝和解除安裝apkAndroidAPK
- win10怎麼解除安裝音效卡驅動_win10徹底解除安裝音效卡驅動的步驟Win10
- 如何安裝印表機驅動 印表機驅動安裝步驟
- 安裝npm 解除安裝npm 安裝apidocNPMAPI
- 電腦怎麼安裝印表機驅動程式 電腦印表機安裝驅動教程
- WindowsService服務程式開發 安裝和解除安裝Windows
- cocoapods安裝/解除安裝/使用
- Mac Redis安裝與解除安裝MacRedis
- Ubuntu安裝和解除安裝mongodbUbuntuMongoDB
- [雲原生]Docker - 安裝&解除安裝Docker
- JDK的安裝與解除安裝JDK
- ORACLE TEXT安裝與解除安裝Oracle
- Linux安裝解除安裝MySQLLinuxMySql
- 電腦驅動程式的安裝方法
- oracle & mysql 驅動程式安裝配置OracleMySql
- mysql安裝------RPM包安裝及解除安裝MySql
- 安裝postgresql odbc驅動SQL
- win10系統驅動精靈解除安裝不了怎麼辦_win10驅動精靈解除安裝不了如何解決Win10
- window下安裝並使用nvm(含解除安裝node、解除安裝nvm、全域性安裝npm)NPM
- Solaris 下解除安裝程式 pkgrm