概要

デバイスドライバのファイル名を指定してデバイスドライバのインストールおよびアンインストールするプログラムです。
デバイスドライバの操作には管理者権限が必要なのでプログラムを実行すると管理者権限を要求します。

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows 7 Enterprise 64bit
Windows 8.1 Enterprise 64bit
Windows XP Professional Service Pack 3 32bit
Windows Vista Ultimate Service Pack 2 32bit
Windows 7 Professional Service Pack 1 32bit

プログラムソースの概要

_tWinMain

ダイアログボックスを表示します。

DlgProc1

ダイアログボックスのプロシージャです。

WM_INITDIALOG

ダイアログボックスの初期化時に呼び出されます。
ドライバパス・ドライバ名のエディットボックスの初期値を設定します。

WM_COMMAND

IDC_LOAD_BUTTON
ドライバロードボタンをクリックしたときに呼び出されます。
ドライバパス・ドライバ名のエディットボックスの文字列を取得し、adddrv関数を呼び出し、ドライバをインストールします。
IDC_UNLOAD_BUTTON
ドライバアンロードボタンをクリックしたときに呼び出されます。
ドライバパス・ドライバ名のエディットボックスの文字列を取得し、deldrv関数を呼び出し、ドライバをアンインストールします。
IDC_REF_BUTTON
ファイル参照ボタンをクリックした場合に呼び出されます。
GetFileName関数を呼び出しドライバファイルのフルパス名を取得します。
フルパス名からフォルダー名を除いたファイル名の先頭位置と拡張子の位置を取得します。
上記で取得した位置から拡張子を除いたファイル名のみを取得します。
フルパス名とファイル名をドライバパス・ドライバ名のエディットボックスに設定します。
IDCANCEL
EndDialogによりダイアログボックスを終了します。

adddrv

ドライバのフルパス名とファイル名よりドライバをインストールします。
一回インストールすると再起動しても有効です。
OpenSCManager APIによりサービスコントロールマネージャーを開きサービスコントロールマネージャーのデータベースのハンドル取得します。
正常に開けない場合は、error_dialog関数によりエラーメッセージを表示して関数を終了します。
OpenService APIによりドライバサービスのハンドルを取得します。
ドライバサービスのハンドルが取得できない場合は、CreateService APIによりドライバサービスを作成しハンドルを取得します。
ドライバサービスの作成に失敗した場合は、error_dialog関数によりエラーメッセージを表示してデータベースのハンドルを閉じて関数を終了します。
StartService APIによりドライバサービスを開始させます。
ドライバサービスの開始に失敗した場合は、error_dialog関数によりエラーメッセージを表示してドライバサービスのハンドルとデータベースのハンドルを閉じて関数を終了します。
ドライバーサービスの開始に成功した場合は、ドライバサービスのハンドルとデータベースのハンドルを閉じて関数を終了します。
以降、他のプログラムからドライバを使用することができます。

deldrv

ドライバのフルパス名とファイル名よりドライバをインストールします。
一回インストールすると再起動しても有効です。
OpenSCManager APIによりサービスコントロールマネージャーを開きサービスコントロールマネージャーのデータベースのハンドル取得します。
正常に開けない場合は、error_dialog関数によりエラーメッセージを表示して関数を終了します。
OpenService APIによりドライバサービスのハンドルを取得します。
ドライバサービスの取得に失敗した場合は、error_dialog関数によりエラーメッセージを表示してデータベースのハンドルを閉じて関数を終了します。
ControlService APIによりドライバサービスを停止させます。
DeleteServiceによりドライバを解放します。
ドライバサービスのハンドルとデータベースのハンドルを閉じて関数を終了します。

GetFileName

GetOpenFileName APIによりファイル名を取得するコモンダイアログボックスを表示しファイル名を取得します。

error_dialog

FormatMessage APIによりエラーコードに対応するエラーメッセージを取得します。
エラーメッセージの文字列バッファは、FormatMessage APIにより動的に確保されます。
MessageBox APIによりエラーメッセージを表示します。
LocalFree APIにより文字列バッファを解放します。

プログラムに管理者権限を要求するようにマニフェストを修正

Visual C++のプロジェクトのプロパティを開き、構成のプロパティの中のリンカ・マニフェストファイルを選びます。
UACの実行レベルをrequireAdministratorに変更します。

ソースコード

drvinst.cpp

#include <windows.h>
#include <tchar.h>
#include "resource.h"

#define DRIVER_PATH _TEXT("C:\\beeptest.sys")
#define DRIVER_NAME _TEXT("beeptest")

// ダイアログボックスプロシージャー
LRESULT CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);

//	ドライバをインストールする
BOOL adddrv(TCHAR* DriverId, TCHAR* DriverPath);

//	ドライバをアンインストールする
BOOL deldrv(TCHAR* DriverId, TCHAR* DriverPath);

// 読込ファイル名の取得
BOOL GetFileName(HWND hWnd, TCHAR* fname, int sz);

//	エラーコードからエラーメッセージを作成しダイアログボックスに表示
void error_dialog(HWND hWnd, int errorcode);

HWND hDlg;

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst, TCHAR* lpszCmdLine, int nCmdShow){
	DialogBox(hInstance, TEXT("DLG1"), 0, (DLGPROC)DlgProc1);
	return 0;
}

 // ダイアログボックスプロシージャー

LRESULT CALLBACK DlgProc1(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
	TCHAR driver_path[MAX_PATH];
	TCHAR driver_name[MAX_PATH];
	TCHAR* top,*bottom;
	switch (msg) {
	case WM_INITDIALOG:
		::hDlg = hDlg;
		SetWindowText(GetDlgItem(hDlg, IDC_PATH_EDIT), DRIVER_PATH);
		SetWindowText(GetDlgItem(hDlg, IDC_NAME_EDIT), DRIVER_NAME);
		return TRUE;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_LOAD_BUTTON:
			GetWindowText(GetDlgItem(hDlg, IDC_PATH_EDIT), driver_path,sizeof(driver_path)/sizeof(TCHAR));
			GetWindowText(GetDlgItem(hDlg, IDC_NAME_EDIT), driver_name, sizeof(driver_name) / sizeof(TCHAR));
			if (adddrv(driver_name, driver_path) == TRUE)
				MessageBox(hDlg, _TEXT("ドライバーがインストールされました"), _TEXT("情報"), MB_OK);
			else
				MessageBox(hDlg, _TEXT("ドライバーがインストールできませんでした"), _TEXT("エラー"), MB_OK);
			return TRUE;
		case IDC_UNLOAD_BUTTON:
			GetWindowText(GetDlgItem(hDlg, IDC_PATH_EDIT), driver_path, sizeof(driver_path) / sizeof(TCHAR));
			GetWindowText(GetDlgItem(hDlg, IDC_NAME_EDIT), driver_name, sizeof(driver_name) / sizeof(TCHAR));
			if(deldrv(driver_name, driver_path)==TRUE)
				MessageBox(hDlg, _TEXT("ドライバーがアンインストールされました"), _TEXT("情報"), MB_OK);
			else
				MessageBox(hDlg, _TEXT("ドライバーをアンインストールできませんでした"), _TEXT("エラー"), MB_OK);
				return TRUE;
		case IDC_REF_BUTTON:
			if (GetFileName(hDlg, driver_path, sizeof(driver_path) / sizeof(TCHAR))){
				top = _tcsrchr(driver_path, _T('\\'));
				bottom = _tcsrchr(driver_path, _T('.'));
				if (_tcscmp(bottom + 1, _TEXT("sys")) == 0){	//	拡張子チェック
					if (top < bottom){
						_tcsncpy_s(driver_name, sizeof(driver_name) / sizeof(TCHAR), top + 1, bottom - top - 1);
					}
				}
				SetWindowText(GetDlgItem(hDlg, IDC_PATH_EDIT), driver_path);
				SetWindowText(GetDlgItem(hDlg, IDC_NAME_EDIT), driver_name);
			}
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg, FALSE);
			return FALSE;
		default:
			return FALSE;
		}
	default:
		return FALSE;
	}
	return TRUE;
}

//	ドライバをインストールする

BOOL adddrv(TCHAR* DriverId, TCHAR* DriverPath){
	SC_HANDLE hSCManager;
	SC_HANDLE hService;

	// サービスコントロールマネージャーを開く
	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCManager == NULL){
		DWORD dwError = GetLastError();
		error_dialog(hDlg, dwError);
		return FALSE;	//	サービスコントロールマネージェーが開けない
	}
	hService = OpenService(hSCManager, DriverId, SERVICE_ALL_ACCESS);
	if (hService == 0){
		//	ドライバサービスを生成
		hService = CreateService(hSCManager, DriverId, DriverId,
			SERVICE_ALL_ACCESS,
			SERVICE_KERNEL_DRIVER,
			SERVICE_DEMAND_START,
			SERVICE_ERROR_NORMAL,
			DriverPath,
			NULL, NULL, NULL, NULL, NULL);
		if (hService == NULL){
			DWORD dwError = GetLastError();
			error_dialog(hDlg, dwError);
			CloseServiceHandle(hSCManager);
			return FALSE;
		}
	}

	if (StartService(hService, 0, NULL) == FALSE){
		DWORD dwError = GetLastError();
		//サービスのインスタンスはすでに動作している以外のエラー
		if (dwError != ERROR_SERVICE_ALREADY_RUNNING){
			error_dialog(hDlg, dwError);
			DeleteService(hService);
			CloseServiceHandle(hService);
			CloseServiceHandle(hSCManager);
			return FALSE;
		}
	}

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);
	return TRUE;
}

//	ドライバをアンインストールする

BOOL deldrv(TCHAR* DriverId, TCHAR* DriverPath){
	SC_HANDLE hSCManager;
	SC_HANDLE	hService;
	// サービスコントロールマネージャーを開く
	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCManager == NULL){
		DWORD dwError = GetLastError();
		error_dialog(hDlg, dwError);
		return FALSE;	//	サービスコントロールマネージェーが開けない
	}
	hService = OpenService(hSCManager, DriverId, SERVICE_ALL_ACCESS);
	if (hService == 0){
		DWORD dwError = GetLastError();
		error_dialog(hDlg, dwError);
		CloseServiceHandle(hSCManager);
		return FALSE;
	}
	SERVICE_STATUS status;
	ControlService(hService, SERVICE_CONTROL_STOP, &status);
	DeleteService(hService);

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);
	return TRUE;
}


// 読込ファイル名の取得

BOOL GetFileName(HWND hWnd,TCHAR* fname, int sz){
	OPENFILENAME o;
	fname[0] = _T('\0');
	ZeroMemory(&o, sizeof(o));
	o.lStructSize = sizeof(o);
	o.hwndOwner = hWnd;
	o.Flags = 0;
	o.lpstrFile = fname;
	o.nMaxFile = sz;
	o.lpstrFilter = _TEXT("SYS(*.SYS)\0");
	o.nFilterIndex = 1;
	return GetOpenFileName(&o);
}

//	エラーコードからエラーメッセージを作成しダイアログボックスに表示

void error_dialog(HWND hWnd, int errorcode){
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, errorcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)&lpMsgBuf, 0, NULL);

	MessageBox(hWnd, (LPCTSTR)lpMsgBuf, _TEXT("エラー"), MB_OK | MB_ICONINFORMATION);
	LocalFree(lpMsgBuf);
}

resource.h

#define	IDC_PATH_EDIT		100
#define	IDC_NAME_EDIT		102
#define	IDC_LOAD_BUTTON		110
#define	IDC_UNLOAD_BUTTON	112
#define IDC_REF_BUTTON		114

resource.rc

#include <windows.h>
#include "resource.h"


DLG1 DIALOG DISCARDABLE 0, 0, 498, 97
EXSTYLE WS_EX_DLGMODALFRAME
STYLE WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_SETFONT
CAPTION "ドライバのロード/アンロード"
FONT 9, "MS 明朝"
{
 CONTROL "ドライバパス", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 7, 81, 12
 CONTROL "", IDC_PATH_EDIT, "EDIT", WS_CHILD | WS_DLGFRAME | WS_VISIBLE | ES_AUTOHSCROLL, 7, 19, 484, 12

 CONTROL "ドライバ名", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 38, 65, 12
 CONTROL "", IDC_NAME_EDIT, "EDIT", WS_CHILD | WS_DLGFRAME | WS_VISIBLE | ES_AUTOHSCROLL, 7, 50, 114, 12

 CONTROL "ドライバロード(&L)", IDC_LOAD_BUTTON, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 7, 76, 103, 14
 CONTROL "ドライバアンロード(&R)", IDC_UNLOAD_BUTTON, "BUTTON", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 120, 76, 128, 14
 CONTROL "ファイル参照(&B)", IDC_REF_BUTTON, "BUTTON", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 255, 76, 96, 14
}
ソースファイルと実行ファイル