読者です 読者をやめる 読者になる 読者になる

FILE_SHARE_DELETE

CreateFileのFILE_SHARE_DELETEというフラグが前から気になっていたので、チェックしてみることにした。
で、下のようなプログラムを書いてみた。

#include <stdio.h>
#include <windows.h>
#include <shlwapi.h>
#include <tchar.h>

void showError(const char* caption);
#define CHECKERR(CALL) if(CALL) printf( #CALL " - OK\n"); else showError( #CALL );

int main(int argc, TCHAR* argv[])
{
  LPCTSTR fn = _T("test.txt");
  
  HANDLE hFile = CreateFile(
    fn,
    GENERIC_WRITE | GENERIC_READ, // 読み書き可能
    FILE_SHARE_DELETE | FILE_SHARE_READ, // ファイル削除可能・メモ帳で開くのはOK
    NULL, CREATE_NEW,
    FILE_FLAG_DELETE_ON_CLOSE, // いずれにしても終了時に削除
    NULL);
  
  // 書き込んでみる(6バイト)
  DWORD dw;
  CHECKERR(WriteFile(hFile, "foobar", 6, &dw, NULL));
  printf("dw=%u\n", dw);

  // ファイルを消す
  CHECKERR(DeleteFile(fn));
  
  // 存在確認(1) by PathFileExists
  CHECKERR(PathFileExists(fn));
  
  // 存在確認(2) by FindFirstFile
  WIN32_FIND_DATA wfd;
  HANDLE hFind;
  CHECKERR((hFind = FindFirstFile(fn, &wfd)) != INVALID_HANDLE_VALUE);
  
  if(hFind != INVALID_HANDLE_VALUE)
    CloseHandle(hFind);
  
  // 書き込んでみる(6バイト)
  CHECKERR(WriteFile(hFile, "foobar", 6, &dw, NULL));
  printf("dw=%u\n", dw);

  CHECKERR(SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0);

  // 12バイトを読み込んでみる
  BYTE buf[12];
  CHECKERR(ReadFile(hFile, buf, 12, &dw, NULL));
  printf("dw=%u\n", dw);

  // 読める?
  HANDLE hFile2 = CreateFile(
    fn, GENERIC_READ,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    NULL, OPEN_EXISTING, 0, NULL);
  if(hFile2 != INVALID_HANDLE_VALUE)
  {
    printf("open the same file!\n");
    CloseHandle(hFile2);
  }
  else
    showError("cannot open the file");

  // ここで同名のファイルを新規作成できるのか?
  hFile2 = CreateFile(
    fn, GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    NULL, CREATE_NEW, 0, NULL);
  if(hFile2 != INVALID_HANDLE_VALUE)
  {
    printf("create the same file!\n");
    CloseHandle(hFile2);
  }
  else
    showError("cannot create the file");
    
  CloseHandle(hFile); // ここで暗黙のDeleteFile
}

void showError(const char* caption)
{
  DWORD err = GetLastError();
  LPSTR buf = NULL;
  if(FormatMessageA(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, err, LANG_USER_DEFAULT, (LPSTR)&buf, 0, NULL) && buf)
  {
    printf("%s: #%u %s\n", caption, err, buf);
    LocalFree(buf);
  }
}

結果:

WriteFile(hFile, "foobar", 6, &dw, NULL) - OK
dw=6
DeleteFile(fn) - OK
PathFileExists(fn): #5 アクセスが拒否されました。

(hFind = FindFirstFile(fn, &wfd)) != INVALID_HANDLE_VALUE - OK
WriteFile(hFile, "foobar", 6, &dw, NULL) - OK
dw=6
SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0 - OK
ReadFile(hFile, buf, 12, &dw, NULL) - OK
dw=12
cannot open the file: #5 アクセスが拒否されました。

cannot create the file: #5 アクセスが拒否されました。

結論から言えば、消えてない。単にアクセス拒否を食らっているだけだ。UNIXのunlinkのような挙動を期待するのは無理そうだ。しかしながら、結構重要なデータをテンポラリファイルとして書き出さざるを得ない場合など、使えるシチュエーションはあると思われる。