(C++)GetMenuItemCount関数の挙動

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

(C++)GetMenuItemCount関数の挙動

#1

投稿記事 by Ketty » 9年前

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

今回の質問は、↓からの続編になります。
http://dixq.net/forum/viewtopic.php?f=3&t=16476
((C++)外部アプリケーションのメニューバー操作)

外部アプリケーションのメニューのそれぞれのメニューアイテム数を取得したいのですが、
GetMenuItemCount関数の挙動が、アプリケーションごとに異るように思え、
それがなぜなのか、どのようにすれば解決できるのか分からずに悩んでいます。

戻り値が正しく返るアプリケーションと、
戻り値が正しく返らない(0になる)アプリケーションがあります。

私の環境では、
・メモ帳(notepad.exe)⇒期待通り正しい数値で返る
・電卓(calc.exe)⇒期待通り正しい数値で返る
・サクラエディタ(sakura.exe)⇒0になる
・秀丸エディタ(Hidemaru.exe)⇒0になる
・差分チェックツールDF(DF.exe)⇒期待通り正しい数値で返る
となります。

マイクロソフト製とか個人作品とか関係ないようです。

そこで質問ですが、
この原因と解決方法をご教示ください。

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

以下に再現するプログラムを掲載します。
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
1.295~312行目は、Win7 64bit用なのでお手元の環境のパスにしてください。
(お持ちでないアプリケーションは無視していただいてかまいません)
2.320~324行目で、どのアプリケーションを起動するか選んでください
3.事象が現れるのは205行目です。
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

コード:

#include <Windows.h>
#include <string>
#include <iostream>
#include <vector>
#include <array>
#include <shlobj.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

// このプログラムで使うウィンドウ情報の構造体
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 )
	{}
} ;
// このプログラムで使うメニュー情報の構造体
struct MenuInfo
{
	unsigned int id ;		// メニューID
	std::string caption ;	// キャプション
	HMENU handle ;			// メニューハンドル
	unsigned int itemNum ;	// アイテム数

	// コンストラクタ
	MenuInfo()
		:id( 0 )
		,handle( NULL )
		,itemNum( 0 )
	{}
	MenuInfo( const unsigned int& p_id, const std::string& p_caption, const HMENU& p_handle, const int& p_itemNum )
		:id( p_id )
		,caption( p_caption )
		,handle( p_handle )
		,itemNum( p_itemNum )
	{}
} ;

// GetLastErrorのテキストを取得する関数
std::string GetLastErrorMessage()
{
	std::string text ;

	// エラーメッセージ用バッファ
	LPVOID lpMsgBuf = NULL ;
	//エラー表示文字列作成
	if( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
						 NULL,
						 ::GetLastError(),
						 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 
						 (LPTSTR)& lpMsgBuf,
						 0,
						 NULL ) != 0 )
	{
		if( lpMsgBuf != NULL )
		{
			text = reinterpret_cast<const char *>( lpMsgBuf ) ;
			::LocalFree( lpMsgBuf );
		}
	}

	return text ;
}
// ファイル存在チェックします
bool IsFileExists( const std::string& filePath )
{
	bool isExists = ( ::PathFileExists( filePath.c_str() ) != 0 ) ;
	
		// ディレクトリでないことをチェックする
	if( isExists )
	{
		isExists = ( ( ::PathIsDirectory( filePath.c_str() ) != 0 ) == false ) ;
	}

	return isExists ;
}
// 前方一致するかどうかチェックする関数
bool IsStringStartWith( const std::string& targetText, const std::string& searchText )
{
	// 空文字を探さないための対応
	if( targetText.empty() ){ return false ; }
	// 空文字を探さないための対応
	if( searchText.empty() ){ return false ; }

	return ( targetText.substr( 0, searchText.size() ) == searchText ) ;
}

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

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

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

		delete[] buf ;

		return FALSE ;
	}

	delete[] buf ;

	return TRUE ;
}
// 指定のキャプションに前方一致するウィンドウハンドルを取得します
HWND GetWindowHandle( const std::string& in_caption )
{
	// 参考 http://7ujm.net/C++/EnumWindows.html

	WindowInfo info = WindowInfo( NULL, in_caption ) ;

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

	return info.handle ;
}

// メニューの情報を取得します
bool GetMenuInfo( const HMENU& in_menuHandle, const unsigned int& item, MenuInfo& out_info )
{
	// 戻り値初期化
	out_info = MenuInfo() ;

	// メニュー無しの場合は処理しません
	if( in_menuHandle == NULL ){ return true ; }

	MENUITEMINFO mii ;
	mii.fMask		= 0x3F ;
	mii.dwTypeData	= "\0" ;
	mii.cch			= 0 ;
	mii.cbSize		= sizeof( MENUITEMINFO ) ;

	//-----------------------------------------------
	// メニューアイテムの情報を取得
	//-----------------------------------------------
	if( ::GetMenuItemInfo( in_menuHandle, item, 1, &mii ) == 0 )
	{
		// 取得失敗
		std::cout << GetLastErrorMessage() << std::endl ;
		return false ;
	}

	//-----------------------------------------------
	// キャプションを取得するための準備
	//-----------------------------------------------
	// セパレータ―の場合はスルー
	const unsigned int dataSize = mii.cch ;
	if( dataSize == 0 ){ return true ; }

	std::string tmp ;
	for( unsigned int j=0, m=dataSize; j<m; ++j )
	{
		tmp.append( " " ) ;
	}

	mii.dwTypeData = (LPSTR)tmp.c_str() ;
	mii.cch = dataSize + 1 ;
	mii.cbSize = sizeof( MENUITEMINFO ) ;
		
	//-----------------------------------------------
	// もう一度メニューアイテムの情報を取得
	//-----------------------------------------------
	if( ::GetMenuItemInfo( in_menuHandle, item, 1, &mii ) == 0 )
	{
		// 取得失敗
		std::cout << GetLastErrorMessage() << std::endl ;
		return false ;
	}
	
	//-----------------------------------------------
	// 戻り値設定
	//-----------------------------------------------
	const unsigned int id		= mii.wID ;				// メニューID
	const std::string caption	= mii.dwTypeData ;		// キャプション
	const HMENU handle			= mii.hSubMenu ;		// メニューハンドル(ツリーの末端のときはハンドルがNULL)
	unsigned int itemNum		= 0 ;					// メニューに紐づくサブメニュー数

	// さらにツリーがあるときのみサブメニュー数を取得
	if( handle != NULL )
	{
		int tmpNum	= ::GetMenuItemCount( handle ) ;	
		if( tmpNum <= -1 )
		{
			// 取得失敗
			std::cout << GetLastErrorMessage() << std::endl ;
			return false ;
		}

		//********************************************************************
		// どうしてアイテム数が0件になるやつと、ならないやつがあるのかな??
		//********************************************************************
		if( tmpNum == 0 )
		{
			std::cout << caption + "というメニューからは正しくアイテム数をカウントできないようです" << std::endl ;
		}

		itemNum = tmpNum ;
	}

	// 戻り値にセット
	out_info = MenuInfo( id, caption, handle, itemNum ) ;

	return true ;
}
// 親メニューハンドルから全てのサブメニュー情報を取得します(再帰あり)
bool GetMenuInfoList( const HMENU& in_menuHandle, std::vector<MenuInfo>& out_infoList )
{
	// 戻り値クリア
	out_infoList.clear() ;
	
	// メニュー無しの場合は処理しません
	if( in_menuHandle == NULL ){ return true ; }

	// このメニューにツリーされているアイテムの数を取得
	const int tmpNum = ::GetMenuItemCount( in_menuHandle ) ; // 失敗すると-1が返ります
	if( tmpNum < -1 )
	{
		// 取得失敗
		std::cout << GetLastErrorMessage() << std::endl ;
		return false ;
	}
	// このメニューにツリーされているアイテムの数
	const unsigned int topItemNum = tmpNum ;

	// 戻り値をリザーブしておきます
	out_infoList.reserve( topItemNum ) ;

	// このメニューにツリーされているアイテムを全て走査して戻り値に追記
	for( unsigned int i=0, n=topItemNum; i<n; ++i )
	{
		// i番目のアイテムのメニュー情報を取得します
		MenuInfo menuInfo ;
		if( GetMenuInfo( in_menuHandle, i, menuInfo ) == false )
		{
			return false ;
		}

		// i番目のアイテムの中にさらにサブアイテムがある場合
		if( menuInfo.itemNum > 0 )
		{
			// 再帰してサブアイテムを全て取得します
			std::vector<MenuInfo> subMenuInfoList ;
			if( GetMenuInfoList( menuInfo.handle, subMenuInfoList ) == false )
			{
				return false ;
			}

			// サブアイテムのキャプションが空(つまりセパレーター)の場合はアイテムとしてカウントしないことにします
			for( unsigned int j=0, m=subMenuInfoList.size(); j<m; ++j )
			{
				if( subMenuInfoList[j].caption.empty() )
				{
					--menuInfo.itemNum ;
				}
			}
		}

		// 戻り値に追記します
		out_infoList.push_back( menuInfo ) ;
	}

	return true ;
}
// 起動するアプリケーションの構造体
struct App
{
	const std::string path ;	// パス
	const std::string caption ;	// キャプション(前方一致)

	// コンストラクタ
	App()
	{}
	App( const std::string p_path, const std::string p_caption )
		:path( p_path )
		,caption( p_caption )
	{}
} ;

//**************************************************************
// 起動するアプリケーションのパスとか(64bit自分用)
//**************************************************************
static const std::array<App, 5> APP_LIST =
{
	// メモ帳
	App( "C:\\WINDOWS\\system32\\notepad.exe",	// パス
		 "無題" ),		// キャプション(前方一致)
	// 電卓
	App( "C:\\WINDOWS\\system32\\calc.exe",		// パス
		 "電卓" ),		// キャプション(前方一致)
	// サクラエディタ
	App( "C:\\Program Files (x86)\\sakura\\sakura.exe",	// パス
		 "(無題)" ),	// キャプション(前方一致)
	// 秀丸エディタ
	App( "C:\\Program Files (x86)\\Hidemaru\\Hidemaru.exe",	// パス
		 "(無題)" ),	// キャプション(前方一致)
	// DF(差分チェックツール)
	App( "C:\\DF\\DF.exe",	// パス
		 "DF" ),		// キャプション(前方一致)
} ;

// 処理本体です
bool Proc()
{
	//**************************************************************
	// ↓お好みを選んでください(^v^)
	//**************************************************************
	const App app = APP_LIST[0] ;	// メモ帳
	//const App app = APP_LIST[1] ;	// 電卓
	//const App app = APP_LIST[2] ;	// サクラエディタ
	//const App app = APP_LIST[3] ;	// 秀丸エディタ
	//const App app = APP_LIST[4] ;	// DF(差分チェックツール)

	// ウィンドウが開くまでの待機時間
	const unsigned int waitMSec = 2000 ;	// ミリ秒

	//-----------------------------------------------------------------------
	// アプリケーションがあるかどうか一応チェックします
	//-----------------------------------------------------------------------
	if( IsFileExists( app.path ) == false )
	{
		std::cout << app.path + "はありません" << std::endl ;
		return false ;
	}

	//-----------------------------------------------------------------------
	// アプリケーションを起動します
	//-----------------------------------------------------------------------
	std::cout << app.path + "を起動" << std::endl ;
	STARTUPINFO si ;
	PROCESS_INFORMATION pi ;
	::GetStartupInfo( &si ) ;
	if( ::CreateProcess( NULL, (LPSTR)app.path.c_str(), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi ) == 0 )
	{
		std::cout << GetLastErrorMessage() << std::endl ;
		return false ;
	}

	// ウィンドウが生成されるまで少し待たないといけません
	Sleep( waitMSec ) ;

	//-----------------------------------------------------------------------
	// アプリケーションのウィンドウハンドルを取得します
	//-----------------------------------------------------------------------
	// キャプションから前方一致で探してきます
	const HWND windowHandle = GetWindowHandle( app.caption ) ;
	// ハンドルが取得できなければ終了
	if( windowHandle == NULL )
	{
		std::cout << app.caption + "に前方一致するウィンドウを見つけられません" << std::endl ;
		return false ;
	}

	//-----------------------------------------------------------------------
	// アプリケーションをアクティブにします
	//-----------------------------------------------------------------------
	::SetForegroundWindow( windowHandle ) ;

	//-----------------------------------------------------------------------
	// アプリケーションのメニューを取得します
	//-----------------------------------------------------------------------
	// まず、ウィンドウハンドルからメニューハンドルを取得します
	HMENU menuHandle = ::GetMenu( windowHandle ) ;

	// 次に、ウィンドウのメニューを全て取得します
	std::vector<MenuInfo> menuInfoList ;
	if( GetMenuInfoList( menuHandle, menuInfoList ) == false )
	{
		return false ;
	}

	//-----------------------------------------------------------------------
	// デバッグプリントしてみます
	//-----------------------------------------------------------------------
	std::cout << "---------メニューアイテム数の列挙---------" << std::endl ;
	for( unsigned int i=0, n=menuInfoList.size(); i<n; ++i )
	{
		std::cout << menuInfoList[i].caption + " = " << menuInfoList[i].itemNum << std::endl ;
	}
	std::cout << "------------------------------------------" << std::endl ;

	//-----------------------------------------------------------------------
	// 処理終了する
	//-----------------------------------------------------------------------
	std::cout << "正常終了ですよ(^o^)" << std::endl ;
	return true ;
}

// メイン関数
int main()
{
	// 処理実施
	Proc() ;

    std::cin.ignore() ;
	return 0 ;
}

よろしくお願いしますm(__)m

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

Re: (C++)GetMenuItemCount関数の挙動

#2

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

とりあえず、手軽に実験できるように対象をコマンドラインから指定できるようにしたプログラムを置いておきます。

差分

コード:

315c315
< bool Proc()
---
> bool Proc(const char *a, const char *b)
320c320
<       const App app = APP_LIST[0] ;   // メモ帳
---
>       //const App app = APP_LIST[0] ; // メモ帳
324a325
>       const App app = App(a, b);
402c403
< int main()
---
> int main(int argc, char *argv[])
405c406,407
<       Proc() ;
---
>       if(argc < 3) return 1;
>       Proc(argv[1], argv[2]) ;
407c409
<     std::cin.ignore() ;
---
>     //std::cin.ignore() ;
添付ファイル
mod1.cpp
改良したソースコード
(11.8 KiB) ダウンロード数: 114 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: (C++)GetMenuItemCount関数の挙動

#3

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

秀丸はわかりませんが、サクラエディタ2.2.0.1では、メインメニュー作成時にはサブメニューはCreatePopupMenu()としており(sakura_core/window/CEditWnd.cpp 877行目)、
サブメニューを表示する時(WM_INITMENUPOPUP受信時)に動的にサブメニューを作っている(sakura_core/window/CEditWnd.cpp 1571行目→2316行目~)ため、
起動直後はサブメニューの項目数が0と認識されているのかもしれません。
実際、サクラエディタの起動後に一旦メニューを開くと、開いたメニューについてはセパレータを除いた項目数を取得出来ました。

テスト用のプログラムを作ってみました。
自分の環境(Windows 7 Home Premium SP1 64bit、gcc (GCC) 4.8.1)では、
メニューをリソースから読み込んでいるtest1では正常(?)にセパレータを除いた項目数を取得出来ましたが、
メニューをサクラエディタとほぼ同じ方法で生成しているtest2では項目数が0と返ってきました。
添付ファイル
getmenuitemcount_no_kyodou.zip
テスト用プログラム
(51.47 KiB) ダウンロード数: 116 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
Ketty
記事: 102
登録日時: 10年前

Re: (C++)GetMenuItemCount関数の挙動

#4

投稿記事 by Ketty » 9年前

>みけCATさん
ご回答くださり、ありがとうございます<(__)>
試験用のプログラムまで作ってくださり重ねてお礼申し上げます。
(ぐ…このtest1、test2のメニュー…なぜか意味もなくポチポチ押してしまいますね…)
みけCAT さんが書きました: 起動直後はサブメニューの項目数が0と認識されているのかもしれません。
なるほど。
確かに、お作りいただいたTest2はサブメニューの項目数は0と返され、
しかし、予め手動でメニューを開いた状態で実施させると、
サブメニューの項目数が期待通り返されますね。

そして、秀丸も同様のやり方で期待通りの値が取れました。

ですが、
みけCAT さんが書きました: 実際、サクラエディタの起動後に一旦メニューを開くと、開いたメニューについてはセパレータを除いた項目数を取得出来ました。
こちらに関しては、私の環境ではメニューを開いてやっても、
サブメニューの項目数は0と返されます。
念のためタブ機能を切って(タブバーを表示しないで)試してみましたが同じでした。
サクラエディタのバージョンにも依存するのかもしれないと考えています。

このサクラエディタの不思議な挙動はちょっとさておきですが、
取り急ぎ、解決に向けての案をまとめ始めております。

外部アプリケーション起動
 ↓
メニュー取得
 ↓
サブメニュー0なら
プログラムからWM_INITMENUPOPUPをPostMessageしてメニューを展開させた状態を作り、
再度メニューを取得
 ↓
こうやって目的のサブメニュー(ツリー末端)までたどり着ければ、
どんな外部アプリケーションのメニューでも操作できる(のかな?)
 
という感じです。
他に良案や、何かご指摘いただけますと幸いです。

アバター
Ketty
記事: 102
登録日時: 10年前

Re: (C++)GetMenuItemCount関数の挙動

#5

投稿記事 by Ketty » 9年前

行き詰まってしまいました。
やはり、メニューがあるのに、メニューアイテムを参照できないアプリケーションがありました。

しかし、今度は、GetMenuItemCount関数が0になるのではなく、
-1(失敗)を返すケースです。

そのアプリケーションですが、Windowsの管理コンソールです。
(C:\Windows\System32\mmc.exe)

調べてみたところ、
このアプリケーションのメニューは、ToolbarWindow32というコンポーネントのようです。
MiniSpyというフリーのツールでウィンドウ情報を調べてみてわかりました。
---------------------------------------------------------------------------
■MiniSpy(vbランタイムが必要です)・・・Vector社
http://www.vector.co.jp/soft/win95/prog/se291933.html
■Msvbvm50(vbランタイムです)・・・マイクロソフト社
http://support.microsoft.com/ja-jp/kb/180071/en-us
---------------------------------------------------------------------------

そして、以下を読むと、どうやらToolbarWindow32というコンポーネントのメニューは特殊らしく、
メニューを取得できないように読み取れました。(英語のやつは正しく理解できている自信がありません)
https://social.msdn.microsoft.com/Forum ... cgeneralja
http://forums.devx.com/showthread.php?4 ... d-Submenus
http://www.devsuperpage.com/search/Arti ... tID=252760
いずれも解決策は記載されておりません。皆困っているのかな、と察しています。

私が個人的に調べられた結果としては、
・このToolbarWindow32の中にさらに子ウィンドウがあるのではなかろうかとEnumChildWindows関数を使って調べたがなかった。
・GetMenu関数ではメニューハンドルが返ってきている(NULLでない)。
・そのメニューハンドルを使ってGetMenuItemCount関数を使うと、-1(失敗)が返る
ということです。

いったいどのようにすればToolbarWindow32のメニューのアイテムを取得できるのでしょうか?
それとも、このコンポーネントは何か特別セキュアな部品で外部から触れないようになっている、ということでしょうか??

再現ソースも掲載しておきます。
C:\Windows\System32\mmc.exeを実行してからこのプログラムを実行すると、229行目で再現します。

コード:

#include <Windows.h>
#include <string>
#include <iostream>
#include <vector>
#include <array>
#include <tchar.h>
#include <shlobj.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

// このプログラムで使うウィンドウ情報の構造体
struct WindowInfo
{
	HWND		handle ;		// ウィンドウハンドル
	std::string caption ;		// キャプション
	std::string className ;		// クラス名

	// コンストラクタ
	WindowInfo()
		:handle( NULL )
	{}
	WindowInfo( const HWND& p_handle, const std::string& p_caption, const std::string& p_className )
		:handle( p_handle )
		,caption( p_caption )
		,className( p_className )
	{}
} ;
// このプログラムで使うメニュー情報の構造体
struct MenuInfo
{
	unsigned int id ;		// メニューID
	std::string caption ;	// キャプション
	HMENU handle ;			// メニューハンドル
	unsigned int itemNum ;	// アイテム数

	// コンストラクタ
	MenuInfo()
		:id( 0 )
		,handle( NULL )
		,itemNum( 0 )
	{}
	MenuInfo( const unsigned int& p_id, const std::string& p_caption, const HMENU& p_handle, const int& p_itemNum )
		:id( p_id )
		,caption( p_caption )
		,handle( p_handle )
		,itemNum( p_itemNum )
	{}
} ;

// GetLastErrorのテキストを取得する関数
std::string GetLastErrorMessage()
{
	std::string text ;

	// エラーメッセージ用バッファ
	LPVOID lpMsgBuf = NULL ;
	//エラー表示文字列作成
	if( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
						 NULL,
						 ::GetLastError(),
						 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 
						 (LPTSTR)& lpMsgBuf,
						 0,
						 NULL ) != 0 )
	{
		if( lpMsgBuf != NULL )
		{
			text = reinterpret_cast<const char *>( lpMsgBuf ) ;
			::LocalFree( lpMsgBuf );
		}
	}

	return text ;
}

// 前方一致するかどうかチェックする関数
bool IsStringStartWith( const std::string& targetText, const std::string& searchText )
{
	// 空文字を探さないための対応
	if( targetText.empty() ){ return false ; }
	// 空文字を探さないための対応
	if( searchText.empty() ){ return false ; }

	return ( targetText.substr( 0, searchText.size() ) == searchText ) ;
}
// コールバック関数
BOOL CALLBACK GetWindowHandleByCaptionCallBack( HWND hWnd, LPARAM lParam )
{
	char* buf1 = new char[256] ;
	char* buf2 = new char[256] ;

	// キャプションとクラス名取得
	::GetWindowText( hWnd, buf1, 256 ) ;
	::GetClassName( hWnd, buf2, 256 ) ;

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

		delete[] buf1 ;
		delete[] buf2 ;

		return FALSE ;
	}

	delete[] buf1 ;
	delete[] buf2 ;

	return TRUE ;
}
// 指定のキャプションに前方一致するウィンドウハンドルを取得します
HWND GetWindowHandleByCaption( const std::string& in_caption )
{
	WindowInfo info = WindowInfo( NULL, in_caption, "" ) ;

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

	return info.handle ;
}

// コールバック関数用のパラメータ
struct GetChildWindowHandleByClassNameParam
{
	WindowInfo info ;		// ウィンドウ情報

	// コンストラクタ
	GetChildWindowHandleByClassNameParam()
		:info( WindowInfo() )
	{}
	GetChildWindowHandleByClassNameParam( const WindowInfo& p_info )
		:info( p_info )
	{}
} ;
// コールバック関数
BOOL CALLBACK GetChildWindowHandleByClassNameCallBack( HWND hWnd, LPARAM lParam )
{
	char* buf1 = new char[256] ;
	char* buf2 = new char[256] ;

	// ウインドウの文字を取得
	::GetWindowText( hWnd, buf1, 256 ) ;
	::GetClassName( hWnd, buf2, 256 ) ;

	// 一致したら戻り値を設定して列挙終了
	if( IsStringStartWith( buf2, ((GetChildWindowHandleByClassNameParam*)lParam)->info.className ) )
	{
		// 一致したら戻り値を設定して列挙終了
		((GetChildWindowHandleByClassNameParam*)lParam)->info.handle	= hWnd ;
		((GetChildWindowHandleByClassNameParam*)lParam)->info.caption	= buf1 ;

		delete[] buf1 ;
		delete[] buf2 ;

		return FALSE ;
	}

	delete[] buf1 ;
	delete[] buf2 ;

	return TRUE ;
}
// 親ウィンドウに存在する子ウィンドウハンドルをクラス名から求めます
HWND GetChildWindowHandleByClassName( const HWND& parentWindowHandle, const std::string& in_windowClassName )
{
	WindowInfo info = WindowInfo( NULL, "", in_windowClassName ) ;
	GetChildWindowHandleByClassNameParam param = GetChildWindowHandleByClassNameParam( info ) ;

	::EnumChildWindows( parentWindowHandle, GetChildWindowHandleByClassNameCallBack, (LPARAM)&param ) ;

	return param.info.handle ;
}

// 処理本体です
bool Proc()
{
	//***********************************************************************
	// 管理コンソールというやつを起動してから実行してください(^v^)
	// (C:\Windows\System32\mmc.exe)
	//***********************************************************************

	//-----------------------------------------------------------------------
	// アプリケーションのウィンドウハンドルを取得する
	//-----------------------------------------------------------------------
	// キャプションから前方一致で探してきます
	const HWND windowHandle = GetWindowHandleByCaption( "コンソール1 - [コンソール ルート]" ) ;
	// ハンドルが取得できなければ終了
	if( windowHandle == NULL )
	{
		std::cout << "キャプションが前方一致するウィンドウを見つけられません" << std::endl ;
		std::cout << "C:\\Windows\\System32\\mmc.exeが起動されていないと思われます" << std::endl ;
		return false ;
	}
	std::cout << "(^o^)アプリケーションのウィンドウハンドルありましたよ" << std::endl ;

	//-----------------------------------------------------------------------
	// アプリケーションをアクティブにする
	//-----------------------------------------------------------------------
	::SetForegroundWindow( windowHandle ) ;

	//-----------------------------------------------------------------------
	// ツールバーのウィンドウハンドルを取得する
	//-----------------------------------------------------------------------
	// ツールバーをクラス名から前方一致で探してきます
	const HWND toolbarWinHandle = GetChildWindowHandleByClassName( windowHandle, "ToolbarWindow32" ) ;
	// ハンドルが取得できなければ終了
	if( toolbarWinHandle == NULL ){ return false ; }
	std::cout << "(^o^)ツールバーのウィンドウハンドルありましたよ" << std::endl ;
	
	//-----------------------------------------------------------------------
	// ツールバーのメニューハンドルを取得する
	//-----------------------------------------------------------------------
	// ウィンドウハンドルからメニューハンドルを取得します
	HMENU menuHandle = ::GetMenu( toolbarWinHandle ) ;
	// ハンドルが取得できなければ終了
	if( menuHandle == NULL ){ return false ; }
	std::cout << "(^o^)ツールバーのメニューハンドルありましたよ" << std::endl ;

	//-----------------------------------------------------------------------
	// アイテム数をカウントする
	//-----------------------------------------------------------------------
	std::cout << "ツールバーのメニューのアイテム数をカウントしてみます…" << std::endl ;
	
	//***********************************************************************
	// ここで事象が発生しますがどうすればいいのかわかりません
	//***********************************************************************
	const int itemNum = ::GetMenuItemCount( menuHandle ) ;	// ←これでは駄目なようです
	if( itemNum <= -1 )
	{
		std::cout << "ぐ・・エラーです(((><)))ガタガタブルブル" << std::endl ;
		//std::cout << GetLastErrorMessage() << std::endl ;
		return false ;
	}

	//-----------------------------------------------------------------------
	// 処理終了する
	//-----------------------------------------------------------------------
	std::cout << "正常終了ですよ(^v^)" << std::endl ;

	return true ;
}

// 
int main()
{
	// 処理実施
	Proc() ;

    std::cin.ignore() ;
	return 0 ;
}
よろしくお願いしますm(__)m

閉鎖

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