C++ Builder CE ローカルな別プロセスの制御

#2 実際に制御の部

の続きです。ハンドル経由でコントロールにイベント送って疑似操作します。直接マウスをクリックしなくてもおけです。まずソースを示しましょうかね。コマンドラインプログラムです。


#include <stdio.h>
#include <windows.h>
#include <string.h>

HWND movie;
HWND duration;


bool Launch(char* program)
{
	STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

	//const char* programPath = "\".\\CRC_Mini.exe\"";
	// 引数があれば: const char* args = "C:\\path\\to\\file.txt";

    const char* args = nullptr;

    // プロセス作成
    if (CreateProcess(
        NULL, // lpApplicationName (NULLならlpCommandLineから取得)
		(LPSTR)program, // lpCommandLine (プログラム名と引数)
        NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
    {
		//std::cout << "プロセス起動成功。ハンドル: " << pi.hProcess << std::endl;
        // プロセスの終了を待つ場合: WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		return true;
	}
	else {
		return false;
		//std::cerr << "CreateProcess失敗: " << GetLastError() << std::endl;
    }

}

// コールバック関数
BOOL CALLBACK EnumChildProc( HWND hWnd, LPARAM lParam )
{
 TCHAR szBuff[1024];
  TCHAR szBuff2[1024];

 
 
 GetWindowText( hWnd, szBuff, sizeof(szBuff) );
 printf( "├[%s] ", szBuff );

  GetClassName( hWnd, szBuff2,sizeof(szBuff2));
  printf("[%s]\n", szBuff2);

  if(!strcmp(szBuff,"Movie"))
    movie = hWnd;

  if(!strcmp(szBuff2,"TLabeledEdit"))
    duration = hWnd;

 return TRUE;
}

// メイン関数
int main( int argc, char** argv)
{

 HWND hCalc;
  int   sec;
  char newtext[10];

    if( argc == 1 )
        sec = 5;
    else
        sec = atoi(argv[1]);

    sprintf(newtext,"%d",sec);


    if( !Launch("\".\\CRCMini.exe\"")){
    	printf("launch failed");
        return 1;
    }
     
 if ( (hCalc = FindWindow(NULL,"CRCMini")) != NULL ){
  printf( "CRC-Miniのコントロール列挙\n" );
  EnumChildWindows( hCalc, EnumChildProc, NULL );
 }
  else {
    printf("CRCMini not found");
    return 1;
  }

  // setting text for test

  if (SendMessageA(duration, WM_SETTEXT, 0, (LPARAM)newtext) == 0) {
        printf("WM_SETTEXT message sent successfully.\n");
    } else {
        printf("WM_SETTEXT message sent, return value: non-zero.\n");
    }

    // movie button click

    PostMessage(movie, BM_CLICK, 0, 0);

   // getchar();

    // shutdown CRC-Mini
    //PostMessageW(hCalc, WM_CLOSE, 0, 0);
   printf("done\n");

 return 0;
}

最初にターゲットプログラム(CRCMini.exe)の各要素をダンプします。まずCRCMini.exeのbuildの時に、FormのキャプションをForm1以外の文字列にしておきます。この場合は、CRCMiniです。でないとForm1だらけになってしまいます。それは、

のようにForm1->Captionを好きな文字列に変更すればおけです。

からコントロールを抜き出して、

CRC-Miniのコントロール列挙
├[] [TProgressBar]
├[Movie] [TButton]
├[Still] [TButton]
├[Capture] [TButton]
├[5] [TLabeledEdit]

各コントロールのCaptionないしClassでセレクトします。まずやりたいことは、TLabeledEditの内容としてコマンドラインから与えられた秒数を書き込みます。それが、

  // setting text for test

  if (SendMessageA(duration, WM_SETTEXT, 0, (LPARAM)newtext) == 0) {
        printf("WM_SETTEXT message sent successfully.\n");
    } else {
        printf("WM_SETTEXT message sent, return value: non-zero.\n");
    }

“Movie”ボタンのクリックは、

    // movie button click

    PostMessage(movie, BM_CLICK, 0, 0);

になります。ここでSendMessage()でなくPostMessage()を使っているのが肝要です。SendMessage()だと待機することになりますから。durationやらmovieを拾っているのは、

 GetWindowText( hWnd, szBuff, sizeof(szBuff) );
 printf( "├[%s] ", szBuff );

  GetClassName( hWnd, szBuff2,sizeof(szBuff2));
  printf("[%s]\n", szBuff2);

  if(!strcmp(szBuff,"Movie"))
    movie = hWnd;

  if(!strcmp(szBuff2,"TLabeledEdit"))
    duration = hWnd;

の部分で、Callback関数内です。相手がVCLのプログラムだと拾いやすいです。FMXだとこう簡単には拾えないです。

コメント