別アカウントでコンソールアプリを起動して標準出力を取得するには?

[戻る]
AGM-65 2009/10/14(水) 09:32:28
自プロセスから子プロセス(コンソールアプリ)を別アカウントで起動し、
名前なしパイプを使って子プロセスの標準出力を随時取得するプログラムを
作成していますが、CreateProcessWithLogonWで失敗してしまいます。
直後のGetLastErrorでは6→The handle is invalid.(ハンドルが無効です。)と
返ってきます。
Web検索やMSDNを読んだり、自分なりに色々調べて試してみたのですが、
原因・解決策を見つけられませんでした。

通常のCreateProcessですと問題なく動作する点、pipeを使用せずに
 //StartUpInfo設定
 ZeroMemory(&siStartInfo,sizeof(STARTUPINFO));
 siStartInfo.cb = sizeof(STARTUPINFO);
 siStartInfo.dwYCountChars = 50;
 siStartInfo.lpTitle = NULL;
として、CreateProcessWithLogonWで起動する分にも正常に動作することから、
pipeの生成方法、もしくはそもそも別アカウントの標準出力をpipeで読むことが
できない?とも思っております。
ソースコードの間違い、など、アドバイス、解決策、参考意見、何でも構いませんので、
どなたかお知恵をお貸しいただけないでしょうか。

■環境
Windows XP Pro(SP2)
Visual C++8(Visual Studio 2005)
プログラムを動作させているアカウント:domain参加ユーザー
起動したいプロセスのアカウント:コンピューター上のユーザー(Admin権限)

■ソースコード(エラー処理は省略してます)

HANDLE hChildStdOutR;
HANDLE hChildStdOutW;
HANDLE hChildStdOutRDup;
HANDLE hSaveStdOut;

//SECURITY_ATTRIBUTEの設定
SECURITY_ATTRIBUTES SecAtt;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;

SecAtt.nLength = sizeof(SECURITY_ATTRIBUTES);
SecAtt.bInheritHandle = TRUE;
SecAtt.lpSecurityDescriptor = NULL;

hSaveStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

//標準出力pipeの生成
CreatePipe(&hChildStdOutR, &hChildStdOutW, &SecAtt, 0);

//標準出力へのリダイレクション
SetStdHandle(STD_OUTPUT_HANDLE, hChildStdOutW);

//読み取りハンドルの複製
DuplicateHandle(GetCurrentProcess(), 
      hChildStdOutR,
      GetCurrentProcess(), 
      &hChildStdOutRDup , 
      0,
      FALSE,DUPLICATE_SAME_ACCESS);

CloseHandle(hChildStdOutR);

// PROCESS_INFORMATION構造体初期化
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

// STARTUPINFO 構造体設定
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
siStartInfo.hStdOutput = hChildStdOutW;
siStartInfo.hStdError = hChildStdOutW;
siStartInfo.wShowWindow = SW_HIDE;

//コンピュータ名取得
wchar_t wzComputerName[MAX_PATH];
GetComputerName(wzComputerName,&dSize);

CreateProcessWithLogonW(
        L"hoge", // ユーザーの名前
        wzComputerName, // ユーザーのドメイン(ローカルなのでコンピュータ名)
        L"password", // ユーザーのパスワード
        LOGON_WITH_PROFILE, // ログオン オプション
        L"C:\ADC\ConsoleApp.exe", // 実行可能モジュール名
        L"ConsoleApp -f "hoge.txt"", // コマンドライン文字列
        CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE |
CREATE_NEW_PROCESS_GROUP , // 作成フラグ
        NULL, // 新しい環境ブロック
        L"C:\HogeApp", // カレントディレクトリの名前
        &siStartInfo,
        &piProcInfo
      );

DWORD dRet;
dRet = GetLastError();

・・・・

subaru 2009/10/14(水) 16:21:16
ping.exeで試してみましたが普通に取れました。
STARTUPINFOW の hStdInput が設定されていないことが原因?かも。

AGM-65 2009/10/14(水) 16:56:48
subaruさん、ありがとうございます。

siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
としてみたのですが、結果は同じでした。
恐らく指定するものが間違っているのでしょうが、
subaruさんは何を設定されたのでしょうか?
標準入力用のpipeを別に作って指定するのでしょうか。

AGM-65 2009/10/14(水) 20:30:27
[[解決]]
subaruさんのアドバイスをきっかけに自己解決しました。
どうもお騒がせしました。

subaru 2009/10/14(水) 20:33:54
>siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
>としてみたのですが、結果は同じでした。
ありゃ、起動すらできませんでしたか。。。
他に原因があるのかな?

>標準入力用のpipeを別に作って指定するのでしょうか。
hStdInput=NULL → ERROR_INVALID_HANDLE
hStdInput=GetStdHandle(STD_INPUT_HANDLE) → OK
標準入力用のpipeを別に作成 → OK
でした。
ちなみにXP SP3です。

subaru 2009/10/14(水) 20:35:42
入れ違いでしたね(^^ゞ
解決してなによりでした。

AGM-65 2009/10/15(木) 16:48:18
ホントに入れ違いだったんですね・・・
まさにsubaruさんの指摘通りです。

hStdInputに標準入力用のpipeを別に作成したらOKでした。

自プロセス(親)がダイアログベース故に標準入力がないので
GetStdHandle(STD_INPUT_HANDLE)で取得した0x00000000を
セットするのが不適切だったのかなと・・・
(試しにコンソールアプリで親プロセスを作ってみて試したところ、
subaruさんと同様の結果になりました。)

でもsubaruさんもダイアログベースでOKだったのなら不思議ですね。

subaru 2009/10/16(金) 00:33:41
ご察しの通りコンソールアプリでしか試してませんでした。
WinMain/wWinMainがエントリーポイントの時は標準入力/標準出力がない
ことをすっかり忘れていました。

古いスレッドには追加発言できません。