プログラミング工房 > HSP > サンプルスクリプト > 

標準入力をパイプにリダイレクトしてコンソール・アプリケーションを起動し、スクリプト(変数)からテキストデータを流し込む

 以前からコンソール・アプリケーションの標準入力をリダイレクトして起動するテストをしていて、ファイルや他のコンソール・アプリケーションの標準出力からデータを流し込む場合はうまく行くのに、スクリプト(変数)からの場合のみ失敗するのでなぜだろうと思っていたのですが、やっと理由がわかりました。それはデータの末尾にヌル文字を付加しなければならない、というものでした。

 たまたま思いついて試したところうまく行きましたが、このノウハウは自分が探した限りではネットに載っていなかったので、下手をしたらずっと悩み続ける羽目になるところでした。

 スクリプトの細かい内容については、下記のページを参考にして下さい。

2つのコンソール・アプリをパイプでつないで実行
標準出力をファイルにリダイレクトしてコンソール・アプリを実行
標準出力をパイプにリダイレクトしてコンソール・アプリケーションを実行し、その出力を変数で受け取る
コンソールアプリケーションに設定される標準入出力ハンドルのデフォルト値

 また、スクリプトに同梱されているコンソール・アプリケーションの仕様はこちらです。

標準入出力とクリップボードの間でテキストをコピー


 >> サンプルをダウンロード  (実行に必要なファイルはすべてアーカイブに含まれています。)

/*

    【HSP3 サンプルスクリプト】

    標準入力をパイプにリダイレクトしてコンソール・アプリケーション
    を起動し、スクリプト(変数)からテキストデータを流し込む

        【2008/02/28 更新】
        
        【概要】
        
        ・コンソール・アプリケーションに受け渡すデータを読み込む
        ・データを受け渡すための名無しパイプを作成
        ・CreateProcess(A) APIで自分のハンドルを継承させる形でコンソール・アプリケーションを起動
        ・作成しておいたパイプにデータを書き込む
        ・パイプのハンドルを閉じる
        ・スクリプト終了
    
        コンソール・アプリケーションは、リダイレクトされた標準入力から流し込まれたデータを
        クリップボードに出力する機能を持つものを使用する。

        正常に処理が行われれば、クリップボードの内容が指定したデータで書き換えられる。

*/

#include "kernel32.as"

#const  TRUE        1
#const  FALSE       0
#const  NULL        0

#const  SIZE_SEC_ATTR           12          ; SECURITY_ATTRIBUTES構造体サイズ

#const  DUPLICATE_SAME_ACCESS   0x02        ; 第5引数を無視する(DuplicateHandleオプション)

; STARTUPINFO構造体関連
#const  SIZE_SUP_INFO           68          ; STARTUPINFO構造体サイズ
#const  STARTF_USESHOWWINDOW    0x00000001  ; 有効メンバフラグ(wShowWindowメンバを使う)
#const  STARTF_USESTDHANDLES    0x00000100  ; 有効メンバフラグ(標準入出力ハンドルメンバを使う)

#const  SW_HIDE                 0           ; 起動時ウィンドウを表示しない

#const  DEF_HSTDOUT             7           ; コンソール・アプリのデフォルトの標準出力ハンドル
#const  DEF_HSTDERR             11          ; コンソール・アプリのデフォルトの標準エラー出力ハンドル

#define NAME_CONAPP             "cb.exe";"more.com";moreは[Ctrl+C]で終了可;

#const  SIZE_BUF                1024        ; WriteFile用バッファサイズ
#const  ERR_WRITEFILE           0           ; WriteFile APIが失敗した


    /* データ読み込み */
    notesel     data
    noteload    "main.hsp"      ; 例えばこのスクリプトを保存したファイルの名前

    /* 名無しパイプ作成 */
    secattr     = SIZE_SEC_ATTRNULLTRUE     ; SECURITY_ATTRIBUTES構造体
    CreatePipe  varptr(hread), varptr(hwrite), varptr(secattr), 0
    if (stat = FALSE) {
        dialog  "パイプの作成に失敗しました。スクリプトを終了します。"1"エラー"
        end
    }
    ; スクリプトから起動するアプリケーションがパイプの
    ; 書き込み側ハンドルにアクセスできないようにする
    GetCurrentProcess
    hself   = stat
    DuplicateHandle hself, hwrite, hself, NULL0FALSEDUPLICATE_SAME_ACCESS

    /* コンソール・アプリケーションを起動 */
    cmdline     = NAME_CONAPP
    ; STARTUPINFO構造体
    supinfo     = SIZE_SUP_INFO,    NULL,   NULL,   NULL
    supinfo(4)  = 0,                0,      0,      0
    supinfo(8)  = 0,                0,      NULL,   STARTF_USESTDHANDLES; | STARTF_USESHOWWINDOW
    supinfo(12) = SW_HIDE,          0,      hread,  DEF_HSTDOUT,    DEF_HSTDERR
    dim procinfo, 4         ; PROCESS_INFORMATION構造体
    CreateProcessA  NULL, cmdline, NULLNULLTRUE0NULLNULLvarptr(supinfo), varptr(procinfo)
    result  = stat
    CloseHandle hread       ; 読み出し側のパイプハンドルはスクリプトで使用しないので閉じる
    if (result = 0) {
        dialog  (NAME_CONAPP + "の起動に失敗しました。スクリプトを終了します。"), 1"エラー"
        CloseHandle hwrite
        end
    }
    /* コンソール・アプリ関連のハンドルを閉じる(使用しない) */
    CloseHandle procinfo(0)
    CloseHandle procinfo(1)

    /* パイプにWriteFileする回数を取得 */
    len     = strlen(data)
    loopcnt = (len / SIZE_BUF)
    if ((len \ SIZE_BUF) ! 0) {
        loopcnt ++
    }

    /* パイプを通じてデータを送信 */
    idx     = 0                     ; データポインタ
    size    = 0                     ; WriteFile書き込みサイズ
    repeat  loopcnt
        sdim    buf, (SIZE_BUF + 1; WriteFile用バッファ
    
        ; WriteFileするデータを取得
        if (cnt = (loopcnt - 1)) {  ; 最後のループ
            memcpy  buf, data, (len - idx), 0, idx
        }
        else {
            memcpy  buf, data, SIZE_BUF0, idx
            idx     += SIZE_BUF
        }
        ; パイプに書き込む
        WriteFile   hwrite, buf, strlen(buf), varptr(size), NULL
        if (stat = ERR_WRITEFILE) {
            break
        }
        await 1
    loop
    nullchar    = ""
    WriteFile   hwrite, nullchar, 1varptr(size), NULL     ; 空文字を送信

    /* 書き込み側ハンドルを閉じる */
    CloseHandle hwrite

    end