質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MFC

MFC (Microsoft Fouondation Class)とは、MicrosoftがVC++用に開発したWindows用アプリケーションのフレームワークです。

Windows 7

Microsoft Windows 7は過去にリリースされたMicrosoft WindowsのOSであり、Windows8の1代前です。2009年の7月にリリースされ販売されました。Windows7の前はWindowsVistaで、その更に3年前にリリースされました。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

7752閲覧

MFCから他のアプリケーションのメニューバーを操作したい

notgoodpg

総合スコア37

MFC

MFC (Microsoft Fouondation Class)とは、MicrosoftがVC++用に開発したWindows用アプリケーションのフレームワークです。

Windows 7

Microsoft Windows 7は過去にリリースされたMicrosoft WindowsのOSであり、Windows8の1代前です。2009年の7月にリリースされ販売されました。Windows7の前はWindowsVistaで、その更に3年前にリリースされました。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/01/23 02:54

編集2018/01/24 06:08

###まとめ

  • Win32APIでフォームアプリのメニューバーを選択したいときはSendMessage(hWnd, WM_COMMAND, 選択したいメニュー項目のID, 0);
  • 選択したいメニュー項目のIDは、GetMenuItemInfo関数を使うが、なんとこの関数、引数のMENUITEMINFO構造体のfTypeに指定した一項目ずつしか情報を取ってこない。
  • なのでほしい情報が集まるまでfTypeを変更しつつ何度もGetMenuItemInfoを投げなくてはならない。
  • GetMenuItemInfoMENUITEMINFOにうまく情報を入れられなかった場合は0を返すので条件分岐はする。
  • MFCのC~DlgクラスではWin32APIに呼びかける関数を使おうとするとマクロで別の処理に切り替わります。とりあえず::を使って名前空間を明示的に指定することでどうにか目的の関数を呼べるようになる。

GetMenuItemInfo(MSDN)
MSDNのサイトで不足情報はここ参照

###前提・実現したいこと
MFCから他のアプリケーションのメニューバーを操作したい。
この質問のベストアンサーを参考に
Windows7標準搭載の電卓アプリをC++/MFCアプリから操作しようとしています。

電卓アプリのHWNDを取得 →HWNDからメニューバーのHMENUを取得 →HMENUからMENUITEMINFOを取得 →dwTypeDataから項目名"表示"と合致するかチェック →hSubMenuでサブメニューのHMENUを取得 →HMENUからMENUITEMINFOを取得 →dwTypeDataから項目名"プログラマ"と合致するかチェック →メニューバーのプログラマ(P)の項目のIDを取得 →SendMessageで選択を実行

という流れで処理を行おうとしたのですがdwTypeDataと項目名を比較しようとすると

0x000007FEEA1F8F22(ucrtbased.dll)で例外がスローされました

1(UIAuto.exe 内): 0xC0000005: 場所 0xFFFFFFFFFFFFFFFF の読み取り中にアクセス違反が発生しました 2この例外のハンドラーがある場合は、プログラムを安全に実行できます。 3```~~と例外が投げられます。(文字列の先頭アドレスが指定されないからでしょうか) 4HMENUをデバッガで確認すると`<メモリを読み取れません>`と表示されており 5たしかに処理できそうに見えません。~~ 6 7~~そこで、HMENUを正しく取得する方法 8もしくはHMENUを利用するほかに他のアプリケーションのメニューバーを操作する方法 9をご教授いただきたいです。 10よろしくお願いいたします。~~ 11上記の打ち消し線部の問題が解決すれば目的の動作を達成すると思っていました。 12ですがどうも動いている様子がありませんので質問を 13- MENUITEMINFOの取得方法 14- メニューバーの項目の選択方法(SendMessageで何のコマンドを利用すればよいか) 15に変え、引き続きお知恵をお貸しいただけますようお願いいたします。 16 17###該当のソースコード 18// 2018 0123 1727 ご指摘を受けて修正 修正前の内容は編集履歴をご確認ください 19// 2018 0124 1105 メニューに表示されいる文字列は取得できました 修正前の内容は編集履歴をご確認ください 20// 2018 0124 1430 これで動くはず 修正前の内容は編集履歴をご確認ください 21// 2018 0124 1500 これを直してる場合じゃない 修正前の内容は編集履歴をご確認ください 22```c++ 23void CUIAutoDlg::OnBnClickedOk() 24{ 25 HWND hWnd = ::FindWindow(_T("CalcFrame"), _T("電卓")); 26 27 if (hWnd == NULL) { 28 MessageBox(_T("電卓が閉じてるとかそういう理由でウィンドウハンドラが取れなかった"), NULL, 0); 29 return; 30 } 31 32 ::SetForegroundWindow(hWnd); 33 34 HMENU hMen = ::GetMenu(hWnd); // cWnd->GetMenu(); 35 if (hMen == NULL) { 36 MessageBox(_T("この電卓、メニューバーのウィンドウハンドラがないぞ・・・"), NULL, 0); 37 return; 38 } 39 40 MENUITEMINFO mii; 41 if (GetSubMenuInfo(hWnd, hMen, &mii, _T("表示(&V")) == FALSE) return; 42 if (GetSubMenuInfo(hWnd, mii.hSubMenu, &mii, _T("プログラマ(&P) Alt+")) == FALSE) return; 43 ::PostMessage(hWnd, WM_COMMAND, mii.wID, 0); 44} 45// メニューバーから目的の項目を見つける 46// 目的の項目の情報をMENUITEMINFOとして返す 47BOOL CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd, MENUITEMINFO* mii,const CString menTitle) { 48 if (menHnd == NULL) return FALSE; 49 50 mii->cbSize = sizeof(MENUITEMINFO); 51 int menuCnt = ::GetMenuItemCount(menHnd); 52 std::wstring buffer; 53 for (int i = 0; i < menuCnt; ++i) { 54 // 文字列取得 55 mii->fMask = MIIM_STRING; 56 mii->cch = 0; 57 if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue; 58 buffer.resize(mii->cch); 59 mii->dwTypeData = NULL; 60 mii->dwTypeData = &buffer[0]; 61 if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue; 62 63 if (mii->dwTypeData == menTitle) { 64 // ID取得 65 mii->fMask = MIIM_ID; 66 mii->wID = -1; 67 if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue; 68 // サブメニューハンドラ取得 69 mii->fMask = MIIM_SUBMENU; 70 mii->hSubMenu = NULL; 71 if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue; 72 73 return TRUE; 74 } 75 } 76 return FALSE; 77}

GetMenuItemInfo(MSDN)とかMENUITEMINFOについて解説してるサイトを見ながら修正

###試したこと
現状の方法で改善の方向性が見出せないため他の方法を探してみています。
wIDとして取得できた値でWM_COMMAND以外のコマンドをいろいろSendMessageしてみています。
以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です
###補足情報(言語/FW/ツール等のバージョンなど)

  • Windows7/64 SP1
  • VisualStudio2015 SP
  • VC++/MFC

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PineMatsu

2018/01/23 08:11

最初のFindWindowだけど、::FindWindowとWin32 APIを使わないといけないと思います。アプリ全体をMFCで組むのは良いけど、電卓アプリを操作する所は全てWin32 APIでということ。
notgoodpg

2018/01/23 08:19

ご指摘ありがとうございます。ですが、”、::FindWindowとWin32 APIを使わないといけないと思います。”によりどのような修正を加えるべきかわかりません。::FindWindowは飽くまでMFCの命令で、Win32APIに対して同じ処理をさせる命令が他にあり、それを呼ばなくてはならないということでしょうか?勉強不足で申し訳ありません。
PineMatsu

2018/01/23 08:24

MFCのCWnd::FindWindow()とWin32のFindWindowは違いますよ。Win32の::FindWindowはHWNDを返します。CWnd::FindWindwはCWndへのポインターを返します。
notgoodpg

2018/01/23 08:30

ありがとうございます。ご指摘頂いた点について修正を行いました。これで大丈夫でしょうか? ご報告まで、今回の修正で現象に変化は見られませんでした
guest

回答1

0

ベストアンサー

質問欄じゃ書ききれないので回答欄に書くことにします。

C++

1if (mii.dwTypeData == menTitle) {

↑ここでエラーということなのでMENUITEMINFOについて調べてみました。

MENUITEMINFO

dwTypeDataメンバーはfTypeメンバーに依存して変わるとあるので、それを調べてから処理しないといけないようです。
詳しくは上記のURLを参照してください。

投稿2018/01/23 09:00

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

notgoodpg

2018/01/24 01:40 編集

ご回答ありがとうございます。 MENUITEMINFOの仕様は調査不足でした。 そこで、よく見てみるとfType,fMask,fStateも3435973836と見るからにおかしそうな値になっていました さらに詳しくMENUITEMINFO取得周りを調べてみます
notgoodpg

2018/01/24 02:25

ご指摘のお陰でMENUITEMINFOを取得できるようになったと思います。ありがとうございました。 お陰様でかなり進展を得られたことは確かなのですが、表題の動作が最終目標ですのでベストアンサーに選ぶことは出来ないかもしれません・・・ご容赦ください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問