none
Powershellからリモート実行したC++のgets関数が正常に動作しない RRS feed

  • 質問

  • いつもお世話になっております。

    ローカルPCからpowershellを用いて、サーバ上にあるPowershellをリモート実行した際に、
    サーバ上のPowershell内に記載されているC++のgets関数の入力の処理が異常に動作致します。
    異常な動作とは、キーボードの待ち受けが発生しないという現象になります。


    ■環境は以下の通りです。

    【ローカル】
    Windows 7
    Powershell 2.0
    【サーバ】
    Windows 2008 R2
    Powershell 2.0

    C++はVisual c++ 2008 ExpressのWin32 コンソールアプリケーションにてビルドしています。


    ■処理の流れは以下の通りです。
    [ローカル]C:\tmp\Local.ps1          ※Powershell

     リモート実行

    [サーバー]\\hoge\D:\tmp\ServerP.sp1 ※Powershell

    [サーバー]\\hoge\D:\tmp\ServerC.exe ※C++


    ■問題の切り分けとしては、以下のパターンを検証致しました。

    ①[ローカル]PS1→リモート実行→[サーバ]PS1→C++ = 異常
    ②[サーバ]C++ = 正常
    ③[サーバ]PS1→C++ = 正常
    ④[ローカル]より直接[サーバ]C++ = 正常
    ⑤[ローカル]より直接[サーバ]PS1→C++ = 正常

    よって、Powershellからリモート実行した際のみに発生する問題だと考えています。


    ■各ソース
    【Local.ps1】
    ※この3行はサーバへの接続設定。
    $wk_sec_str = ConvertTo-SecureString (パスワード) -AsPlainText -Force                      #パスワードの暗号化
    $wk_psc = New-Object System.Management.Automation.PsCredential ((ユーザ名), $wk_sec_str)   #Credential option instance Create
    $wk_sess = New-PSSession -ComputerName (\\hoge) -Credential $wk_psc                        #Session Create
    
    #サーバでリモート実行
    Invoke-Command -Session $wk_sess -ScriptBlock {D:\tmp\ServerP.sp1}

    【ServerP.ps1】
    echo "powershellの入力待ちです。Enterを押してください。
    "$host.UI.ReadLine()
    & D:\tmp\ServerC.exe
    echo "powershellに戻ってきた!"

    【ServerC.exe】
    printf("C++のEXEを実行しました。数値を入力してください。\n");
    char str[5];
    L1:
    gets(str);
    if (str == "") {
        printf("未入力です!入力してください!\n");
        goto L1;
    }
    printf("入力がありました!\n");
    return;
    ----------------------------------------------------------


    ■画面の動き

    現在の画面の遷移といたしましては、以下の通りになります。
    []内の記載は、PowershellからC++のいずれかの動作を示しています。
    ------------------------------------------------------------
    PS C:\tmp>Local.ps1

    powershellの入力待ちです。Enterを押してください。[PS1]
    (Enterを押下)
    C++のEXEを実行しました。数値を入力してください。 [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    ・・・・(無限ループ)・・・
    ------------------------------------------------------------

    上記の動きでは無く、以下のような動作にしたいと思っています。
    ------------------------------------------------------------
    PS C:\tmp>Local.ps1

    powershellの入力待ちです。Enterを押してください。[PS1]
    (Enterを押下)
    C++のEXEを実行しました。数値を入力してください。 [C++]
    123(Enterを押下)                                 [C++]  ←入力待ちが発生し、正常に入力できる
    入力がありました!                               [C++]
    powershellに戻ってきた!                         [PS1]
    (終了)
    ------------------------------------------------------------


    ■質問内容
    問題は、リモート実行にあると思いますが、
    リモート実行している状態でのgets関数は正常に挙動しなくなるのでしょうか?

    正直いって・・・問題の原因の見当がまったくついておりません。
    何か問題解決になりそうな情報がありましたらどんな情報でも構いませんので
    ご教示頂けないでしょうか?

    よろしくお願い致します。


    また、当質問はマルチポストになります。
    理由としましては、Powershell・C++のどちらの掲示板に投稿しても
    結局は両方の投稿する事になると考えたからになります。

    各掲示板にて同一のタイトルにて投稿させて頂きました。
    タイトル「Powershellからリモート実行したC++のgets関数が正常に動作しない」

    <マルチポスト先>
    【マイクロソフトの技術情報ポータル】
    http://social.technet.microsoft.com/Forums/ja-JP/powershellja/thread/45d11102-25dd-458e-95d3-9899dc19de88

    【C言語何でも質問掲示板】
    http://dixq.net/forum/viewtopic.php?f=3&t=12704


    長文で非常に申し訳ないですが、皆様よろしくお願い致します。


    • 編集済み keeji.k 2013年3月16日 11:22 マルチスレッドのURLを更新
    2013年3月16日 11:17

回答

  • PowerShellフォーラムでこれを書くのもどうかとは思いましたが…。

    挙げられているC言語(not C++言語)コードはいろいろ問題があります。if (str == "") で入力が得られたかどうかを比較していますが、C言語やC++言語にはそのような比較機能はなく、メモリアドレスの一致を確認するだけです。
    # ローカルで試してうまく動作しているのは謎ですが。

    gets()には正常に取得できたかを返すインターフェースがなく、ドキュメントにあります通り、ferror()やfeof()を確認する必要がありますが、それがなされていません。実はリモート実行した場合、stdinはクローズ済みでそもそも取得できていなかったりはしませんか?

    2013年3月17日 2:53

すべての返信

  • ■画面の動き

    現在の画面の遷移といたしましては、以下の通りになります。
    []内の記載は、PowershellからC++のいずれかの動作を示しています。
    ------------------------------------------------------------
    PS C:\tmp>Local.ps1

    powershellの入力待ちです。Enterを押してください。[PS1]
    (Enterを押下)
    C++のEXEを実行しました。数値を入力してください。 [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    未入力です!入力してください!                   [C++]
    ・・・・(無限ループ)・・・
    ------------------------------------------------------------

    回答ではなくくだらない確認ですが、パターン①を実行すると、このようにリモートで出力した内容はローカルに表示されるが、ローカルで入力した内容はリモートに送り込まれない、ということですよね?
    # 個人的にはリモートの出力内容もローカル側に表示されないと思っていました。

    リモートのPS1がstdinをバッファリングしてるのかなぁ…?

    2013年3月16日 22:43
  • 佐祐理様

    ご回答ありがとうございます。

    >このようにリモートで出力した内容はローカルに表示されるが、ローカルで入力した内容はリモートに送り込まれない、ということですよね?
    送り込まれないというよりかは、入力さえさせてくれない状況です。

    -----------------------------------------------------------------------
    C++のEXEを実行しました。数値を入力してください。 [C++]
    (入力待ち →何か入力)
    未入力です!入力してください!                   [C++]
    -----------------------------------------------------------------------
    では無く・・・
    -----------------------------------------------------------------------
    C++のEXEを実行しました。数値を入力してください。 [C++]
    未入力です!入力してください!                   [C++]
    (無限Loop)
    -----------------------------------------------------------------------

    とノンタイムでキーボードの標準入力をスルーしてしまっているようです。

    >リモートのPS1がstdinをバッファリングしてるのかなぁ…?
    すこし調査を進めていくうちにローカルから直接C++を起動したのですが

    PS C:\tmp> \\(サーバIP)\d$\tmp\ServerC.exe   → 正常
    PS C:\tmp> \\(サーバIP)\d$\tmp\ServerC.exe > aaa.txt → 異常時と同一現象

    つまりリモートで実行した際は、Powershellのリダイレクト機能が働いている・・・?
    実に不可解な現象で更に混乱してきました。

    引き続き皆様のお知恵をお借りしたいと思っております。
    よろしくお願い致します。

    2013年3月17日 2:13
  • PowerShellフォーラムでこれを書くのもどうかとは思いましたが…。

    挙げられているC言語(not C++言語)コードはいろいろ問題があります。if (str == "") で入力が得られたかどうかを比較していますが、C言語やC++言語にはそのような比較機能はなく、メモリアドレスの一致を確認するだけです。
    # ローカルで試してうまく動作しているのは謎ですが。

    gets()には正常に取得できたかを返すインターフェースがなく、ドキュメントにあります通り、ferror()やfeof()を確認する必要がありますが、それがなされていません。実はリモート実行した場合、stdinはクローズ済みでそもそも取得できていなかったりはしませんか?

    2013年3月17日 2:53
  • 佐祐理様
    ご回答ありがとうございます。
    ご指摘のC++の箇所は、つまりは正常に動作していないという事でしょうか?
    当方C++ソースを見るのは実は初めてでテストEXEをつくるのにも苦労しました・・・。
    if (str == "") の他に if (str == NULL)や if (str[0] == NULL) など記載しています。

    >stdinはクローズ済みでそもそも取得できていなかったりはしませんか?
    以下の方法で確認したところ、状態は異常でした。

    	std::ios_base::iostate state;  // 状態を受け取る変数
    	int num;
    
    	std::cin >> num;
    
    	state = std::cin.rdstate();  // 状態を受け取る
    	if( state == std::ios_base::goodbit )  // 正常かどうか調べる
    	{
    		std::cout << num << std::endl;
    	}
    	else
    	{
    		std::cout << "正常な状態ではありません" << std::endl;
    	}
    

    (C++のソースで非常に申し訳ないですが・・・)

    あとリモート実行でServerP.ps1 を実行すると入力を受け付けますが(パターン①の途中)、リモート実行でPowershell.exeやcmd.exeを実行しても
    入力を受け付けないことがわかりました・・・。

    Invoke-Command -Session $wk_sess -ScriptBlock {powershell.exe}

    2013年3月17日 8:46
  • 自己レスになります。

    Invoke-Commandにて実行したサーバ側のコマンドプロンプトさえ入力できないという事は
    C++のEXEも普通の方法では期待している挙動で動くのは難しいと考察致しましたので、
    C++側のgets関数を使用しているところで分割しようと思います。

    佐祐理様ご回答頂きありがとうございました。
    またよろしくお願い致します。

    【ServerP.ps1】
    echo "powershellの入力待ちです。Enterを押してください。"
    $host.UI.ReadLine() & D:\tmp\ServerC_1.exe
    $strEnter=$host.UI.ReadLine()
    & D:\tmp\ServerC_2.exe $strEnter echo
    "powershellに戻ってきた!"

    小生(合わせて150本もソースあるのに・・・TT)
    上司<いつやるんですか?・・・今でしょ!
    小生(TT)

    2013年3月17日 9:52