(C++)外部アプリケーションのメニューバー操作

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
Ketty
記事: 103
登録日時: 11年前

(C++)外部アプリケーションのメニューバー操作

#1

投稿記事 by Ketty » 10年前

こんにちは(^^) Kettyです。

プログラムから、他のアプリケーションのウィンドウのメニューバーを操作してみたいのですが、
どのような手続きでそれが実現できるのか教えてください。

とりあえず、メモ帳(notepad.exe)を対象にプログラムを作っているのですが、下記ソースコード内の
行き詰まった(><)」というコメントの部分で行き詰まっております。
メモ帳の起動、ウィンドウのハンドル取得、メニューの取得まで出来ていますが、
その後どのようにすればよいのかが分かりません。

"ファイル(F)"といったキャプションからハンドルを探せば可能なのかなと考えておりますが、
プログラムに落とし込めません。

ソースコメントにも書いていますが、GetMenuState関数を使えば可能なのか、
そうであれば、それをどのように使えばよいのか、わかりません。

ご教示ください。

--------------------------------
Windows 7 64bit
Visual C++ 2010 Express
--------------------------------

メモ帳を起動して操ってみるプログラム

コード:

#include <Windows.h>
#include <string>
#include <iostream>
#include <vector>

// ウィンドウ情報の構造体
struct WindowInfo
{
	HWND		handle ;		// ウィンドウハンドル
	std::string caption ;		// キャプション

	// コンストラクタ
	WindowInfo()
		:handle( NULL )
	{}
	WindowInfo( const HWND& p_handle, const std::string& p_caption )
		:handle( p_handle )
		,caption( p_caption )
	{}
} ;

// EnumWindowsのコールバック関数です
BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam )
{
	char* buf = new char[256] ;

	// キャプションを取得
	::GetWindowText( hWnd, buf, 256 ) ;

	// 名前が一致するかチェック
	if( buf == ((WindowInfo*)lParam)->caption )
	{
		// 一致したら戻り値を設定して列挙終了
		((WindowInfo*)lParam)->handle		= hWnd ;

		delete[] buf ;

		return FALSE ;
	}

	delete[] buf ;

	return TRUE ;
}
// ウィンドウキャプションからウィンドウハンドルを求めます
HWND GetWindowHandle( const std::string& in_caption )
{
	WindowInfo info = WindowInfo( NULL, in_caption ) ;

	::EnumWindows( EnumWindowsProc, (LPARAM)&info ) ;

	return info.handle ;
}

// メイン関数
// メモ帳を起動して操ってみますよ
int main()
{
	//-----------------------------------------------------------------------
	// メモ帳を起動
	//-----------------------------------------------------------------------
	STARTUPINFO si ;
	PROCESS_INFORMATION pi ;
	::GetStartupInfo( &si ) ;
	// 戻り値はさておきで進めます
	::CreateProcess( NULL, "C:\\WINDOWS\\system32\\notepad.exe", NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi ) ;

	//-----------------------------------------------------------------------
	// メモ帳のウィンドウハンドルを取得
	//-----------------------------------------------------------------------
	// キャプションから探してきます
	const std::string caption = "無題 - メモ帳" ;
	const HWND windowHandle = GetWindowHandle( caption ) ;
	// ハンドルが取得できなければ終了
	if( windowHandle == NULL ){ return -1 ; }

	//-----------------------------------------------------------------------
	// メモ帳をアクティブにする
	//-----------------------------------------------------------------------
	::SetForegroundWindow( windowHandle ) ;
	
	//-----------------------------------------------------------------------
	// メモ帳のメニューを取得
	//-----------------------------------------------------------------------
	const HMENU menu = ::GetMenu( windowHandle ) ;
	// メニューがなければ終了
	if( menu == NULL ){ return -1 ; }
	
	//-----------------------------------------------------------------------
	// メモ帳のファイル(F)を操作してみたい(マウスクリックしたかのようにしたい)
	//-----------------------------------------------------------------------
	// 行き詰まった(><)
	// ファイル(F)のメニューのハンドルはどうやったら取得できるのかな?
	// あらかじめ知っておかないとダメなのかな?
	// "ファイル(F)"というキャプションからメニューハンドルを探せそうな気がする。
	// ここで紹介されている↓GetMenuStateという関数が使えそうだが読んでも分からない。
	// 参考 http://www-higashi.ist.osaka-u.ac.jp/~k-maeda/vcpp/sec6-3menuapp.html

	//-----------------------------------------------------------------------
	// メモ帳のファイル(F)-メモ帳の終了(X)を操作してみたい(マウスクリックしたかのようにしたい)
	//-----------------------------------------------------------------------
	// 行き詰まった(><)
	// 上記と同じ
	
	//-----------------------------------------------------------------------
	// プログラム終了
	//-----------------------------------------------------------------------
    std::cout << "正常終了ですよ(^o^)" << std::endl ;
    std::cin.ignore() ;

	return 0 ;
}
そもそもこんなことは無理なのかな(??)とも思っていますが、
↓これを読むと、普通のボタンは操作できるようなので、メニューも操作できそうな気がします。
http://oshiete.goo.ne.jp/qa/3416508.html

よろしくお願いします。

アバター
Ketty
記事: 103
登録日時: 11年前

Re: (C++)外部アプリケーションのメニューバー操作

#2

投稿記事 by Ketty » 10年前

解決しました。
ほぼ回答そのものが↓OKWaveにありました(^v^;)
http://ziddy.japan.zdnet.com/qa5240712.html

上記はvbですが、
C++に移植して、メニューのキャプションからメニューのハンドルを取得できるところまで確認できましたので、
解決とさせていただきます。

誰かの役に立つかもしれませんので、移植において、注意すべき点をメモしておきますよ(^_^)

メモ帳(notepad.exe)は、"ファイル(F)"にぶらさがるサブメニューには、目に見えない隠しメニューのようなものがあるようです。
"新規(N)"~"メモ帳の終了(X)"まで、7つしかアイテムがないのに、GetMenuItemCount関数が9を返しました。
そして、この、見えないアイテムについて、
GetMenuItemInfo関数を使用してMENUITEMINFO構造体にデータを流し込むと、メンバcchが0になります。
(なので、単純に上記をC++で置き換えるだけだと、メモリアクセス違反が発生する)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: (C++)外部アプリケーションのメニューバー操作

#3

投稿記事 by みけCAT » 10年前

Ketty さんが書きました:メモ帳(notepad.exe)は、"ファイル(F)"にぶらさがるサブメニューには、目に見えない隠しメニューのようなものがあるようです。
"新規(N)"~"メモ帳の終了(X)"まで、7つしかアイテムがないのに、GetMenuItemCount関数が9を返しました。
予想ですが、セパレータが数に入っているのではないでしょうか?
セパレータは(メニューが開かれていれば、通常の条件では)目に見えます。
separeeta.png
セパレータ
separeeta.png (19.29 KiB) 閲覧数: 9280 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
Ketty
記事: 103
登録日時: 11年前

Re: (C++)外部アプリケーションのメニューバー操作

#4

投稿記事 by Ketty » 10年前

>みけCATさん
おせわになっております(^^)
みけCAT さんが書きました: 予想ですが、セパレータが数に入っているのではないでしょうか?
なるほど!!!!
局所的にしか確認できていませんが、(おそらく)そうです!
確かに、添付していただいた画像のセパレーターのところで1カウントずつされていることを目視できました。

すっきりしました。ありがとうございましたm(_ _)m

閉鎖

“C言語何でも質問掲示板” へ戻る