コケ。
「ゴーストフォルダの辞書ファイルが更新されたら自動でリロードする」様にしてみたけど、大失敗。まぁ、仕様自体が負け負けってコトで(笑)
まず、フォルダを監視するために 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; |