今回から、ファイルのオーバーラップについてやります。ファイルの読み書きに時間がかかる時、これが終了するまで他の作業が できないのでは、困ります。このような場合、オーバーラップを利用するとになります。
これには、win32のAPI関数を利用します。
CreateFile, ReadFile, WriteFile関数については、すでにSDK編で解説があります。
オーバーラップI/Oを行うには、CreateFile関数の第3引数をFILE_SHARE_READ | FILE_SHARE_WRITEにします。
第6引数をFILE_FLAG_OVERLAPPEDにします。
これで、ファイルをオープンします。
関数が失敗すると、INVALID_HANDLE_VALUEが返されます。
他のスレッドや、プロセスが使用中の場合、でもFILE_SHARE_***で読み書きしている場合はエラーになりません。
さて、次にReadFile関数で読み出します。
この時、第5引数にOVERLAPPED構造体へのポインタを指定します。
OVERLAPPED構造体は次のように定義されています。
typedef struct _OVERLAPPED { 
    ULONG_PTR  Internal; 
    ULONG_PTR  InternalHigh; 
    DWORD  Offset; 
    DWORD  OffsetHigh; 
    HANDLE hEvent; 
} OVERLAPPED; 
Internalや、InternalHighは内部的に予約済みです。Offsetには、ReadFileやWriteFile関数のオフセットを指定します。
OffsetHighにはオフセットの上位WORD値を指定します。
hEventには、イベントハンドルを指定します。
ReadFile関数は読み取りが完了する前に制御を返すことがあります。
これにより、ReadFileに時間がかかる場合も、他の仕事をすることができます。
読み取り前に制御が返された時、この関数はFALSEを返します。
すぐに、GetLastError関数を呼び出すと、ERROR_IO_PENDINGが返されます。
WriteFile関数も同様に扱います。
さて、ペンディング中はGetOverlappedResult関数で待ちます。
BOOL GetOverlappedResult( HANDLE hFile, // ファイル、パイプ、通信デバイスのハンドル LPOVERLAPPED lpOverlapped, // オーバーラップ構造体 LPDWORD lpNumberOfBytesTransferred, // 転送されたバイト数 BOOL bWait // 待機オプション );bWaitにTRUEを指定すると、オーバーラップ操作が完了するまで待機します。
では、サンプルを見てみましょう。
/* overlap01.c */
#define MYFILE "c:\\test.txt"
#include <stdio.h>
#include <windows.h>
int main()
{
    HANDLE hFile, hEvent;
    OVERLAPPED ovl;
    BOOL bRet, bLError;
    char szBuf[64];
    DWORD dwWritten;
    strcpy(szBuf, "テスト書き込みです");
    hEvent = CreateEvent(NULL, FALSE, FALSE, "olp");
    hFile = CreateFile(MYFILE, GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("ファイルのオープンに失敗しました\n");
        return -1;
    }
    memset(&ovl, 0, sizeof(OVERLAPPED));
    ovl.hEvent = hEvent;
    bRet = WriteFile(hFile, szBuf, (DWORD)strlen(szBuf), &dwWritten, &ovl);
    if (!bRet) {
        bLError = GetLastError();
        if (bLError == ERROR_IO_PENDING) {
            GetOverlappedResult(hFile, &ovl, &dwWritten, TRUE);
        } else {
            printf("エラーです");
            CloseHandle(hFile);
            CloseHandle(hEvent);
            return -2;
        }
    }
    CloseHandle(hFile);
    CloseHandle(hEvent);
    return 0;
}
Cドライブのルートにtest.txtと言うファイルを用意しておきます。プログラムを実行すると、このファイルに「テスト書き込みです」と書き込まれます。
次回から、もう少し実際的な状態を作ってみます。
Update Dec/06/2004 By Y.Kumei