インストーラーなどを作成していると現在実行中のファイル(例えば自分自身)を削除する必要が出てきます。このようなとき単に DeleteFile
などのAPIを使用してもファイルが使用中なので削除できません。このような場合にはWindowsの再起動時に削除するファイルに登録します。
WindowsNTの場合にはAPI一つ( MoveFileEx
)を呼び出すだけです。
- ::MoveFileEx(lpszFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
MOVEFILE_DELAY_UNTIL_REBOOT
を指定することにより
lpszFileName
の削除は次にWindowsNTを再起動する時に行われます。
Windows95やWindows98の場合には MoveFileEx
がサポートされていないので、WinInit.iniに書き込むことで登録します。WinInit.iniはWindowsディレクトリにあるので GetWindowsDirectory
を使用してWindowsディレクトリを取得します。また、INIファイルへの書き込みには WritePrivateProfileString
を使用します。
- TCHAR szWinInitFile[MAX_PATH];
- ::GetWindowsDirectory(szWinInitFile, countof(szWinInitFile));
- ::lstrcat(szWinInitFile, "\\WinInit.ini");
- ::WritePrivateProfileString("Rename", "Nul", lpszFileName, szWinInitFile);
(98/11/17追記)
と、VCのヘルプには書かれているのですが、どうもうまくいきませんでした。よく考えると WritePrivateProfileString
というAPIを使っていたのでは同じキー名で二つ以上の値を登録できないのでした。要するに、二つ以上のファイルを削除しようとしても後から登録したファイルしか削除されません。また、他のアプリケーションなどで既にNulに値が設定されていたりするとその値を上書きしてしまうことになります。そこで WritePrivateProfileSection
というAPIを使用して次のように書き換えます。
- TCHAR szWinInitFile[MAX_PATH];
- ::GetWindowsDirectory(szWinInitFile, countof(szWinInitFile));
- ::lstrcat(szWinInitFile, "\\WinInit.ini");
- // 95/98でGetPrivateProfileSectionや
- // WritePrivateProfileSectionを使用して読み書きできるサイズは32Kまで
- TCHAR szBuffer[32768];
- // まず最初にセクション全体をバッファーに読込む
- ::GetPrivateProfileSection("Rename", szBuffer, countof(szBuffer), szWinInitFile);
- // セクションの最後を検索
- LPTSTR lpsz = szBuffer;
- while (*lpsz){
- while (*lpsz++)
- ;
- }
- // Nul=[FileName]の形式でバッファーに追加
- lstrcpy(lpsz, "Nul=");
- lstrcat(lpsz, lpszFileName);
- // 終端を書き込む
- while (*lpsz++)
- ;
- *lpsz = '\0';
- // INIファイルへRenameセクションを書き込む
- ::WritePrivateProfileSection("Rename", szBuffer, szWinInitFile);
こうすることによりNulというキー名が複数あった場合にでもINIファイルへ書き込まれます。
(以上 98/11/17追記分)
これだけではまだWinInit.iniには書込まれていません。プログラムが実行中に再起動するとそのまま書込まれずに終了してしまい実際には削除されません。確実に書込むためには
- ::WritePrivateProfileString(NULL, NULL, NULL, szWinInitFile);
も追加しておきましょう
どちらの場合もNULL、Nulの部分でファイル名を指定してやればファイルを移動させることができます。その場合、移動先にファイルがあってはいけないので移動先のファイルを削除しておきます。