HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2007
0614
KAZUリダイレクト14未解決


KAZU

リンク

2007/6/14(Thu) 19:40:45|NO.8923

HSPからwin32APIを使って非表示でffmpeg等のCUIソフトを起動したのですが、本来DOS窓で表示されている内容(標準出力?)をHSP側でリアルタイムで知る方法はありますか?<BR>
<BR>
OSはWindows98です。<BR>
↓一応自分なりにWin32APIから取得を試みた結果です。(APIの使い方を間違えているかもしれません)<BR>
パイプ→リアルタイムでは取得できませんでした。<BR>
スクリーンバッファ→DOS窓を非表示にすると取得できませんでした。<BR>
98なのでPostMessageによるコピーは使えないと思います(未確認)<BR>



この記事に返信する


GENKI

リンク

2007/6/14(Thu) 20:24:11|NO.8925

DOS窓のリダイレクトなら、さくらさんところにモジュールありますよ。
http://hspnext.com/module/library.htm



KAZU

リンク

2007/6/15(Fri) 14:22:22|NO.8945

御回答ありがとうございます。
さくらさんのモジュールは既に試していましたが中身はパイプでした。
なので質問文にも書いてありますがリアルタイムでは取得できませんでした。



pizza

リンク

2007/6/16(Sat) 19:50:24|NO.8974

>リアルタイムでは取得できませんでした。

WaitForSingleObjectで終わるまで待機とかしてませんか?

ReadFileが子プロセス終了まで制御を返さないなら、
子プロセス側でstdoutをフラッシュしてないとだめかも知れません。

http://support.microsoft.com/kb/190351/ja



naznyark

リンク

2007/6/19(Tue) 01:29:16|NO.9024

コンソール画面の取得で良いのなら。

プログラム1、出力テスト用。
このソースから実行ファイルを作成しておいてください。

#runtime "hsp3cl" #packopt name "test_conout" repeat 20 mes cnt wait 50 loop

プログラム2。

#include "kernel32.as" AllocConsole GetStdHandle -10 : hs(0) = stat GetStdHandle -11 : hs(1) = stat GetStdHandle -12 : hs(2) = stat appname = "test_conout.exe" dim startupinfo, 17 dim procinfo, 4 startupinfo(0) = 68 CreateProcess varptr( appname ), 0, 0, 0, 1, 0, 0, 0, varptr( startupinfo ), varptr( procinfo ) dim sbi, 6 GetConsoleScreenBufferInfo hs(1), varptr( sbi ) sdim buf, wpeek( sbi, 18 ) * wpeek( sbi, 20 ) + 1 n = 0 repeat wait 3 GetConsoleScreenBufferInfo hs(1), varptr( sbi ) coocur = sbi(1) if ( coocur != cooold ) { ReadConsoleOutputCharacter hs(1), varptr( buf ), wpeek( sbi, 18 ) * wpeek( sbi, 20 ), 0, varptr( n ) redraw 0 color 255, 255, 255 : boxf color 0, 0, 0 pos 0, 0 repeat wpeek( sbi, 20 ) mes strmid( buf, wpeek( sbi, 18 ) * cnt, wpeek( sbi, 18 ) ) loop redraw 1 cooold = coocur } loop



KAZU

リンク

2007/6/20(Wed) 02:12:54|NO.9033

>>pizzaさん
WaitForSingleObjectではタイムアウト時間を100msにセットしています。
あとC言語は読めないのですがコンソールプログラム側のソースらしきものを入手したので見てみました。
しかしfflush()という関数は出てこなかったような気がします。

>>naznyarkさん
わざわざソースまで作っていただきありがとうございます。
私は「プログラム2」を実行した際に「プログラム1」のウィンドウが非表示にできたらいいなぁと思っています。
そこで「プログラム2」のSTARTUPINFO構造体のdwFlagsを0x00000001にしてwShowWindowを有効にして
「プログラム1」を非表示にしてみようとしたのですが上手くいきませんでした(非表示になりませんでした)。
変更点
startupinfo(0) = 68
CreateProcess varptr(   ...
   ↓
startupinfo(0) = 68
startupinfo(11)= 1,0
CreateProcess varptr(   ...



pizza

リンク

2007/6/21(Thu) 00:49:15|NO.9044

> しかしfflush()という関数は出てこなかったような気がします。
printf等で出力してあるならfflushが無くても

setvbuf(stdout, NULL, _IONBF, 0);
setbuf(stdout, NULL);

のどちらかでバッファリングを無効にしてあれば
パイプでもリアルタイムに読めるみたいです。

> 非表示にできたらいいなぁと思っています。
一瞬見えても良ければ、ShowWindowで非表示に出来ます。
(AllocConsole後)


#include "kernel32.as" #include "user32.as" #module #define SW_HIDE 0 #deffunc hide_console sdim defName, 1024 GetConsoleTitle varptr(defName), 1024 if stat == 0 : return 0 repeat GetTickCount newName = "console_name:"+stat FindWindow 0, newName if stat == 0 : break Sleep 1 loop SetConsoleTitle newName Sleep 40 // ウィンドウハンドル取得 FindWindow 0, newName hConsole = stat SetConsoleTitle defName ShowWindow hConsole, SW_HIDE // 非表示に return 1 #global

他に方法が無ければ使ってみてください。



KAZU

リンク

2007/6/21(Thu) 04:12:48|NO.9047

main関数の中の始めの方に
setvbuf(stdout, (char *)NULL, _IONBF, 0);
というのが含まれているのを確認しました。

なので恐らく私のパイプの扱い方がおかしいのだと思います。
これからの方針としてはパイプでいきたいと思います。



KAZU

リンク

2007/6/21(Thu) 06:08:18|NO.9049

CreateProcessで「メモリ ロケーションへのアクセスが無効です。」を意味するCode:998のエラーが発生してしまいました。

「プログラム1」 child.exe

#runtime "hsp3cl" #packopt name "child" repeat 20 mes cnt wait 15 loop end
「プログラム2」 redirect.exe

#uselib "kernel32.dll" #func CreatePipe "CreatePipe" int,int,int,int #func CreateProcess "CreateProcessA" int,int,int,int,int,int,int,int,int,int #cfunc WaitForSingleObject "WaitForSingleObject" int,int #func PeekNamedPipe "PeekNamedPipe" int,int,int,int,int,int #func ReadFile "ReadFile" int,int,int,int,int #func CloseHandle "CloseHandle" int #cfunc GetLastError "GetLastError" #packopt name "redirect" sdim lpCommandLine,260 lpCommandLine ="child.exe" hReadPipe =0 ;標準出力パイプ hWritePipe =0 hErrReadPipe =0 ;エラー出力用パイプ hErrWritePipe =0 ;SECURITY_ATTRIBUTES構造体 dim sa,3 sa(0) =12,0,1 ;パイプの作成 CreatePipe varptr(hReadPipe),varptr(hWritePipe),varptr(sa),1024 if stat=0 : dialog "標準出力パイプ作成の失敗",1,"エラー"+str(GetLastError()) :end CreatePipe varptr(hErrReadPipe),varptr(hErrWritePipe),varptr(sa),1024 if stat=0 : dialog "エラー出力用パイプ作成の失敗",1,"エラー"+str(GetLastError()) :end ;STARTUPINFO構造体 dim stinfo,17 stinfo(0) =68 ;cb stinfo(11) =101 ;dwFlags stinfo(12) =0 ;下位wShowWindow/上位cbReserved2 stinfo(15) =hWritePipe ;hStdOutput stinfo(16) =hErrWritePipe ;hStdError ;PROCESS_INFORMATION構造体 dim procinfo,4 ;コンソールアプリ起動 CreateProcess 0,varptr(lpCommandLine),0,0,1,8,0,0,varptr(sa),varptr(procinfo) if stat=0 : dialog "コンソールアプリ起動の失敗",1,"エラー"+str(GetLastError()) :end ;パイプ内容受け取り repeat lpTBA =0 if WaitForSingleObject(procinfo(0),1) { break } else { sdim bufStdOut,1024 sdim bufErrOut,1024 PeekNamedPipe hReadPipe,0,0,0,varptr(lpTBA),0 if lpTBA>0 { ReadFile hReadPipe,varptr(bufStdOut),1024,varptr(lpTBA),0 mes "Std / "+bufStdOut } PeekNamedPipe hErrReadPipe,0,0,0,varptr(lpTBA),0 if lpTBA>0 { ReadFile hErrReadPipe,varptr(bufErrOut),1024,varptr(lpTBA),0 mes "Err / "+bufErrOut } await loop } ;各種ハンドルを閉じる CloseHandle procinfo(0) ;hProcess CloseHandle procinfo(1) ;hThread CloseHandle hReadPipe CloseHandle hWritePipe CloseHandle hErrReadPipe CloseHandle hErrWritePipe title "終了" stop



pizza

リンク

2007/6/21(Thu) 19:53:44|NO.9055

> 「メモリ ロケーションへのアクセスが無効です。」
CreateProcessのp9にはvarptr(sa)ではなく、varptr(stinfo)を指定してください。

> stinfo(11) =101 ;dwFlags
0x101にしてください。


> CreatePipe varptr(hReadPipe),varptr(hWritePipe),varptr(sa),1024
子に渡さない方はDuplicateHandleで継承不可にした方が良いらしいです。

#define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_SAME_ACCESS 0x00000002 GetCurrentProcess hcp = stat sa = 12, 0, 1 CreatePipe varptr(hReadTmp), varptr(hWritePipe), varptr(sa), 1024 // 継承不可のハンドルを複製して複製元を閉じる DuplicateHandle hcp, hReadTmp, hcp, varptr(hReadPipe), 0, 0, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS //stderr用もread側を継承不可で複製する


> if WaitForSingleObject(procinfo(0),1) {
> break
子プロセス終了時は0(WAIT_OBJECT_0)を返します。
パイプから全て読み込んだかのチェックもした方が良いかも知れません。


> 「プログラム1」
mesはなぜかリアルタイムに読めないので、WriteFileを使ってください。

#runtime "hsp3cl" #packopt name "child" #include "kernel32.as" #define STD_OUTPUT_HANDLE (-11) GetStdHandle STD_OUTPUT_HANDLE hStdOut = stat repeat 20 buf = ""+cnt WriteFile hStdOut, varptr(buf), strlen(buf), varptr(writeSize), 0 wait 15 loop end



KAZU

リンク

2007/6/22(Fri) 07:57:41|NO.9057

ありがとうございます。
ご指摘の部分を訂正したら無事にchild.exeの読み取りに成功しました。
さっそく別のコンソールプログラムにも応用しようと思い、試してみました。
まずlame.exeを試した結果「変換経過」の取得用途で使えそうでした。
そして本命のffmpeg.exeを試した結果「変換経過」の取得を始めてすぐに処理が終了してしまいました。
原因を考えてみたのですがReadFile関数でパイプを取得するとポインタの位置が読み取った分だけ進むからだと思いました。
そして私はまだ「同期/非同期」について質問できるほど自己調査していないので学習してみようと思います。
なのでもう少しだけ、このスレを未解決のまま残しておきたいと思います。



pizza

リンク

2007/6/22(Fri) 20:07:40|NO.9064

>「変換経過」の取得を始めてすぐに処理が終了してしまいました。
子が孫に処理を移して終了している可能性があります。
command.comを使うことで回避できるかも知れません。


#include "kernel32.as" sdim prompt, 260 GetEnvironmentVariable "COMSPEC", varptr(prompt), 260 lpCommandLine = prompt+" /c child.exe"



KAZU

リンク

2007/6/23(Sat) 04:23:35|NO.9070

>「変換経過」の取得を始めてすぐに処理が終了してしまいました。
と自分で書いたのですがWindows98ではlame.exeと同様に成功していました。
WindowsXPだとこのような症状になってしまうようです。
>command.comを使うことで回避できるかも知れません。
XPでやってみた結果、新しいコンソールウィンドウが現れてしまいました。
そしてそのウィンドウのなかでffmpeg.exeやchild.exeが走ってしまい親側へは何も送られてきませんでした。

98系OSでは成功しNT系OSではうまくいかないということが分かったのでMSDNで両者の細かい違いを調べてみます。



pizza

リンク

2007/6/24(Sun) 11:57:53|NO.9101

> WindowsXPだとこのような症状になってしまうようです。
NT系だけで、となると心当たりが無いのですが、
GetExitCodeProcessで終了判定してみるのはどうでしょう?


#define STATUS_PENDING 0x00000103 #define STILL_ACTIVE STATUS_PENDING GetExitCodeProcess procinfo(0), varptr(exitCode) if exitCode != STILL_ACTIVE { // プロセス終了 }



f

リンク

2007/7/7(Sat) 02:22:55|NO.9290

age



ONION software Copyright 1997-2023(c) All rights reserved.