入力を受け取り、ビジネスを継続する前に前処理を行う小さなプログラムがあります。(「プログラムを作成します。正確なデータ形式はまだわかりません。」という典型的なケースです。) このステップをよりスクリプト化できるようにするために、前処理ステップに AWK を使用することにしました (データが本質的に表形式)。
背景は十分です。つまり、 CreateProcessで GAWK を呼び出そうとしています。
- 私の GAWK は UTF-8 を想定していると確信しています (つまり、Windows の "Unicode"/UTF-16 は想定していません)。
- これは GnuWin32-AWK であるため、ウィンドウ スタイルのパスを認識している必要があります。
- また、通信に使用される匿名パイプが正しく設定されていることもかなり確信しています。正しく動作する test.bat スクリプトを作成しました。また、コマンド ラインに型がある場合、入力パイプ (子出力) から AWK エラー メッセージを読み取ることができます。
- 取得できた唯一の出力は 0A 0D、つまり \n\r でした。
- コマンド ラインに問題がない場合は、
WaitForSingleObject()
デッドロックを示すエラー 259 が返されます。
EDIT 1 : これは関数の簡易版です。私は今のところメインループを維持しています。どちらの場合も、ループ内で 2 回転します。
wstring path = L"C:\\MODBUSSINATOR\\awk\\awk.exe";
wstring args = L"C:\\MODBUSSINATOR\\awk\\awk.exe --file=.\\awk\\recipe.awk";
string source = "PERSE PERSE PERSE";
wchar_t argbuff[args.size()+1]; // MSDN says the arg-buff may be modified by client
wcscpy(argbuff,args.c_str()); // so copy args into array
istringstream inpus(source);
ostringstream resus;
DWORD written=0,retcode=0,read=0,readable=0,inpusize=0,resusize=0;
char inpu_buff[1024],resu[1024],*inpu;
SECURITY_ATTRIBUTES cia = {sizeof(SECURITY_ATTRIBUTES),nullptr,true}, coa = cia;
HANDLE oh,ih,cih,coh;
if(!CreatePipe(&cih,&oh,&cia,BUFF_SZ)) //BUFF_SZ = 1024
abort();
if(!CreatePipe(&ih,&coh,&cia,BUFF_SZ))
abort();
PROCESS_INFORMATION procinfo;
STARTUPINFO startinfo;
memset(&procinfo,0,sizeof(PROCESS_INFORMATION)); // The documentation says to do this.
memset(&startinfo,0,sizeof(STARTUPINFO)); // Though I set all the fields exclusively.
startinfo = {
sizeof(STARTUPINFO),nullptr,nullptr,nullptr,0,0,0,0,0,0,0,
STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,SW_HIDE,0,nullptr,
cih,coh,coh
};
if(!CreateProcess(
path.c_str(),argbuff,nullptr,nullptr,true, 0 // true, handles are inherited
,nullptr,nullptr,&startinfo,&procinfo
))
abort();
while(true){
if(inpusize <= 0){
inpu = inpu_buff;
inpus.get(inpu,1024);
inpusize = inpus.gcount();
if(inpusize){
if(WriteFile(oh,inpu,inpusize,&written,nullptr)){
inpusize -= written;
inpu += written;
}else
abort();
}else
CloseHandle(oh);
}
if(!PeekNamedPipe(ih,nullptr,0,nullptr,&readable,nullptr))
abort();
if(readable > 0){
if(!ReadFile(ih,resu,readable,&read,nullptr))
abort();
resu[read] = '\0';
resus << resu;
}
if(!written && !read)
break;
read = 0,written = 0;
}
CloseHandle(coh);
CloseHandle(cih);
CloseHandle(ih);
if(WaitForSingleObject(procinfo.hProcess,conf.script_to) == WAIT_TIMEOUT)
abort();
cout << "AWK SAYS:" << endl <<
resus.str() << endl;
単純化する前に、パイプから次のエラーを読み取っていました。
「awk: 致命的: ソース ファイル `.\aD' を開けません」.
これで、テスト バット ファイルがWaitForSingleObject()
タイムアウトになるまで関数でブロックされます。しかし、出力は OK ("PERSE PERSE PERSE") を通過し、AWK はまだ何も出力しません。調査中です。
コードの周りのホットスポットは、おそらくCreateProcess()
関数の周りにあることに注意してください。残りは通常の WinAPI の冗長性です。
私のレシピ.awkは、現時点では単なるパススルーです:
BEGIN { print "paskaa" > "paska.txt" ; }
/.*/ { print $0; }
END { exit 999; }
上記では、paska.txt ファイルの生成を使用して、スクリプトの実行開始を示しています。そんなことは一度もありません。
これは私の equivalant.bat で、期待どおりに機能しました。
@ECHO OFF
:LOOP
SET VAR=
SET /P VAR=
IF "%VAR%" NEQ "" (
ECHO %VAR%
GOTO :LOOP
)
私の無能さを我慢してください。あなたの新鮮な意見が必要です。
EDIT 2:問題を解決できましたが、これらが欠けていました:
SetHandleInformation(ihh,HANDLE_FLAG_INHERIT,0)
SetHandleInformation(ohh,HANDLE_FLAG_INHERIT,0)
つまり、子プロセスに自分側の通信ハンドルを継承させないでください。その場合、2 つのコピーが存在するため、パイプが閉じられることはありません。
これで 1 日半の作業を費やしたのは非常に不自由でした。
EDIT 3:そして、そこにいる奇妙なグーグルのためのさらなる助けとして:
子プロセスが作成されたら、パイプの子側ハンドルのインスタンスを閉じたい! そうでない場合、Child がハンドルのコピーを閉じてもパイプは有効なままであるため、PeekNamedPipe と ReadFile は読み取り可能な 0 を返すか、無期限にブロックします (引数に応じて)。