none
プログラムからメモ帳をうまく操作できませんFindWindowEx()の使用に問題か RRS feed

  • 質問

  •  プログラムからメモ帳をうまく操作できません。WaitSubWindow()内のFindWindowEx()の使用方法が間違っているのでしょうか。

     本プログラムから、メモ帳を起動して、更に本プログラムから、「ファイル」メニューの「開く」を選択してファイル選択ダイアログを開き、更に本プログラムから、そのダイアログでc:\manual.txtファイルを指定してそのファイルをメモ帳に開こうと思うのですが、ファイル選択ダイアログを開いた後、その先の処理がうまく行きません。

    private: System::Void button1_Click(System:Surprisebject^  sender, System::EventArgs^  e)
     {
     PROCESS_INFORMATION pih;
     STARTUPINFO sih;

     ZeroMemory(&sih, sizeof(sih));
     sih.cb = sizeof(sih);
     sih.wShowWindow = SW_SHOWDEFAULT;
               ZeroMemory(&pih, sizeof(pih));

     if (CreateProcess(L"C:\\WINDOWS\\system32\\Notepad.EXE"
      , NULL, 0, 0, FALSE, 0, 0, 0, &sih, &pih) != 0)
     {
                HANDLE pcsh;
                if((pcsh = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pih.dwProcessId))!=0)
          {
              MessageBox:Tongue Tiedhow("オープンプロセスOK!!");
                    HWND handle1 = 0;
                    if ((handle1 = WaitWindow(L"Notepad", L"無題- メモ帳", 25, 1000)) != 0)
        {
                  MessageBox:Tongue Tiedhow("Notepad OK !!");//成功。
                        PostMessage(handle1, WM_COMMAND, 2, 0);//メニューの選択。

                        HWND dialg;
            if((dialg = WaitWindow(L"#32770",L"開く", 100, 120))!=0)
            {
    //----  ここまでは成功している模様  ---  ファイル選択ダイアログを開くことに成功。 ----

                           HWND editbbb = 0;//ダイアログのハンドルを使用して
                                 //ダイアログ内のコントロールのハンドルを取得。
    //-------  直下のifではじかれてelseに進みます。  --------------------------------
                           if((editbbb = WaitSubWindow(dialg,0, L"ComboBox",L"*.txt",60,750))!=0)
                            {
              String^ iFile = "C:\\manual.txt";
                                    PostStr(editbbb,iFile);
                                    PostMessage(dialg, WM_COMMAND, IDOK, 0);
                         MessageBox:Tongue Tiedhow("PostMessage() OK !!");
                 }
      else
      {
                     MessageBox:Tongue Tiedhow("ファイルダイアログError !!");//
      }
                        }
                    }
          }
     }
                }

            HWND Form1::WaitWindow(
                LPCTSTR c_name,
                LPCTSTR w_name,
                int r_count,
                int w_time)
            {
                HWND handle = 0;

                for (int ii = 0; ii < r_count; ii++)
                {
                    if ((handle = FindWindow(c_name, w_name))!=0) break;
                   
                    Sleep(w_time);
                }
                return handle;
            }

            HWND Form1::WaitSubWindow(
                HWND oya,
                HWND kodomo,
                LPCTSTR c_name,
          LPCTSTR w_name,
                int retry,
                int w_time)
            {
                HWND handle = 0;

                for (int ii = 0; ii < retry; ii++)
                {
                    if ((handle = FindWindowEx(oya, kodomo, c_name, w_name))!=0) break;
                    Sleep(w_time);
                }
                return handle;
            }

     void Form1:Stick out tongueostStr(HWND handlea, String^ stra)
            {
       for (int ii = 0, nn = stra->Length; ii < stra->Length; ii++)
                {
                    PostMessage(handlea, WM_CHAR, stra[ii], 0);
                }
       PostMessage(handlea, WM_CHAR, '\0', 0);
            }

     

    2008年1月11日 17:01

回答

  •  Sentencer さんからの引用

     ということで、Win32APIを使用して、クラス名とウィンドウ名を登録して、外部プログラムのコントロールにデーターを設定したり獲得したり、みたいなことを、マスターしたいわけです。

    了解しました。

     

    WaitSubWindowの中で使用されているFindWindowEx関数は子ウィンドウは取得できますが

    孫ウィンドウは取得できません。

    #32770からEditまで親子関係はAzuleanさんが調べられていますね。

     

     Azulean さんからの引用

    調べなおしましたところ、次のような階層構造になっているようです。

     

    '開く' #32770

    +'*.txt' ComboBoxEx32

    ++ '' ComboBox

    +++ '*.txt' Edit

     

    この階層構造はSpy++で調べられます。

    (個人的にはSpy++よりWinspectorの方が好みです)

    後はSentencerさんの作られたWaitSubWindows関数にこの順番で渡していけばOKかと思います。

     

    コード ブロック
          HWND parent1 = WaitSubWindow(dialg,0, L"ComboBoxEx32",NULL,60,750);
          HWND parent2 = WaitSubWindow(parent1,0, L"ComboBox",NULL,60,750);
          if((editbbb = WaitSubWindow(parent2,0, L"Edit",NULL,60,750))!=0)

     

     


     

    2008年1月14日 12:50

すべての返信

  • Spyを使うと、カーソルで合わせたウィンドウの「クラス」を知ることができます。

    (ウィンドウの検索)

     

     Sentencer さんからの引用

    //-------  直下のifではじかれてelseに進みます。  --------------------------------
                           if((editbbb = WaitSubWindow(dialg,0, L"ComboBox",L"*.txt",60,750))!=0)

    Windows XPのコモンダイアログでは、「ファイル名」、すなわち「*.txt」と表示される部分は"Edit"クラスです。

    Comboboxの内側にEditコントロールが貼り付けられている格好になっているため、見つかるものも見つからないという状態とみられます。

    2008年1月11日 19:04
    モデレータ
  •  

     Azuleanさん、ご回答ありがとうございます。
     一応は、Spyを使用してクラスとキャプション、つまり、クラス名とウィンドウ名、の確認をし、下記の通りのコードにしましたが、つまり、クラス名をComboBoxからEditに置き換えましたが、不成功でした。
     また、下記のコードにおいて、Editに置き換えをした行をコメントアウトして、/* */のコメント2箇所をコードにして、つまりは、ComboBoxとEditの2段構えにしたテストしてみましたが、それも不成功でした。

    //-----------    以下、抜粋。    ---------------
                 HWND dialgko = 0;
                 HWND editbbb = 0;
    /*
      if((dialgko = WaitSubWindow(dialg,0,L"ComboBox",L"*.txt",60,750))!=0)//不成功。
      {
                     if((editbbb = WaitSubWindow(dialgko,0, L"Edit",L"*.txt",60,750))!=0)
    */
                     if((editbbb = WaitSubWindow(dialg,0, L"Edit",L"*.txt",60,750))!=0)//不成功。
                     {
       String^ iFile = "C:\\manual.txt";
                         PostStr(editbbb,iFile);
                         PostMessage(dialg, WM_COMMAND, IDOK, 0);
               }
         else
         {
                   MessageBox:Tongue Tiedhow("Edit Error !!");//
         }
    /*
      }
      else
      {
                    MessageBox:Tongue Tiedhow("ComboBox Error !!");
      }
    */

     なお、ソースファイルの冒頭の方の記述は、下記の通りとしていますが、不備がありますでしょうか。

    #pragma once

    #include <windows.h>
    #include <stdio.h>
    #include <winbase.h>
    #include <winuser.h>

    namespace AutoExecute01 {

     using namespace System;
     using namespace System::ComponentModel;
     using namespace System::Collections;
     using namespace System::Windows::Forms;
     using namespace System:Big Smileata;
     using namespace System:Big Smilerawing;

     

    2008年1月11日 20:36
  • 昨晩の回答は不十分でした、すみません。

     

    調べなおしましたところ、次のような階層構造になっているようです。

     

    '開く' #32770

    +'*.txt' ComboBoxEx32

    ++ '' ComboBox

    +++ '*.txt' Edit

     

    どこを書き換えれば十分かは調べていません。

     

    ところで、ファイルを開くことが最終目的ではないですよね?

    2008年1月12日 4:09
    モデレータ
  • //やや本題から外れているかもしれません

     

    ファイルを開くことが最終目的なら以下のようにメモ帳の起動引数にファイル名を渡せばOKですよね。

     

    CreateProcess(NULL, "notepad.exe \"c:\\manual.txt\"", .....

     

    また、例として省略されているだけかもしれませんが

    CreateProcess(L"C:\\WINDOWS\\system32\\Notepad.EXE" ....だとWindowsのシステムフォルダを直接指定してしまっているため、Windows2000(システムフォルダがC:\Winnt\system32)や、Cドライブ以外にWindowsをインストールしていた場合にメモ帳が起動できません。

    システムフォルダのパスを取得してメモ帳のフルパスを指定するか、第二引数にフルパスではなくnotepad.exeのみを指定したほうが良いと思います。
    2008年1月13日 12:18
  •  

     C.Johnさん、アドバイスありがとうございます。
     これから書くことは、この掲示板の趣旨からちょっとズレ気味ですが、Azuleanさんからも「最終目的」のお問い合わせがあったり、伏せていると、自分の目的からは回答がそれてしまいそうなので以下に少々、目的としているところを書かせていただきます。 
     今回のアプローチが的を射ているかズレているかわかりませんが、本当の目的は、証券会社が提供しているツールを自作プログラムから操作して、自作プログラムの中に『リアルタイム株価を取得する』こと。
     そのために、Win32APIを使用して、たとえば、ツール内のEditなどにデーターを設定し、アクセスのめたにツール内の「OK」ボタンをクリックしたのと同様の処理ができるようになりたい。そのとっかかりとして、自作プログラムからメモ帳を起動しメニューをたどりダイアログを開かせ更にダイアログ内のEditにファイル名を設定して開くボタンをクリックしたのと同等のメッセージをWin32APIを使用して発し、ということに取り組みました。そうしたところ、開いたダイアログ内の、ファイル名のEdit、へのファイル名の設定、あたりで行き詰まり、今回のような質問となりました。
     ということで、Win32APIを使用して、クラス名とウィンドウ名を登録して、外部プログラムのコントロールにデーターを設定したり獲得したり、みたいなことを、マスターしたいわけです。

     

    2008年1月13日 16:25
  • .NET FrameworkのSendKeysが使用できるかも知れません

     

    参照設定で『Microsoft VisualBasic』を追加します

    メモ帳の起動には System:Big Smileiagnostic:Stick out tonguerocessクラスを使います

     

    コード ブロック

    System::Diagnostics::Process^ oNote; // を Formクラス内で宣言します

     

    ボタン1のクリックで起動ならそのクリックイベントで

    oNote = gcnew System::Diagnostics::Process();

    oNote->StartInfo->FileName = "notepad.exe";
    oNote->StartInfo->Verb = "open";

    // ボタン2で次の動作をする ・・・ デザイン時は EnableをFalseに設定
    button2->Enabled = oNote->Start();


     

    ボタン2のクリックイベントで

    // メモ帳をアクティブにする

    Interaction::AppActivate( oNote->MainWindowTitle );

    // SendKeysでキー操作を送信 『ALT+F』『O』『C:\Sample.txt』『Enter』

    SendKeys::Send( L"%foc:\\sample.txt{enter}" );

     

     

    といった具合でどうでしょう
    2008年1月14日 3:11
  •  Sentencer さんからの引用

     ということで、Win32APIを使用して、クラス名とウィンドウ名を登録して、外部プログラムのコントロールにデーターを設定したり獲得したり、みたいなことを、マスターしたいわけです。

    了解しました。

     

    WaitSubWindowの中で使用されているFindWindowEx関数は子ウィンドウは取得できますが

    孫ウィンドウは取得できません。

    #32770からEditまで親子関係はAzuleanさんが調べられていますね。

     

     Azulean さんからの引用

    調べなおしましたところ、次のような階層構造になっているようです。

     

    '開く' #32770

    +'*.txt' ComboBoxEx32

    ++ '' ComboBox

    +++ '*.txt' Edit

     

    この階層構造はSpy++で調べられます。

    (個人的にはSpy++よりWinspectorの方が好みです)

    後はSentencerさんの作られたWaitSubWindows関数にこの順番で渡していけばOKかと思います。

     

    コード ブロック
          HWND parent1 = WaitSubWindow(dialg,0, L"ComboBoxEx32",NULL,60,750);
          HWND parent2 = WaitSubWindow(parent1,0, L"ComboBox",NULL,60,750);
          if((editbbb = WaitSubWindow(parent2,0, L"Edit",NULL,60,750))!=0)

     

     


     

    2008年1月14日 12:50