ClasFiltサンプルINFにアンインストール処理を追加する
皆さん、こんにちは。A寿です。
突然ですが、皆さんは乗った船の船頭さんに船から引きずり落とされそうになったことはありますか?・・・このお話にご興味のある方は本文の最後の【閑話休題】までどうぞ。
さて、前回の私の記事では、ClasFiltサンプルINFファイルをご紹介しました。このINFファイルには、お気づきの方もいらっしゃるかと思いますが、INFそのものにはアンインストールの方法は記述されておりません。そこで、今回は、ClasFiltサンプルINFファイルにアンインストール処理を追加する方法をご紹介しようと思います。
追加の手順の概要は以下の通りです。
(1) INFファイルに[DefaultUninstall]セクションを追加
(1-1) DelFilesディレクティブを追加
(1-2) DelRegディレクティブを追加
(2) INFファイルに[DefaultUninstall.Services]セクションを追加
それでは、それぞれの手順についてご説明します。
(1) INFファイルに[DefaultUninstall]セクションを追加
[DefaultUninstall]セクションは、アンインストール時の起点となるセクションです。ここには、[DefaultInstall]セクションの内容を削除する処理を記述します。前回の私の記事のClasFilt.inf(cdrupper.inf)の[DefaultInstall.NT]セクションは、以下のようになっています。
31 [DefaultInstall.NT] 32 ; 33 ; DefaultInstall section is used to install the class filter driver. Use .NT platform extension so this 34 ; section won't be executed on Windows 9x/ME. 35 ; 36 ; Change clasfilt.sys to the name of the class filter driver you need to copy. 37 ; 38 CopyFiles = @cdrupper.sys 39 AddReg = ClassFilter_AddReg |
38行目では、CDROMクラスの上位フィルタであるcdrupper.sysを、CopyFilesディレクティブに指定しています。これにより、下記の通り、27行目に指定されたDefaultDestDirの場所にcdrupper.sysをコピーしています。
23 [DestinationDirs] 24 ; 25 ; Driver to be installed in the drivers subdirectory. 26 ; 27 DefaultDestDir = 12 ; DIRID_DRIVERS |
DefaultDestDirに指定された12は、下記ドキュメントに記載されている通り、%SystemRoot%\system32\driversのディレクトリを表します。
Using Dirids
https://msdn.microsoft.com/en-us/library/ff553598(VS.85).aspx
つまり、%SystemRoot%がC:\Windowsなら、C:\Windows\system32\driversのフォルダにcdrupper.sysをコピーしています。そのため、[DefaultUninstall]セクションでは、このファイルを削除する記述をします。詳細は、「(1-1) DelFilesディレクティブを追加」でご説明します。
続いて、ClasFilt.inf(cdrupper.inf)の39行目では、AddRegディレクティブで、以下の47行目のレジストリの値を追加しています。これは、CDROMクラスの上位フィルタ(UpperFilters)としてclasfiltというサービスを登録するという意味です。
41 [ClassFilter_AddReg] 42 ; 43 ; Change {setup-ClassGUID} to the string form of the ClassGUID that you are installing the filter on. 44 ; 45 ; Change UpperFilters to LowerFilters if this is a lower class filter. 46 ; 47 HKLM, System\CurrentControlSet\Control\Class\{4D36E965-E325-11CE-BFC1-08002BE10318}, UpperFilters, 0x00010008, clasfilt |
0x0001008というフラグは、
INF AddReg Directive
https://msdn.microsoft.com/en-us/library/ff546320(VS.85).aspx
のflagsの項目から、
0x00000008 (FLG_ADDREG_APPEND)
Append a given value to that of an existing named value entry. This flag is valid only if FLG_ADDREG_TYPE_MULTI_SZ is also set.
The specified string value is not appended if it already exists.
と
0x00010000 (FLG_ADDREG_TYPE_MULTI_SZ)
The given value entry and/or value is of the registry type REG_MULTI_SZ. This specification does not require any NULL terminator
for a given string value.
の和になっていることから、cdrupperというマルチ文字列が既存のエントリに追記されることがわかります。そのため、[DefaultUninstall]セクションでは、このレジストリを削除する記述をします。詳細は、「(1-2) DelRegディレクティブを追加」でご説明します。
(1-1) DelFilesディレクティブを追加
[DefaultUninstall]セクションでは、[DefaultInstall]セクションのCopyFilesディレクティブでコピーしたファイルを以下のように記述することで削除します。
DelFiles = clasfilt.DriverFiles |
このclasfilt.DriverFilesは、ファイルリストのセクションとして、別途、以下のように記述します。
[clasfilt.DriverFiles] cdrupper.sys |
(1-2) DelRegディレクティブを追加
[DefaultUninstall]セクションでは、[DefaultInstall]セクションのAddRegディレクティブで追加した値を以下のように記述することで削除します。
DelReg = clasfilt.DelReg |
このclasfilt.DelRegは、削除対象のレジストリリストのセクションとして、別途、以下のように記述します。
[clasfilt.DelReg] HKLM, System\CurrentControlSet\Control\Class\{4D36E965-E325-11CE-BFC1-08002BE10318}, UpperFilters, 0x00018002, clasfilt |
ここで、AddRegで追加した、ClasFilt.inf(cdrupper.inf)の47行目と比較すると、フラグが違うことに気づかれた方もいらっしゃるかと思います。
INF DelReg Directive
https://msdn.microsoft.com/en-us/library/ff547374(VS.85).aspx
のflagsの項目から、
0x00018002 (FLG_DELREG_MULTI_SZ_DELSTRING)
Within a multistring registry entry, delete all strings matching a string value specified by value. Case is ignored.
と定義されていることから、これはマルチ文字列のエントリを削除するためのフラグであることがわかります。
(2) INFファイルに[DefaultUninstall.Services]セクションを追加
続いて、[DefaultUninstall.Services]セクションには、[DefaultInstall.Services]の内容で登録されたサービスを削除する処理を記述します。
前回の私の記事のClasFilt.inf(cdrupper.inf)の[DefaultInstall.NT.Services]セクションは、以下のようになっています。
50 [DefaultInstall.NT.Services] 51 ; 52 ; Services section is required for installation of drivers on NT-based operating systems. 53 ; 54 AddService = clasfilt, , clasfilt_Service_Inst, clasfilt_EventLog_Inst |
54行目は、clasfiltというサービス名で、clasfilt_Service_Instセクションとclasfilt_EventLog_Instセクションの内容を登録するという意味です。
clasfilt_Service_Instセクションは、以下のように、いつ開始するか(StartType)やどのバイナリがサービスの実体か(ServiceBinary)など、サービスを構成する要素を記述しています。
57 [clasfilt_Service_Inst] 58 DisplayName = %cdrupper.SvcDesc% 59 ServiceType = %SERVICE_KERNEL_DRIVER% 60 StartType = %SERVICE_DEMAND_START% 61 ErrorControl = %SERVICE_ERROR_IGNORE% 62 ServiceBinary = %12%\cdrupper.sys ;change clasfilt.sys to the name of your driver binary. |
clasfilt_EventLog_Instセクションは、以下のように、ドライバがイベントログを出力するために必要なレジストリ登録を記載しています。
65 [clasfilt_EventLog_Inst] 66 AddReg = clasfilt_EventLog_AddReg 67 68 69 [clasfilt_EventLog_AddReg] 70 ;Change clasfilt.sys to the name of your driver file. 71 HKR,,EventMessageFile, %REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\cdrupper.sys" 72 HKR,,TypesSupported, %REG_DWORD%, 7 |
AddServiceに関連した内容の詳細は、下記ドキュメントをご参照いただければ幸いです。
INF AddService Directive
https://msdn.microsoft.com/en-us/library/ff546326(VS.85).aspx
[DefaultUninstall.Services]セクションでは、上記のような[DefaultInstall.Services]の内容で登録されたサービスを削除するために、以下の記述を行います。
[DefaultUninstall.Services] DelService = clasfilt,0x200 ;Ensure service is stopped before deleting |
これは、clasfiltというサービス名のサービスを削除しますが、削除の前に、0x200で指定されたフラグに従い、サービスの削除の前にサービスを停止することを表します。このことは以下のドキュメントをご参照ください。
INF DelService Directive
https://msdn.microsoft.com/en-us/library/ff547377(VS.85).aspx
のflagsの説明:
0x00000200 (SPSVCINST_STOPSERVICE)
Stop the service before deleting it.
実際、後述の通り、アンインストールをしてみると、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servicesの下のclasfiltキーが削除されるわけではなく、clasfiltキーのStartエントリが4(=SERVICE_DISABLED)となります。
以上をまとめると、以下のような記述になります。
ClasFilt.inf(cdrupper.inf)の74~88行目に、以下のコードを追加いたしました。
74 ; 75 ; General uninstall Section 76 ; 77 [DefaultUninstall] 78 DelFiles = clasfilt.DriverFiles 79 DelReg = clasfilt.DelReg 80 81 [clasfilt.DriverFiles] 82 cdrupper.sys 83 84 [clasfilt.DelReg] 85 HKLM, System\CurrentControlSet\Control\Class\{4D36E965-E325-11CE-BFC1-08002BE10318}, UpperFilters, 0x00018002, clasfilt 86 87 [DefaultUninstall.Services] 88 DelService = clasfilt,0x200 ;Ensure service is stopped before deleting |
以上で、ClasFiltサンプルINFファイルにアンインストール処理を追加することができました。
続いて、このINFファイルを使って、実際にインストールからアンインストールまでをやってみましょう。
1. インストール
インストールの手順の詳細は、前回のブログの「(5) インストール」と同じです。
テストPCはWindows 7 x86を使用しています。
2. アンインストール
管理者権限でコマンドプロンプトを起動します。
コマンドプロンプト上で、cd C:\testを実行し、C:\testフォルダに移動します。(前回の記事で、C:\testにはcdrupper.sysとcdrupper.infがあります。)
続いて、
rundll32.exe setupapi,InstallHinfSection DefaultUninstall 132 .\cdrupper.inf
を実行し、cdrupper.sysのアンインストールを行います。
補足:
ちなみに、cdrupper.infのインストールは、INFファイルの右クリックだけでなく、上記コマンドのDefaultUninstallをDefaultInstallに変えることでもできます。
Rundll32.exeによるインストール/アンインストールの内容の詳細は、下記ドキュメントをご参照ください。
InstallHinfSection Function
https://msdn.microsoft.com/en-us/library/aa376957(VS.85).aspx
Using an INF File to Uninstall a File System Filter Driver
https://msdn.microsoft.com/en-us/library/ms790741.aspx
3. アンインストールの確認
OSを再起動します。
まずはデバッガを接続しない状態で、以下を確認してみましょう。
・デバイスマネージャの[DVD/CD-ROMドライブ]の下にあるドライブを右クリックしてプロパティを表示。
プロパティの[ドライバー]タブの[ドライバーの詳細]ボタンをクリック。
cdrupper.sysがないことを確認。(下図参照)
・C:\Windows\system32\driversフォルダの下のcdrupper.sysが削除されている。
・レジストリエディタのHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E965-E325-11CE-BFC1-08002BE10318}の、
UpperFiltersのエントリから、「clasfilt」が削除されている。(下図参照)
・レジストリエディタのHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\の下の「clasfilt」のキーが削除されている。(下図参照)
続いて、カーネルデバッガでドライバスタックを確認してみましょう。
デバッガを接続したら、WinDbgのBreakボタンをクリックし、ターゲットPCであるWindows 7の動きを止めます。
!drvobjをサービス名clasfiltに対して実行してみます。すると、以下のように存在しない、という表示になりました。
0: kd> !drvobj clasfilt Driver object clasfilt not found |
それでは、!drvobjをサービス名cdromに対して実行してみます。すると、以下のように表示されました。
0: kd> !drvobj cdrom Driver object (86acd600) is for: \Driver\cdrom Driver Extension List: (id , addr) (84225e7e 8696fe18) Device Object list: 8894b030 |
この一番最後の8桁の数字がcdrom(cdrom.sys)が持つデバイスオブジェクトのアドレスです。
このデバイススタックを!devstackで見てみましょう。
0: kd> !devstack 8894b030 !DevObj !DrvObj !DevExt ObjectName > 8894b030 \Driver\cdrom 8893c6a0 CdRom0 864a9908 \Driver\atapi 864a99c0 IdeDeviceP1T0L0-1 !DevNode 864a6008 : DeviceInst is "IDE\CdRomHL-DT-ST_DVD+-RW_GSA-H31N_______________B109____\5&1a4d1015&0&1.0.0" ServiceName is "cdrom" |
上記のように、CDROMクラスドライバの上位にあったclasfilt(cdrupper.sys)が削除(アンインストール)できたことがわかります。
――――――――――――――――
【閑話休題】皆さんは乗った船の船頭さんに船から引きずり落とされそうになったことはありますか?
先日のゴールデンウィークの話ですが、関西に旅行に行った際に川下りをしてきました。
この川下りは、だいたい20人強くらいのお客さんと、3人の船頭さん(?)が、約2時間ほど、平底の船に乗って、天然の急流すべりのようなスリルが味わえる非常に楽しいものでした。また、船頭さんも2時間しゃべりっぱなしで非常に楽しませてくださる方々でした。坊主で髭剃りあとが濃く、まるでたこ焼きみたいな顔をした(と、船頭さんたちがネタにしていました)船頭さんや、60歳を超えてもムキムキで、ペラペラ喋る口と同じくらいすごいスピードで櫂をこぐことができる船頭さん、岩の間を猛スピードですりぬけながら、方向転換のために岩に空いた小さな穴に絶妙なタイミングで棹を刺して見せ、客の反応が悪いと切れる(もちろんネタです)コワモテの船頭さん、といった感じです。
これらの船頭さんは、船の前方に二人、船の後方に一人という配置なのですが、2時間の船旅の間、時々場所を入れ替わります。その入れ替わる方法は、船が進んでいる間に、船の縁の部分を器用に歩いて交代します。ムキムキな船頭さんとコワモテの船頭さんはベテランだったのですが、問題は、まだかけ出しのたこ焼き顔の船頭さんです。明らかに他の船頭さんとは違ってお客さんの肩にときどき触りながらのおぼつかなげな歩き方でしたが、何とか私の列まで前から歩いてきました。しかし、その時!船が一瞬、波に押し上げられて、ゆれたと思いきや、たこ焼き顔の船頭さんは「うわ! 」と叫び、私の隣の友人の肩をガッ! とつかみました!・・・が、船も船頭さんも体勢を持ち直し、友人だけが川に引きずり落とされそうになりながらも、船べりにしがみついて、なんとか船から落とされることだけは回避しました。皆様も、平底の船で船旅をされる時は、ご注意ください。(でも、この川下りそのものは、この友人含め、皆、本当に楽しめましたのでおススメです。ただ、船頭さんが櫂をこぐ度に、かいた水が、櫂の側の客たちにぴしゃぴしゃかかるので、暖かい時期がおススメです。)