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ほど使われており正常に開放されていない。
f:id:SuperSecretTech:20180320193040p:plain



以下のマイクロソフトのページを見ると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となった
f:id:SuperSecretTech:20180320193415p:plain