2008/02/07(木)Win32 コンソール向きパイプ通信モジュール
何で今更こんなモノ、とか思わないでもない。
というか、誰か似たようなモノ作ってるんじゃないのかなぁ、
という感は否めないんだけど(笑
しかも、何に使うんだコレ(笑x2
今回は思ってたより時間かかってしまったなぁ。
予想+1時間くらい。コード量も+100行くらい。
なんで、pipe2なのかといえば、hspextのpipeの代替だから。
特にpipeputは呼び出しただけでシステムエラーに^^;
このモジュールはスクリプトに組み込んで自由に使用できます。
/* pipe2.hsp */ // // Win32 コンソール向きパイプ通信モジュール // 月影とも 2008. 2. 7 v0.02 // // パイプを使ったリダイレクトで // 標準入力(STDIN), 標準出力(STDOUT), 標準エラー出力(STDERR) // を操作できるモジュール。以下の命令を定義してます。 // // #deffunc pipe2exec str cmdline // 子プロセスをパイプ付き実行。 // cmdline : 実行するコマンドライン。 // statの値 : 成功時 procid (0以上), 失敗時 -1 // // #deffunc pipe2get int procid, var buf, int size, int offset // #deffunc pipe2err int procid, var buf, int size, int offset // 標準出力/標準エラー出力の(文字列/バイナリ)取得。 // procid : pipe2exec の戻り値 // buf : 内容取得先のバッファ // size : 取得する最大サイズ // offset : バッファの書き込み開始位置 // statの値 : 取得したバイト数 // 備考 : size 以降を省略した場合、必要なサイズを勝手にbufに確保する(内容はクリアされる)。 // 取得内容が文字列とわかっている場合は便利。ただしoffsetの指定は無効。 // // #deffunc pipe2write int procid, var buf, int size, int offset // 標準入力へバイナリ書き込み。 // procid : pipe2exec の戻り値 // buf : 書き込み元のデータが入っているバッファ // size : 書き込むバイト数 // offset : 書き込み元データの開始位置 // statの値 : 実際に書き込めたサイズ // // #deffunc pipe2put int procid, str string // 標準入力へ文字列書き込み。 // procid : pipe2exec の戻り値 // string : 書き込む内容 // statの値 : 実際に書き込めたサイズ // // #deffunc pipe2check int procid // パイプの状況をチェック。 // procid : pipe2exec の戻り値 // statの値 : 以下のビットの組み合わせ。 // if stat & 1 : プログラムは実行中 // if stat & 2 : STDOUTにデータあり(pipe2getで取得) // if stat & 4 : STDERRにデータあり(pipe2errで取得) // // #deffunc pipe2term int procid // 子プロセスの強制終了+パイプを閉じる // procid : pipe2exec の戻り値 // statの値 : 常に 0 // #module mod_execconsole m_hStdOut, m_hStdErr, m_hStdIn, m_hProcess #uselib "kernel32.dll" #func ReadFile "ReadFile" int,int,int,int,nullptr #func WriteFile "WriteFile" int,int,int,int,nullptr #cfunc GetCurrentProcess "GetCurrentProcess" #func CreatePipe "CreatePipe" int,int,int,int #func PeekNamedPipe "PeekNamedPipe" int,nullptr,nullptr,nullptr,int,nullptr #func DuplicateHandle "DuplicateHandle" int,int,int,int, int,int,int #func CloseHandle "CloseHandle" int #cfunc GetLastError "GetLastError" #func CreateProcess "CreateProcessA" int,int,int,int,int,int,int,int,int,int #cfunc WaitForSingleObject "WaitForSingleObject" int,int #func TerminateProcess "TerminateProcess" int,int #defcfunc local _GetModIndex var p1, local hspctx, local vptr mref hspctx, 68 dupptr vptr, hspctx.207, 8, 4 return vptr.1 #modinit return _GetModIndex@mod_execconsole(thismod) #modfunc local _ExecProcessWithPipe str _cmdline ret = 0 thisProcess = GetCurrentProcess() security_attributes = 12, 0, 1 // for STDOUT CreatePipe varptr(hTemp), varptr(hStdout), varptr(security_attributes), 0 DuplicateHandle thisProcess, hTemp, thisProcess, varptr(m_hStdOut), 0, 0, 2 CloseHandle hTemp // for STDERR CreatePipe varptr(hTemp), varptr(hStderr), varptr(security_attributes), 0 DuplicateHandle thisProcess, hTemp, thisProcess, varptr(m_hStdErr), 0, 0, 2 CloseHandle hTemp // for STDIN CreatePipe varptr(hStdin), varptr(hTemp), varptr(security_attributes), 0 DuplicateHandle thisProcess, hTemp, thisProcess, varptr(m_hStdIn), 0, 0, 2 CloseHandle hTemp // CreateProcess dim process_information, 4 dim startupinfo, 17 startupinfo.0 = 68 startupinfo.11 = 0x101 startupinfo.14 = hStdin, hStdout, hStderr cmdline = _cmdline CreateProcess 0, varptr(cmdline), 0, 0, 1, 0, 0, 0, varptr(startupinfo), varptr(process_information) if stat = 0 : ret = -1 : else : m_hProcess = process_information.0 : CloseHandle process_information.1 // CloseHandle CloseHandle hStdOut CloseHandle hStdErr CloseHandle hStdIn return ret #modfunc local _WriteStdin var buf, int size, int offset, local written written = 0 WriteFile m_hStdIn, varptr(buf)+offset, size, varptr(written) if stat=0 : return 0 return written #modfunc local _readPipe int hPipe, var buf, int size, int offset, local read, local readable read = 0 : readable = 0 PeekNamedPipe hPipe, varptr(readable) : if readable = 0 : return 0 if size : sz = size : else : sz = readable : sdim buf, readable+1 ReadFile hPipe, varptr(buf)+offset, sz, varptr(read) if stat=0 : return 0 return read #modfunc local _ReadStdout var buf, int size, int offset _readPipe@mod_execconsole thismod, m_hStdout, buf, size, offset : return #modfunc local _ReadStderr var buf, int size, int offset, local read _readPipe@mod_execconsole thismod, m_hStderr, buf, size, offset : return #modfunc local _GetProcessStatus local status, local readable status = 0 readable = 0 : PeekNamedPipe m_hStderr, varptr(readable) : if readable : status += 4 readable = 0 : PeekNamedPipe m_hStdout, varptr(readable) : if readable : status += 2 if WaitForSingleObject(m_hProcess, 0) : status += 1 return status #modfunc local _Dispose CloseHandle m_hStdout CloseHandle m_hStderr CloseHandle m_hStdin if WaitForSingleObject(m_hProcess, 0) : TerminateProcess m_hProcess return 0 #modterm _Dispose@mod_execconsole thismod return #deffunc pipe2exec str _cmdline newmod children, mod_execconsole : idx = stat _ExecProcessWithPipe@mod_execconsole children.idx, _cmdline if stat != 0 : delmod children.idx : return -1 return idx #deffunc pipe2err int procid, var buf, int size, int offset _ReadStderr@mod_execconsole children.procid, buf, size, offset return #deffunc pipe2get int procid, var buf, int size, int offset _ReadStdout@mod_execconsole children.procid, buf, size, offset return #deffunc pipe2write int procid, var buf, int size, int offset _WriteStdin@mod_execconsole children.procid, buf, size, offset return #deffunc pipe2put int procid, str string buf = string _WriteStdin@mod_execconsole children.procid, buf, strlen(buf) return #deffunc pipe2check int procid _GetProcessStatus@mod_execconsole children.procid return #deffunc pipe2term int procid _Dispose@mod_execconsole children.procid return #global //// モジュ終わり #if 0 // サンプル #define CMDLINE "cmd.exe" pipe2exec CMDLINE : ChildID = stat if stat<0: dialog "実行に失敗:\\n"+CMDLINE : end wait 10 pipe2get ChildID, buf : if stat : mes buf pipe2put ChildID, "dir /w \\\\\\n" pipe2put ChildID, "exit\\n" wait 10 // 子が終了後でも受け取るモノは受け取れます。 pipe2get ChildID, buf : if stat : mes buf pipe2check ChildID : title ""+stat #endif #if 0 // サンプル その2 #define CMDLINE "netstat" pipe2exec CMDLINE : ChildID = stat if stat<0: dialog "実行に失敗:\\n"+CMDLINE : end repeat pipe2check ChildId : c = stat : title ""+c if c & 4 : pipe2err ChildID, buf : if stat : mes buf if c & 2 : pipe2get ChildID, buf : if stat : mes buf if c = 0 : break wait 10 loop mes "終了しました。" #endif