﻿<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href='base.xsl'?>

<desc title="コンソールアプリケーションの標準出力・標準エラーを取得する(パイプ)">

	<source>
BOOL GetCUIAppMsg( PCTSTR *cmdline, PTSTR *buf, DWORD size, BOOL stdout, BOOL stderr, DWORD timeout )
{
	HANDLE				read,	write;
 	SECURITY_ATTRIBUTES	sa;
	STARTUPINFO 		si;
	PROCESS_INFORMATION	pi;
	DWORD				len;
	BOOL 				isOK = FALSE;

	sa.nLength				=	sizeof(sa);
	sa.lpSecurityDescriptor	=	0;
	sa.bInheritHandle		=	TRUE;

	if( !CreatePipe( &amp;read, &amp;write, &amp;sa, 0 ) ) return FALSE;

	memset( &amp;si, 0, sizeof(si) );
	si.cb			=	sizeof(si);
	si.dwFlags		=	STARTF_USESTDHANDLES;
	si.wShowWindow	= 	SW_HIDE;
	if( stdout ) si.hStdOut		=	write;
	if( stderr ) si.hStdError	=	write;

	do
	{
		if( !CreateProcess( NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &amp;si, &amp;pi ) ) break;
		if( WaitForInputIdle( pi.hProcess, timeout ) != 0 ) break;
		if( WaitForSingleObject( pi.hProcess, timeout ) != WAIT_OBJECT_0 ) break;

		CloseHandle( pi.hThread );
		CloseHandle( pi.hProcess );

		if( !PeekNamedPipe( read, NULL, 0, NULL, &amp;len, NULL ) ) break;

		memset( buf, '\0', size );

		if( len &gt; 0 &amp;&amp; !ReadFile( read, buf, size - 1, &amp;len, NULL ) ) break;

		isOK = TRUE;
	}
	while(0);

	CloseHandle( read );
	CloseHandle( write );

	return isOK;
}
	</source>

	<r/>

	CreatePipe 関数<r/>
	WaitForInputIdle 関数<r/>
	WaitForSingleObject 関数<r/>
	CloseHandle 関数<r/>
	PeekNamedPipe 関数<r/>
	ReadFile 関数<r/>
	<block>
		<version>95以降, NT3.1以降</version>
		<r/>
		<library>
			windows.h<r/>
			kernel32.lib<r/>
			user32.lib<r/>
		</library>
	</block>

	<r/>

	コンソールアプリケーションが printf や fprintf で出力する、
	標準出力、標準エラーの内容を取得する方法です。<r/>

	<r/>

	標準出力や標準エラーの内容を取得するには、パイプと呼ばれる機能を使います。<r/>
	自分と他のアプリケーションをパイプで繋いで、
	パイプを通してデータを移動させるようなイメージだと思います。<r/>

	<r/>

	パイプには読み込み用と書き込み用の２つがあり、
	標準出力、標準入力、標準エラーに対して、
	どちらのパイプを使うかをプログラマが決めます。<r/>

	<r/>

	この処理でハマりそうなのは、CreateProcess 関数の使い方です。<r/>
	一番目の引数にはコンソールアプリケーションのパスを指定し、
	二番目の引数にはコマンドライン引数を指定する仕様です。<r/>

	ところが、一番目の引数と二番目の引数に分けて指定すると、
	うまく動かないアプリケーションがあります。<r/>
	なので、
	二番目の引数に両方をくっつけた形で指定します。<r/>

	<r/>

	例)メモ帳でtest.txtを読み込んだ状態で開く。<r/>
	CreateProcess( NULL, "C:\\WINDOWS\notepad.exe C:\\test.txt", ...<r/>

	<r/>

	サンプル中の関数の引数の説明<r/>

	<r/>

	BOOL GetCUIAppMsg( PCTSTR *cmdline, PTSTR *buf, DWORD size, BOOL stdout, BOOL stderr, DWORD timeout )<r/>

	<r/>

	<list>
		<item>
			cmdline<r/>
			実行するコンソールアプリケーションのパスとコマンドライン引数。
		</item>
		<item>
			buf<r/>
			コンソールアプリケーションが出力した文字列を格納する配列のポインタ。
		</item>
		<item>
			size<r/>
			bufが確保しているバイト数。<r/>
			※要素数ではありません。
		</item>
		<item>
			stdout<r/>
			実行するコンソールアプリケーションの標準出力を取得する場合はTRUEを指定します。
		</item>
		<item>
			stderr<r/>
			実行するコンソールアプリケーションの標準エラーを取得する場合はTRUEを指定します。
		</item>
		<item>
			timeout<r/>
			実行するコンソールアプリケーションの終了待ちをする時間をミリ秒で指定します。<r/>
			永久に待つ場合は INFINITE を指定します。
		</item>
	</list>

	<post/>

</desc>

