共有メモリを使ってみる ACT-2

サンプルスクリプト

さて、実際にスクリプトを書いてみましょう。

各処理の部分に分けて見ていくことにします。

マッピングオブジェクト作成部分

    #include "llmod.as"
    #include "apierr.as"   ; エラーコード取得モジュール

    screen 0, 300, 224
    onexit *lb_quit        ; 終了時にジャンプ

    name = "HSP_mem_Test"  ; ファイルマッピングオブジェクトの名前

    ; ファイルマッピングオブジェクトの作成
    prm.0 = -1             ; 0xFFFFFFFF
    prm.1 = 0              ; NULL
    prm.2 = 4              ; PAGE_READWRITE
    prm.3 = 0
    prm.4 = 1024           ; ファイルマッピングオブジェクトのサイズ
    getptr prm.5, name     ; オブジェクト名のアドレス
    dllproc "CreateFileMappingA", prm, 6, D_KERNEL
    hmapobj = dllret

    ; オブジェクトが作成されていたかどうかの判別
    geterrcode             ; GetLastError関数によるエラーコード取得
    if stat == 183 {       ; ERROR_ALREADY_EXISTS
        goto *lb_exist     ; すでに同じ名前のマッピングオブジェクトが
                           ; 存在する場合
    } else {
        goto *lb_new       ; マッピングオブジェクトが存在しない場合
    }

まずはマッピングオブジェクト作成部分です。

今回はメモリ上にマッピングオブジェクトを作成するためにCreateFileMapping関数の第1引数に0xFFFFFFFF (-1) を指定しています。ここでは共有メモリのサイズを1024バイトにしてあります。

マッピングオブジェクトを識別できるように、固有の名前を作成するオブジェクトにつけます。すでに同じ名前のマッピングオブジェクトがあるかどうかは、CreateFileMapping関数呼び出し直後にGetLastError関数を呼び出して、その戻り値を調べることでわかります。戻り値が183であれば、すでに同じ名前のマッピングオブジェクトが存在していることになります。

今回は、GetLastError関数を呼び出すのに、『Win32 APIのエラー処理』の項で作成したエラーコード取得モジュールapierr.asの中のgeterrcode命令を使用しています。このgeterrcode命令は、GetLastError関数を呼び出して、取得されたエラーコードをstatに格納します。したがって、このapierr.asをインクルードしておく必要があります。

共有メモリが作成されていなかった場合

    ; 新規に共有メモリをセット
*lb_new

    sdim buf, 1024
    mesbox buf, 300, 200, 1
    objsize 100
    button "書き込み", *lb_setmem
    stop

*lb_setmem
    ; ビューのマッピング
    prm.0 = hmapobj         ; マッピングオブジェクトのハンドル
    prm.1 = 2               ; FILE_MAP_WRITE
    prm.2 = 0
    prm.3 = 0
    prm.4 = 0
    dllproc "MapViewOfFile", prm, 5, D_KERNEL
    lpdata = dllret         ; 先頭アドレス

    ll_poke buf, lpdata     ; 共有メモリ領域に文字列をコピー

    prm = lpdata
    dllproc "UnmapViewOfFile", prm, 1, D_KERNEL

    dialog "共有メモリに書き込みました。"
    stop

まだ共有メモリが作成されていなかった場合の処理です。1回目の起動ではこの処理がなされます。HSPのメッセージボックスに文字列を入力して、ボタンを押せば共有メモリにその内容が書き込まれるようにしてあります。

MapViewOfFile関数を実行すると、データ領域の先頭アドレスが返されるので、loadlibメモリアクセス命令ll_pokeを用いてそのアドレスに書き込みます。

ここではマップしてからアンマップするまでの処理を一度に行なっていますが、アンマップのし忘れを防ぐためにも、このようにしたほうがいいでしょう。

共有メモリが作成されていた場合

    ; すでに共有メモリが存在していた場合
*lb_exist

    sdim buf, 1024

    prm.0 = hmapobj         ; マッピングオブジェクトのハンドル
    prm.1 = 4               ; FILE_MAP_READ
    prm.2 = 0
    prm.3 = 0
    prm.4 = 0
    dllproc "MapViewOfFile", prm, 5, D_KERNEL
    lpdata = dllret         ; 先頭アドレス

    ll_peek buf, lpdata     ; 共有メモリ領域から文字列を読み込む

    prm = lpdata
    dllproc "UnmapViewOfFile", prm, 1, D_KERNEL

    mesbox buf, 300, 200, 0
    stop

2回目以降の起動の場合、すなわち、すでに共有メモリが作成されていた場合は、その内容を表示するようにしています。

今回は読み出すことしかしないので、MapViewOfFile関数の第2引数には4 (FILE_MAP_READ) を指定しています。

ここではll_peek命令を使って、データの先頭アドレスから変数に読み込んで、その内容をメッセージボックスで表示しています。

終了時に実行される処理

    ; 終了処理(マッピングオブジェクトのハンドルのクローズ)
*lb_quit
    if hmapobj {
        prm = hmapobj
        dllproc "CloseHandle", prm, 1, D_KERNEL
    }
    end

終了時に実行される処理です。CloseHandle関数を呼び出してマッピングオブジェクトのハンドルをクローズし、オブジェクトの破棄を行ないます。実際にはすべてのプロセスがクローズしない限り、マッピングオブジェクトは破棄されません。