|
|
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>
|
|
2007/6/14(Thu) 20:24:11|NO.8925
|
|
2007/6/15(Fri) 14:22:22|NO.8945
御回答ありがとうございます。
さくらさんのモジュールは既に試していましたが中身はパイプでした。
なので質問文にも書いてありますがリアルタイムでは取得できませんでした。
|
|
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
|
|
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( ...
|
|
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
他に方法が無ければ使ってみてください。
|
|
2007/6/21(Thu) 04:12:48|NO.9047
main関数の中の始めの方に
setvbuf(stdout, (char *)NULL, _IONBF, 0);
というのが含まれているのを確認しました。
なので恐らく私のパイプの扱い方がおかしいのだと思います。
これからの方針としてはパイプでいきたいと思います。
|
|
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
| |
|
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
|
|
2007/6/22(Fri) 07:57:41|NO.9057
ありがとうございます。
ご指摘の部分を訂正したら無事にchild.exeの読み取りに成功しました。
さっそく別のコンソールプログラムにも応用しようと思い、試してみました。
まずlame.exeを試した結果「変換経過」の取得用途で使えそうでした。
そして本命のffmpeg.exeを試した結果「変換経過」の取得を始めてすぐに処理が終了してしまいました。
原因を考えてみたのですがReadFile関数でパイプを取得するとポインタの位置が読み取った分だけ進むからだと思いました。
そして私はまだ「同期/非同期」について質問できるほど自己調査していないので学習してみようと思います。
なのでもう少しだけ、このスレを未解決のまま残しておきたいと思います。
|
|
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"
|
|
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で両者の細かい違いを調べてみます。
|
|
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 {
// プロセス終了
}
|
|
2007/7/7(Sat) 02:22:55|NO.9290
age
|
|