C:\MSDOS.SYS の READ ONLY を解除して sample の値を OK が押されるたびに +1 する.
(以下のプログラム)
Win95 上では、+1 されるのですが Win98 上では、全然値が変化しない.
(Win95上でもたまにインクリメントされない場合があるのですがこれも原因不明)
----(1) の行を ----(2) へ移動させると Win98 でも +1 される.
#include
#include
#define fn "C:\\MSDOS.SYS"
#define sc "Options"
#define kn "sample"
int WINAPI WinMain(HINSTANCE hTI,HINSTANCE hPI,LPSTR lpA,int nW)
{
int count = 0;
char buff[20];
do {
SetFileAttributes(fn,GetFileAttributes(fn) & ~FILE_ATTRIBUTE_READONLY);
count = GetPrivateProfileInt(sc, kn, 1, fn);
WritePrivateProfileString(sc, kn, itoa(count + 1, buff, 10), fn);
WritePrivateProfileString(NULL, NULL, NULL, fn); //write back to ini file
// ---------(2)
SetFileAttributes(fn, GetFileAttributes(fn) | FILE_ATTRIBUTE_READONLY);
count=GetPrivateProfileInt(sc, kn, 1, fn); //-------------(1)
} while (MessageBox(NULL, itoa(count, buff, 10), "Increment test", MB_OKCANCEL) == IDOK);
return 0;
}
インクリメントされない現象はWindows95でもかなり頻繁に発生する.
インクリメントされない現象が発生する時は必ず
WritePrivateProfileString(sc, kn, itoa(count + 1, buff, 10), fn);
の戻り値がFALSEになっている.
(しかしGetLastError()しても0が返る)
上記を回避する方法は,
"C:\MSDOS.SYS" の ReadOnly属性を解除したあとに
WritePrivateProfileString(NULL, NULL, NULL, ファイル名);
を実行する.
これで問題は発生しない.
下記は以上のことからの勝手な推測である.
GetPrivateProfile*()にて読み込みを行った場合,指定したファイルの内容が Windows に
よって自動的にキャッシングされる.
そのキャッシングはファイルの内容だけでなく,ファイルの属性もキャッシングさ
れているのではないか?
(1)"C:\MSDOS.SYS" の ReadOnly属性を解除する
(2)GetPrivateProfileInt()にて値を読み、
WritePrivateProfileString()にて+1した値を書く
(3)WritePrivateProfileString(NULL, NULL, NULL, ファイル名)にて
オンメモリのバッファからファイルに書き込ませる
(4)"C:\MSDOS.SYS" に ReadOnly属性をつけて元の状態に戻す
(5)チェックのためもう一度 GetPrivateProfileInt()にて値を読む
上記の処理では,(4)で ReadOnly属性をつけた後 (5)で値を読んでいる.
この(5)の時点で「ReadOnly属性のファイルである」という情報がキャッシングされてしま
うのではないか.
その後(1)に戻って ReadOnly属性を解除しても,キャッシングされているメモリ内の情報は
「ReadOnly属性のファイルの内容」をキャッシングしている状態のままなのでしょう.
(ここが Windowsのバグくさいですが)
そのため(2)での書き込みに失敗してしまう.
この「自動的にキャッシュされる内容」は,Windowsが適当なタイミングで破棄する.
(5)から(2)の直前までの間に運良く破棄されれば,(2)の段階で再度ファイルから読み込み
が行われることになり,この時点で「ReadOnly属性が解除されている」ことを(Windowsが)
認識してくれる.
この場合には (2)での書き込みが成功し,結果的に「成功したり失敗したり」という不安定
な動作となるのでしょう。
そこで回避策として(1)で ReadOnly属性を解除した直後に,
WritePrivateProfileString(NULL, NULL, NULL, ファイル名)を実行する.
これは「未書込のメモリ内の情報をディスクに書かせる」ためではなく,「オンメモリにキャッ
シュされている情報を無効にする」ために行う.
次回のアクセスで必ずファイルから読み込みが行われることになり,ReadOnly属性のファイ
ルであることを正しく認識させることができる.
参照
WriteProfileString