OpenFile()という化石API
需要はないと思うけど、OpenFile()という化石APIについて気づいたこと。
OpenFile()を下記みたいな使い方をするとヒープにゴミが残る。
以下のコードはOpenFile(path, &of, OF_EXIST) を使ってファイルが存在するかどうかチェックしている。OpenFile(path, &of, OF_EXIST) が成功すると「file handle」を返し、失敗すると「HFILE_ERROR」を返す。ヒープにゴミが残らないようにCloseHandle()でファイルハンドルを閉じてしまいたいのだが、当然ファイルハンドルの実体は存在しないので無理に閉じようとするとメモリーアロケーションエラーになる。
OpenFile()のバグかと思い、VisualStudio6.0sp6とVisualStudio2017を使って検証してみたら両方とも同じ結果でヒープにゴミが残ってしまう。
int CheckFile(LPCSTR pszFile) { OFSTRUCT buf; HFILE hFile = 0; for (int i=0; i<100; i++) { hFile = OpenFile(pszFile, &buf, OF_EXIST); if (hFile == HFILE_ERROR) return -1; //CloseHandle((HANDLE)hFile); // ここでメモリーアロケーションエラーになる。 // OF_EXISTではファイルハンドルを握らないからCloseHandle()は不要か? // しかしCloseHandle()しないとヒープは増えていく一方なので } return 0; }
ゴミは↓こんな感じ。ヒープが関数終了後も3.07KBほど使われており正常に開放されていない。
以下のマイクロソフトのページを見るとOpenFile()は互換性のために残してあるAPIなので使うなと記載されていたので、現代APIに置き換えてゴミが残ることがなくりました。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa365430(v=vs.85).aspx
bool CheckFile(LPCSTR pszFile) { HANDLE hFind; WIN32_FIND_DATA FindFileData; hFind = ::FindFirstFile((LPCWSTR)pszFile, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) return false; ::FindClose(hFind); if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return false; //同名のフォルダがある(ファイルではない) return true; }
この通り、綺麗にヒープが0KBとなった