「何か。」のゴースト製作記(10)(2002/02/11)
新着情報 トップメニュー ボードメニュー 掲示板 お手紙はここ!

コケ。

「ゴーストフォルダの辞書ファイルが更新されたら自動でリロードする」様にしてみたけど、大失敗。まぁ、仕様自体が負け負けってコトで(笑)

まず、フォルダを監視するために FindFirstChangeNotification API と WaitForSingleObject API を利用。むろん監視はスレッドを作ってループをまわします。
が、しかし、FindFirstChangeNotification は変更そのものを検出しても、どのファイルが更新されたからとは教えてくれません……。仕方がないのでファイルのリストを作って比べたりしました。

基本的にリロードが目的ならばこれだけで OK なのですが、折角だからイベントで処理しようと決意。DirectSSTP を導入してみます……。
まずは識別子 SAKURA で確保されているマップトファイルを取得。そこからハンドルを抽出して、そこ目掛けてメッセージを投げる。原理は簡単ながら、やったことないので大変でした(^-^;)

リターンを返してもらうためにハンドルが必要です……が、SHIORI は DLL なので当然ながら持っていません。そもそも返信の必要自体あるんかと思ってましたし、デスクトップで良いや……っててんで適当にしてみたら動かないでやんの。よわ。

もちろん、こう言う場合に必要になるハンドルは Classes ユニットの AllocateHWnd() で賄うことができますが、この場合には OS から投げられたメッセージを処理するコールバックを必要とするのですよ……で、この手続きを TWndMethod という型で定義するんですけどコイツが普通の手続きじゃダメだったりします。
結局、DirectSSTP クライアントのためのクラスを作ってこの辺を解決なすった次第。

というわけで、下がその実装です。


(* 識別子'SAKURA'で共有されているマップトファイルを読み込む *)
function TDirectSSTP.GetSakuraFileMappedObject( var Buffer:String ): Boolean;
var
    hMF: THandle;
    Ptr: Pointer;
begin
    hMF := OpenFileMapping( FILE_MAP_READ, False, 'Sakura' );
    
    if (hMF <> 0) then
    begin
        Ptr := MapViewOfFile( hMF, FILE_MAP_READ, 0, 0, 0 );
        
        if (Ptr <> NIL) then
        begin
            Inc( PChar(Ptr), SizeOf(DWORD) );
            Buffer := StringReplace( PChar(Ptr), #1, '=', [rfReplaceAll] );
            UnMapViewOfFile(Ptr);
            
            Result := True;
            
        end else
            Result := False;
        
        CloseHandle( hMF );
            
    end else
        Result := False;
end;

(* ゴースト名からそのゴーストのウィンドウハンドルを抽出する *)
function TDirectSSTP.ExtractSstpServerHandle( GhostName:String ): HWND;
var
    SL : TStringList;
    Wrk: String;
    Idx: Integer;
    H  : Integer;
begin
    Result := 0;

    SL := TStringList.Create;
    try
        if GetSakuraFileMappedObject( Wrk ) then
        begin
            SL.Text := StringReplace( Wrk, #1, '=', [rfReplaceAll] );
            for Idx:=0 to SL.Count-1 do
            begin
                Wrk := SL.Values[SL.Names[Idx]];
                if AnsiSameText( GhostName, Wrk ) then
                begin
                    Wrk := Copy( SL[Idx], 1, 32 );
                    H := StrToIntDef( SL.Values[Wrk+'.hwnd'], -1 );
                    if (H <> -1) then Result := THandle(H);
                        
                    Break;
                end;
                
            end;{ of for}
        end;
        
    finally
        SL.Free;
    end;
end;

(* SSTP サーバーにイベントをリクエストする *)
function TDirectSSTP.RequestEventScript( EventName:String; Reference: array of String ): String;
var
    Wrk: String;
    I  : Integer;
    Len: Integer;
    GMH: HGLOBAL;
    CDS: TCopyDataStruct;
begin
    Wrk := 'NOTIFY SSTP/1.1'         +#13#10
          +'Sender: MP5A5'           +#13#10
          +'Event: '+EventName       +#13#10
          +'SecurityLevel: local'    +#13#10
          +'Charset: Shift_JIS'      +#13#10
          +'HWnd: '+IntToStr(FHandle)+#13#10
          ;
    for I:=0 to High(Reference) do
        Wrk := Wrk + 'Reference' +IntToStr(I) + ': '+ Reference[I] + #13#10;
    Wrk := Wrk + #13#10;

    if (SstpServer = 0) then FSstpServer := ExtractSstpServerHandle( CurrGhost );

    if (SstpServer <> 0) then
    begin
        GMH := GetGlobalMemory( Wrk, Len );
        CDS.dwData := 9801;
        CDS.cbData := Len;        
        CDS.lpData := Pointer(GMH);

        SendMessage( SstpServer, WM_COPYDATA, WParam(FHandle), LParam(@CDS) );
        { ……GMHは本体側で開放しくれますかね? }
    end;
end;




あと、なんとなく SHIORI のイベントを眺めていたら OnKeyPress があったので、意味もなく対応。まだ反応するキーワードは少なめ……。っていうか、打ち間違いに対する処理がまったくなってない(--;) 鍛えなおさんと行かんのですがそんなことは後回しじゃーい(笑)



とか書いてる間に仕様が変わっちゃって、シェルが表示できねぇでやんの(爆死) alias.txt 廃止の動きかぁ〜。まぁ仕方ないす。つーか、変更のペースに完全に追尾して逝けませんが(T-T) どっちかってぇとゴーストそのものの整備よりプログラミングがしたいんdskd……。



マクロ言語の挙動ミスについては打開策が見えてきた気がする。がむしゃらに展開しないで済むようにするにしても、ひとつのメソッドのパラメータが何処から何処までかはっきりしていないので、結局は全部を展開しないと行かんと思っていましたが、単純なフラグ処理で必要でない展開は何もしないでカウンタを進行させる事で良いのではないか?

要するに %ms とかの展開を止めるだけでも思っている動作に近づくわけでありまして。



ある意味では画期的な実験なのですが、alias.txt で SHIORI と MAKOTO を同じファイルで実装しても全然、問題ナッシングでした。ええ。インド人もびっくり。
注意点としては、load() や unload() が何度も呼ばれることになりますんで、フラグを立てるかして同じ処理を重ねないようにしないと行けません。
request() に関してはヘッダが重複したりしないのでそのまま処理を追加するだけでオーケーどす。

これで、DLL 一本で SSTP などの文字列も横取りできるようになったりしちゃいました。統合バルーン計画に一歩。って言うか、まじユニークだと信じて疑わず(笑)



ともかく、まーいーや。とりあえず、とっとと新スクリプト処理は書き上げなければ(^-^;) 今回はバージョンアップはありませんです。マクロスクリプトが崩壊しているので(笑)

つづく。


新着情報 トップメニュー ボードメニュー 掲示板 お手紙はここ!