teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

18

あああ

2018/01/24 06:08

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -1,7 +1,7 @@
1
1
  ###まとめ
2
2
  - Win32APIでフォームアプリのメニューバーを選択したいときは`SendMessage(hWnd, WM_COMMAND, 選択したいメニュー項目のID, 0);`
3
- - 選択したいメニュー項目のIDは、`GetMenuItemInfo`関数を使うが、**なんとこの関数、引数のMENUITEMINFO構造体のfTypeに指定した一項目ずつしか情報を取ってこない。**
3
+ - 選択したいメニュー項目のIDは、`GetMenuItemInfo`関数を使うが、**なんとこの関数、引数の`MENUITEMINFO`構造体の`fType`に指定した一項目ずつしか情報を取ってこない。**
4
- - なのでほしい情報が集まるまでfTypeを変更しつつ何度も`GetMenuItemInfo`を投げなくてはならない。
4
+ - なのでほしい情報が集まるまで`fType`を変更しつつ何度も`GetMenuItemInfo`を投げなくてはならない。
5
5
  - `GetMenuItemInfo`は`MENUITEMINFO`にうまく情報を入れられなかった場合は0を返すので条件分岐はする。
6
6
  - MFCの`C~Dlg`クラスでは**Win32APIに呼びかける関数を使おうとするとマクロで別の処理に切り替わり**ます。とりあえず`::`を使って名前空間を明示的に指定することでどうにか目的の関数を呼べるようになる。
7
7
  [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)
@@ -44,69 +44,62 @@
44
44
  // 2018 0123 1727 ご指摘を受けて修正 修正前の内容は編集履歴をご確認ください
45
45
  // 2018 0124 1105 メニューに表示されいる文字列は取得できました 修正前の内容は編集履歴をご確認ください
46
46
  // 2018 0124 1430 これで動くはず 修正前の内容は編集履歴をご確認ください
47
+ // 2018 0124 1500 これを直してる場合じゃない 修正前の内容は編集履歴をご確認ください
47
48
  ```c++
48
49
  void CUIAutoDlg::OnBnClickedOk()
49
50
  {
50
- // TODO: ここにコントロール通知ハンドラー コードを追加します。
51
- // 電卓のウィンドウを最善面に移動
52
- const CString prgNm = _T("電卓");
53
- const CString prgClsNm = _T("CalcFrame");
51
+ HWND hWnd = ::FindWindow(_T("CalcFrame"), _T("電卓"));
54
52
 
55
- CWnd* cWnd = FindWindow(prgClsNm, prgNm);
53
+ if (hWnd == NULL) {
54
+ MessageBox(_T("電卓が閉じてるとかそういう理由でウィンドウハンドラが取れなかった"), NULL, 0);
55
+ return;
56
+ }
56
57
 
57
- try {
58
+ ::SetForegroundWindow(hWnd);
59
+
58
- if (cWnd == NULL) throw std::exception("cant find calc.");
60
+ HMENU hMen = ::GetMenu(hWnd); // cWnd->GetMenu();
59
- }
60
- catch(std::exception e){
61
+ if (hMen == NULL) {
61
- MessageBox(CString(e.what()), NULL, 0);
62
+ MessageBox(_T("この電卓、メニューバーのウィンドウハンドラがないぞ・・・"), NULL, 0);
62
63
  return;
63
64
  }
64
- cWnd->SetForegroundWindow();
65
- // メニューバーを操作
66
- HWND hWnd = ::FindWindow(prgClsNm, prgNm);
67
- HMENU hMen = ::GetMenu(hWnd);
68
- if(hMen == NULL)return; // メニューバーが無ければここで抜け
69
65
 
66
+ MENUITEMINFO mii;
70
- MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(&V"));
67
+ if (GetSubMenuInfo(hWnd, hMen, &mii, _T("表示(&V")) == FALSE) return;
71
- mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P) Alt+")); // *これ、デバッガから適当にコピーしたけど\tとか含んでるのでクソめんどくさい文字列
68
+ if (GetSubMenuInfo(hWnd, mii.hSubMenu, &mii, _T("プログラマ(&P) Alt+")) == FALSE) return;
72
- ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0);
69
+ ::PostMessage(hWnd, WM_COMMAND, mii.wID, 0);
73
70
  }
74
71
  // メニューバーから目的の項目を見つける
75
72
  // 目的の項目の情報をMENUITEMINFOとして返す
76
- MENUITEMINFO CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd,const CString menTitle)
73
+ BOOL CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd, MENUITEMINFO* mii,const CString menTitle) {
77
- {
78
- if (menHnd == NULL) return MENUITEMINFO();
74
+ if (menHnd == NULL) return FALSE;
79
75
 
76
+ mii->cbSize = sizeof(MENUITEMINFO);
80
77
  int menuCnt = ::GetMenuItemCount(menHnd);
81
- std::wstring buffer; // メニュー表示文字列受け取りバッファ
78
+ std::wstring buffer;
82
- MENUITEMINFO mii;
83
-
84
- mii.cbSize = sizeof(MENUITEMINFO); // 構造体サイズらしい。なんとなく初期化
85
-
86
79
  for (int i = 0; i < menuCnt; ++i) {
87
- // メニュー項目の文字列取得
80
+ // 文字列取得
88
- mii.fMask = MIIM_STRING; // メニュー項目の文字列を取得するよう設定
81
+ mii->fMask = MIIM_STRING;
89
- mii.cch = 0; // 文字列長を一旦0で初期化
82
+ mii->cch = 0;
90
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列長を取得
83
+ if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue;
91
- buffer.resize(mii.cch); // バッファサイズの指定
84
+ buffer.resize(mii->cch);
92
- mii.dwTypeData = NULL;
85
+ mii->dwTypeData = NULL;
93
- mii.dwTypeData = &buffer[0]; // バッファのアドレスを与える
86
+ mii->dwTypeData = &buffer[0];
94
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列を取得
87
+ if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue;
95
88
 
96
- if (mii.dwTypeData == menTitle) { // 項目名を比較(完全一致じゃ書きづらくて仕方が無いので.Contains相当のロジックを組まなくては)
89
+ if (mii->dwTypeData == menTitle) {
97
- // メニュー項目のID取得
90
+ // ID取得
98
- mii.fMask = MIIM_ID; // メニュー項目のIDを取得するよう変更
91
+ mii->fMask = MIIM_ID;
99
- mii.wID = -1;
92
+ mii->wID = -1;
100
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行でIDを取得
101
- // サブメニューのウィンドウハンドラを取得
102
- mii.fMask = MIIM_SUBMENU; // サブメニューのウィンドウハンドラを取得するよう変更
103
- mii.hSubMenu = NULL;
104
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue;
93
+ if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue;
105
-
94
+ // サブメニューハンドラ取得
95
+ mii->fMask = MIIM_SUBMENU;
96
+ mii->hSubMenu = NULL;
97
+ if (::GetMenuItemInfo(menHnd, i, 1, mii) == 0) continue;
98
+
106
- return mii;
99
+ return TRUE;
107
100
  }
108
101
  }
109
- return MENUITEMINFO();
102
+ return FALSE;
110
103
  }
111
104
  ```
112
105
  [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)とか[MENUITEMINFOについて解説してるサイト](http://chokuto.ifdef.jp/urawaza/struct/MENUITEMINFO.html)を見ながら修正

17

ちょっと直した

2018/01/24 06:08

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -1,9 +1,12 @@
1
1
  ###まとめ
2
2
  - Win32APIでフォームアプリのメニューバーを選択したいときは`SendMessage(hWnd, WM_COMMAND, 選択したいメニュー項目のID, 0);`
3
- - 選択したいメニュー項目のIDは、`GetMenuItemInfo`関数を使うが、**なんとこの関数、fTypeに指定した一項目ずつしか情報を取ってこない。**
3
+ - 選択したいメニュー項目のIDは、`GetMenuItemInfo`関数を使うが、**なんとこの関数、引数のMENUITEMINFO構造体のfTypeに指定した一項目ずつしか情報を取ってこない。**
4
- - なのでほしい情報が集まるまでfTypeを変更しつつ何度も`GetMenuItemInfo`を投げ
4
+ - なのでほしい情報が集まるまでfTypeを変更しつつ何度も`GetMenuItemInfo`を投げなくてはならない
5
5
  - `GetMenuItemInfo`は`MENUITEMINFO`にうまく情報を入れられなかった場合は0を返すので条件分岐はする。
6
- - MFCの`C~Dlg`クラスでは**Win32APIに呼びかける関数を使おうとするとマクロで別の処理に切り替わり**ます。とりあえず`::`を使って名前空間を明示的に指定すればどうにか呼べます
6
+ - MFCの`C~Dlg`クラスでは**Win32APIに呼びかける関数を使おうとするとマクロで別の処理に切り替わり**ます。とりあえず`::`を使って名前空間を明示的に指定することでどうにか目的の関数を呼べるようになる
7
+ [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)
8
+ [MSDNのサイトで不足情報はここ参照](http://chokuto.ifdef.jp/urawaza/struct/MENUITEMINFO.html)
9
+
7
10
  ###前提・実現したいこと
8
11
  MFCから他のアプリケーションのメニューバーを操作したい。
9
12
  [この質問のベストアンサー](https://oshiete.goo.ne.jp/qa/5240712.html)を参考に

16

更新のメッセージを入れ忘れた

2018/01/24 05:40

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -40,6 +40,7 @@
40
40
  ###該当のソースコード
41
41
  // 2018 0123 1727 ご指摘を受けて修正 修正前の内容は編集履歴をご確認ください
42
42
  // 2018 0124 1105 メニューに表示されいる文字列は取得できました 修正前の内容は編集履歴をご確認ください
43
+ // 2018 0124 1430 これで動くはず 修正前の内容は編集履歴をご確認ください
43
44
  ```c++
44
45
  void CUIAutoDlg::OnBnClickedOk()
45
46
  {

15

まとめました

2018/01/24 05:30

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -1,3 +1,9 @@
1
+ ###まとめ
2
+ - Win32APIでフォームアプリのメニューバーを選択したいときは`SendMessage(hWnd, WM_COMMAND, 選択したいメニュー項目のID, 0);`
3
+ - 選択したいメニュー項目のIDは、`GetMenuItemInfo`関数を使うが、**なんとこの関数、fTypeに指定した一項目ずつしか情報を取ってこない。**
4
+ - なのでほしい情報が集まるまでfTypeを変更しつつ何度も`GetMenuItemInfo`を投げる。
5
+ - `GetMenuItemInfo`は`MENUITEMINFO`にうまく情報を入れられなかった場合は0を返すので条件分岐はする。
6
+ - MFCの`C~Dlg`クラスでは**Win32APIに呼びかける関数を使おうとするとマクロで別の処理に切り替わり**ます。とりあえず`::`を使って名前空間を明示的に指定すればどうにか呼べます。
1
7
  ###前提・実現したいこと
2
8
  MFCから他のアプリケーションのメニューバーを操作したい。
3
9
  [この質問のベストアンサー](https://oshiete.goo.ne.jp/qa/5240712.html)を参考に
@@ -58,9 +64,8 @@
58
64
  if(hMen == NULL)return; // メニューバーが無ければここで抜け
59
65
 
60
66
  MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(&V"));
67
+ mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P) Alt+")); // *これ、デバッガから適当にコピーしたけど\tとか含んでるのでクソめんどくさい文字列
61
- ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0); // 表示を選ぼうとしているが出来てない
68
+ ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0);
62
- mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P"));
63
- ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0); // まず表示を選ばないとこれも意味が無い
64
69
  }
65
70
  // メニューバーから目的の項目を見つける
66
71
  // 目的の項目の情報をMENUITEMINFOとして返す
@@ -75,19 +80,25 @@
75
80
  mii.cbSize = sizeof(MENUITEMINFO); // 構造体サイズらしい。なんとなく初期化
76
81
 
77
82
  for (int i = 0; i < menuCnt; ++i) {
83
+ // メニュー項目の文字列を取得
78
84
  mii.fMask = MIIM_STRING; // メニュー項目の文字列を取得するよう設定
79
85
  mii.cch = 0; // 文字列長を一旦0で初期化
80
86
  if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列長を取得
81
-
82
87
  buffer.resize(mii.cch); // バッファサイズの指定
83
88
  mii.dwTypeData = NULL;
84
89
  mii.dwTypeData = &buffer[0]; // バッファのアドレスを与える
85
90
  if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列を取得
86
91
 
87
- if (mii.dwTypeData == menTitle) {
92
+ if (mii.dwTypeData == menTitle) { // 項目名を比較(完全一致じゃ書きづらくて仕方が無いので.Contains相当のロジックを組まなくては)
93
+ // メニュー項目のIDを取得
88
94
  mii.fMask = MIIM_ID; // メニュー項目のIDを取得するよう変更
89
95
  mii.wID = -1;
90
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行でIDを取得
96
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行でIDを取得
97
+ // サブメニューのウィンドウハンドラを取得
98
+ mii.fMask = MIIM_SUBMENU; // サブメニューのウィンドウハンドラを取得するよう変更
99
+ mii.hSubMenu = NULL;
100
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue;
101
+
91
102
  return mii;
92
103
  }
93
104
  }

14

質問をちょっと修正

2018/01/24 05:28

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -27,8 +27,8 @@
27
27
  よろしくお願いいたします。~~
28
28
  上記の打ち消し線部の問題が解決すれば目的の動作を達成すると思っていました。
29
29
  ですがどうも動いている様子がありませんので質問を
30
- MENUITEMINFOの取得方法
30
+ - MENUITEMINFOの取得方法
31
- メニューバーの項目の選択方法
31
+ - メニューバーの項目の選択方法(SendMessageで何のコマンドを利用すればよいか)
32
32
  に変え、引き続きお知恵をお貸しいただけますようお願いいたします。
33
33
 
34
34
  ###該当のソースコード

13

何度も直して申し訳ない

2018/01/24 04:56

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -58,9 +58,9 @@
58
58
  if(hMen == NULL)return; // メニューバーが無ければここで抜け
59
59
 
60
60
  MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(&V"));
61
- ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0); // 表示を選ぼうとしているが出来てない
61
+ ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0); // 表示を選ぼうとしているが出来てない
62
62
  mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P"));
63
- ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0); // まず表示を選ばないとこれも意味が無い
63
+ ::SendMessage(hWnd, WM_COMMAND, mii.wID, 0); // まず表示を選ばないとこれも意味が無い
64
64
  }
65
65
  // メニューバーから目的の項目を見つける
66
66
  // 目的の項目の情報をMENUITEMINFOとして返す

12

試したこと を更新し忘れていたので更新。

2018/01/24 02:39

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -97,7 +97,8 @@
97
97
  [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)とか[MENUITEMINFOについて解説してるサイト](http://chokuto.ifdef.jp/urawaza/struct/MENUITEMINFO.html)を見ながら修正
98
98
 
99
99
  ###試したこと
100
- 現状の方法で改善の方向性が見出せないため他の方法を探してみています。
100
+ ~~現状の方法で改善の方向性が見出せないため他の方法を探してみています。~~
101
+ `wID`として取得できた値で`WM_COMMAND`以外のコマンドをいろいろ`SendMessage`してみています。
101
102
  以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です
102
103
  ###補足情報(言語/FW/ツール等のバージョンなど)
103
104
  - Windows7/64 SP1

11

コピーし忘れ部分を修正

2018/01/24 02:27

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -39,8 +39,11 @@
39
39
  {
40
40
  // TODO: ここにコントロール通知ハンドラー コードを追加します。
41
41
  // 電卓のウィンドウを最善面に移動
42
+ const CString prgNm = _T("電卓");
42
- CWnd* cWnd = FindWindow(_T("CalcFrame"), _T("電卓"));
43
+ const CString prgClsNm = _T("CalcFrame");
43
44
 
45
+ CWnd* cWnd = FindWindow(prgClsNm, prgNm);
46
+
44
47
  try {
45
48
  if (cWnd == NULL) throw std::exception("cant find calc.");
46
49
  }
@@ -50,13 +53,14 @@
50
53
  }
51
54
  cWnd->SetForegroundWindow();
52
55
  // メニューバーを操作
53
- HWND hWnd = ::FindWindow(_T("CalcFrame"), _T("電卓"));
56
+ HWND hWnd = ::FindWindow(prgClsNm, prgNm);
54
- HMENU hMen = ::GetMenu(hWnd); // HMENUの中身が本当に無いならNULLが返るので
57
+ HMENU hMen = ::GetMenu(hWnd);
55
- if(hMen == NULL)return; // ここで抜けるはず
58
+ if(hMen == NULL)return; // メニューバーが無ければここで抜け
56
- // ところが上のチェックをパスしたにもかかわらず次の処理で例外を投げている
59
+
57
60
  MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(&V"));
61
+ ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0); // 表示を選ぼうとしているが出来てない
58
62
  mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P"));
59
- ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
63
+ ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0); // まず表示を選ばないとこれも意味が無い
60
64
  }
61
65
  // メニューバーから目的の項目を見つける
62
66
  // 目的の項目の情報をMENUITEMINFOとして返す

10

MENUITEMINFOを取得する処理が動いたのでコードを修正

2018/01/24 02:13

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -12,22 +12,29 @@
12
12
  →dwTypeDataから項目名"プログラマ"と合致するかチェック
13
13
  →メニューバーのプログラマ(P)の項目のIDを取得
14
14
  →SendMessageで選択を実行
15
+ ```
15
- ```という流れで処理を行おうとしたのですがdwTypeDataと項目名を比較しようとすると
16
+ ~~という流れで処理を行おうとしたのですがdwTypeDataと項目名を比較しようとすると~~
16
17
  ```0x000007FEEA1F8F22(ucrtbased.dll)で例外がスローされました
17
18
  (UIAuto.exe 内): 0xC0000005: 場所 0xFFFFFFFFFFFFFFFF の読み取り中にアクセス違反が発生しました
18
19
  この例外のハンドラーがある場合は、プログラムを安全に実行できます。
19
- ```と例外が投げられます。(文字列の先頭アドレスが指定されないからでしょうか)
20
+ ```~~と例外が投げられます。(文字列の先頭アドレスが指定されないからでしょうか)
20
21
  HMENUをデバッガで確認すると`<メモリを読み取れません>`と表示されており
21
- たしかに処理できそうに見えません。
22
+ たしかに処理できそうに見えません。~~
22
23
 
23
- そこで、HMENUを正しく取得する方法
24
+ ~~そこで、HMENUを正しく取得する方法
24
25
  もしくはHMENUを利用するほかに他のアプリケーションのメニューバーを操作する方法
25
26
  をご教授いただきたいです。
26
- よろしくお願いいたします。
27
+ よろしくお願いいたします。~~
28
+ 上記の打ち消し線部の問題が解決すれば目的の動作を達成すると思っていました。
29
+ ですがどうも動いている様子がありませんので質問を
30
+ MENUITEMINFOの取得方法
31
+ メニューバーの項目の選択方法
32
+ に変え、引き続きお知恵をお貸しいただけますようお願いいたします。
27
33
 
28
34
  ###該当のソースコード
29
- ```ここに言語を入力
30
35
  // 2018 0123 1727 ご指摘を受けて修正 修正前の内容は編集履歴をご確認ください
36
+ // 2018 0124 1105 メニューに表示されいる文字列は取得できました 修正前の内容は編集履歴をご確認ください
37
+ ```c++
31
38
  void CUIAutoDlg::OnBnClickedOk()
32
39
  {
33
40
  // TODO: ここにコントロール通知ハンドラー コードを追加します。
@@ -47,32 +54,40 @@
47
54
  HMENU hMen = ::GetMenu(hWnd); // HMENUの中身が本当に無いならNULLが返るので
48
55
  if(hMen == NULL)return; // ここで抜けるはず
49
56
  // ところが上のチェックをパスしたにもかかわらず次の処理で例外を投げている
50
- MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(V)"));
57
+ MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(&V"));
51
- mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(P)"));
58
+ mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(&P"));
52
59
  ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
53
60
  }
54
61
  // メニューバーから目的の項目を見つける
55
62
  // 目的の項目の情報をMENUITEMINFOとして返す
56
63
  MENUITEMINFO CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd,const CString menTitle)
57
64
  {
65
+ if (menHnd == NULL) return MENUITEMINFO();
66
+
67
+ int menuCnt = ::GetMenuItemCount(menHnd);
68
+ std::wstring buffer; // メニュー表示文字列受け取りバッファ
58
69
  MENUITEMINFO mii;
70
+
59
- int menuCnt = ::GetMenuItemCount(menHnd);
71
+ mii.cbSize = sizeof(MENUITEMINFO); // 構造体サイズらしい。なんとなく初期化
72
+
60
73
  for (int i = 0; i < menuCnt; ++i) {
61
- mii.fMask = MIIM_FTYPE; // 追記
74
+ mii.fMask = MIIM_STRING; // メニュー項目の文字列を取得するよう設定
62
- mii.fType = MFT_STRING; // 追記
63
- mii.cch = 0; // 追記
75
+ mii.cch = 0; // 文字列長を一旦0で初期化
76
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列長を取得
77
+
78
+ buffer.resize(mii.cch); // バッファサイズの指定
79
+ mii.dwTypeData = NULL;
80
+ mii.dwTypeData = &buffer[0]; // バッファのアドレスを与える
64
- if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) {
81
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行で文字列を取得
65
- continue; // 取得失敗なら以下の処理は飛ばす
66
- }
67
82
 
83
+ if (mii.dwTypeData == menTitle) {
84
+ mii.fMask = MIIM_ID; // メニュー項目のIDを取得するよう変更
85
+ mii.wID = -1;
68
- // if (mii.fType != MIIM_STRING) continue; // ご指摘受けて修正 *り急ぎ
86
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) continue; // この実行でIDを取得?
69
-
70
- if (mii.dwTypeData == menTitle) { // ここでエラー dwTypeDataの指すポインタが<読み取れません>になっている
71
- // メニュー項目が目的のものなら返す
72
87
  return mii;
73
88
  }
74
89
  }
75
- return MENUITEMINFO(); // 目的の項目が見つからなければ空の構造体を返す
90
+ return MENUITEMINFO();
76
91
  }
77
92
  ```
78
93
  [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)とか[MENUITEMINFOについて解説してるサイト](http://chokuto.ifdef.jp/urawaza/struct/MENUITEMINFO.html)を見ながら修正

9

コードを慎重に見直し

2018/01/24 02:05

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -58,9 +58,14 @@
58
58
  MENUITEMINFO mii;
59
59
  int menuCnt = ::GetMenuItemCount(menHnd);
60
60
  for (int i = 0; i < menuCnt; ++i) {
61
+ mii.fMask = MIIM_FTYPE; // 追記
62
+ mii.fType = MFT_STRING; // 追記
63
+ mii.cch = 0; // 追記
61
- ::GetMenuItemInfo(menHnd, i, 1, &mii); // MENUITEMINFOの取り方に間違いがある?
64
+ if (::GetMenuItemInfo(menHnd, i, 1, &mii) == 0) {
65
+ continue; // 取得失敗なら以下の処理は飛ばす
66
+ }
62
67
 
63
- if (mii.fType != MIIM_STRING) continue; // ご指摘を受けて修正 *取り急ぎ
68
+ // if (mii.fType != MIIM_STRING) continue; // ご指摘を受けて修正 *取り急ぎ
64
69
 
65
70
  if (mii.dwTypeData == menTitle) { // ここでエラー dwTypeDataの指すポインタが<読み取れません>になっている
66
71
  // メニュー項目が目的のものなら返す
@@ -70,6 +75,7 @@
70
75
  return MENUITEMINFO(); // 目的の項目が見つからなければ空の構造体を返す
71
76
  }
72
77
  ```
78
+ [GetMenuItemInfo(MSDN)](https://msdn.microsoft.com/ja-jp/library/cc364689.aspx)とか[MENUITEMINFOについて解説してるサイト](http://chokuto.ifdef.jp/urawaza/struct/MENUITEMINFO.html)を見ながら修正
73
79
 
74
80
  ###試したこと
75
81
  現状の方法で改善の方向性が見出せないため他の方法を探してみています。

8

ちょっと修正

2018/01/24 01:25

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -60,6 +60,8 @@
60
60
  for (int i = 0; i < menuCnt; ++i) {
61
61
  ::GetMenuItemInfo(menHnd, i, 1, &mii); // MENUITEMINFOの取り方に間違いがある?
62
62
 
63
+ if (mii.fType != MIIM_STRING) continue; // ご指摘を受けて修正 *取り急ぎ
64
+
63
65
  if (mii.dwTypeData == menTitle) { // ここでエラー dwTypeDataの指すポインタが<読み取れません>になっている
64
66
  // メニュー項目が目的のものなら返す
65
67
  return mii;

7

ご指摘を受けて修正

2018/01/24 00:15

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -27,10 +27,11 @@
27
27
 
28
28
  ###該当のソースコード
29
29
  ```ここに言語を入力
30
+ // 2018 0123 1727 ご指摘を受けて修正 修正前の内容は編集履歴をご確認ください
30
31
  void CUIAutoDlg::OnBnClickedOk()
31
32
  {
32
33
  // TODO: ここにコントロール通知ハンドラー コードを追加します。
33
- // 電卓のCWnd取得
34
+ // 電卓のウィンドウ最善面に移動
34
35
  CWnd* cWnd = FindWindow(_T("CalcFrame"), _T("電卓"));
35
36
 
36
37
  try {
@@ -40,14 +41,14 @@
40
41
  MessageBox(CString(e.what()), NULL, 0);
41
42
  return;
42
43
  }
43
-
44
44
  cWnd->SetForegroundWindow();
45
45
  // メニューバーを操作
46
+ HWND hWnd = ::FindWindow(_T("CalcFrame"), _T("電卓"));
46
- HMENU hMen = ::GetMenu(cWnd->GetSafeHwnd()); // HMENUの中身が本当に無いならNULLが返るので
47
+ HMENU hMen = ::GetMenu(hWnd); // HMENUの中身が本当に無いならNULLが返るので
47
48
  if(hMen == NULL)return; // ここで抜けるはず
48
49
  // ところが上のチェックをパスしたにもかかわらず次の処理で例外を投げている
49
- MENUITEMINFO mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), hMen, _T("表示(V)"));
50
+ MENUITEMINFO mii = GetSubMenuInfo(hWnd , hMen, _T("表示(V)"));
50
- mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), mii.hSubMenu, _T("プログラマ(P)"));
51
+ mii = GetSubMenuInfo(hWnd ,mii.hSubMenu, _T("プログラマ(P)"));
51
52
  ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
52
53
  }
53
54
  // メニューバーから目的の項目を見つける

6

泣き言を消しました

2018/01/23 08:28

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -70,8 +70,7 @@
70
70
 
71
71
  ###試したこと
72
72
  現状の方法で改善の方向性が見出せないため他の方法を探してみています。
73
- 以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です。__にほんごの資料が少なく難航してます__
73
+ 以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です
74
-
75
74
  ###補足情報(言語/FW/ツール等のバージョンなど)
76
75
  - Windows7/64 SP1
77
76
  - VisualStudio2015 SP

5

文面を少し修正

2018/01/23 07:47

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -21,7 +21,8 @@
21
21
  たしかに処理できそうに見えません。
22
22
 
23
23
  そこで、HMENUを正しく取得する方法
24
- もしくはHMENUを利用するほかに他のアプリケーションのメニューバーを操作する方法をご教授いただきたいです。
24
+ もしくはHMENUを利用するほかに他のアプリケーションのメニューバーを操作する方法
25
+ をご教授いただきたいです。
25
26
  よろしくお願いいたします。
26
27
 
27
28
  ###該当のソースコード
@@ -58,7 +59,7 @@
58
59
  for (int i = 0; i < menuCnt; ++i) {
59
60
  ::GetMenuItemInfo(menHnd, i, 1, &mii); // MENUITEMINFOの取り方に間違いがある?
60
61
 
61
- if (mii.dwTypeData == menTitle) { // ここでエラー マトモに文字列ばLPTSTRとCStringの比較でエラーは起きない
62
+ if (mii.dwTypeData == menTitle) { // ここでエラー dwTypeDataの指すポインタ<読み取ません>にって
62
63
  // メニュー項目が目的のものなら返す
63
64
  return mii;
64
65
  }
@@ -68,8 +69,8 @@
68
69
  ```
69
70
 
70
71
  ###試したこと
71
- 他の方法を探してみていますが、とりあえず上記にあるリンク先の方法以外は何も見つけられていません
72
+ 現状の方法で改善の方向性が見出せないため他の方法を探してみています。
72
- なお、以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です。
73
+ 以前の質問でUI Automationを教えていただいており、これを用いる方法は現在調査中です。__にほんごの資料が少なく難航してます__
73
74
 
74
75
  ###補足情報(言語/FW/ツール等のバージョンなど)
75
76
  - Windows7/64 SP1

4

タグの整理整頓と少し修正

2018/01/23 07:46

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -44,7 +44,7 @@
44
44
  // メニューバーを操作
45
45
  HMENU hMen = ::GetMenu(cWnd->GetSafeHwnd()); // HMENUの中身が本当に無いならNULLが返るので
46
46
  if(hMen == NULL)return; // ここで抜けるはず
47
- // ところが上のチェックをパスしたにもかかわらず次の処理に進み例外を投げている
47
+ // ところが上のチェックをパスしたにもかかわらず次の処理例外を投げている
48
48
  MENUITEMINFO mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), hMen, _T("表示(V)"));
49
49
  mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), mii.hSubMenu, _T("プログラマ(P)"));
50
50
  ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
@@ -56,7 +56,7 @@
56
56
  MENUITEMINFO mii;
57
57
  int menuCnt = ::GetMenuItemCount(menHnd);
58
58
  for (int i = 0; i < menuCnt; ++i) {
59
- ::GetMenuItemInfo(menHnd, i, 1, &mii);
59
+ ::GetMenuItemInfo(menHnd, i, 1, &mii); // MENUITEMINFOの取り方に間違いがある?
60
60
 
61
61
  if (mii.dwTypeData == menTitle) { // ここでエラー マトモに文字列があればLPTSTRとCStringの比較でエラーは起きない
62
62
  // メニュー項目が目的のものなら返す

3

ちょっとだけ追加

2018/01/23 07:27

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -34,37 +34,35 @@
34
34
 
35
35
  try {
36
36
  if (cWnd == NULL) throw std::exception("cant find calc.");
37
-
38
37
  }
39
38
  catch(std::exception e){
40
39
  MessageBox(CString(e.what()), NULL, 0);
41
40
  return;
42
41
  }
42
+
43
43
  cWnd->SetForegroundWindow();
44
44
  // メニューバーを操作
45
- HMENU hMen = ::GetMenu(cWnd->GetSafeHwnd()); // cWnd->GetMenu();
45
+ HMENU hMen = ::GetMenu(cWnd->GetSafeHwnd()); // HMENUの中身が本当に無いならNULLが返るので
46
-
46
+ if(hMen == NULL)return; // ここで抜けるはず
47
+ // ところが上のチェックをパスしたにもかかわらず次の処理に進み例外を投げている
47
48
  MENUITEMINFO mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), hMen, _T("表示(V)"));
48
49
  mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), mii.hSubMenu, _T("プログラマ(P)"));
49
50
  ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
50
51
  }
51
52
  // メニューバーから目的の項目を見つける
52
53
  // 目的の項目の情報をMENUITEMINFOとして返す
53
- MENUITEMINFO CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd,const CString menTitle) {
54
+ MENUITEMINFO CUIAutoDlg::GetSubMenuInfo(const HWND winHnd,const HMENU menHnd,const CString menTitle)
54
-
55
+ {
55
56
  MENUITEMINFO mii;
56
57
  int menuCnt = ::GetMenuItemCount(menHnd);
57
58
  for (int i = 0; i < menuCnt; ++i) {
58
59
  ::GetMenuItemInfo(menHnd, i, 1, &mii);
59
60
 
60
- if (mii.dwTypeData == NULL) continue;
61
-
62
- if (mii.dwTypeData == menTitle) { // ここでエラー
61
+ if (mii.dwTypeData == menTitle) { // ここでエラー マトモに文字列があればLPTSTRとCStringの比較でエラーは起きない
63
62
  // メニュー項目が目的のものなら返す
64
63
  return mii;
65
64
  }
66
65
  }
67
-
68
66
  return MENUITEMINFO(); // 目的の項目が見つからなければ空の構造体を返す
69
67
  }
70
68
  ```

2

処理の流れに不足があったので追加

2018/01/23 06:20

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -10,6 +10,7 @@
10
10
  →hSubMenuでサブメニューのHMENUを取得
11
11
  →HMENUからMENUITEMINFOを取得
12
12
  →dwTypeDataから項目名"プログラマ"と合致するかチェック
13
+ →メニューバーのプログラマ(P)の項目のIDを取得
13
14
  →SendMessageで選択を実行
14
15
  ```という流れで処理を行おうとしたのですがdwTypeDataと項目名を比較しようとすると
15
16
  ```0x000007FEEA1F8F22(ucrtbased.dll)で例外がスローされました

1

未検証のIDチェックをそのまま載せちゃってたので削除(ていうか条件も < 0 だな・・・ま逆・・・

2018/01/23 05:07

投稿

notgoodpg
notgoodpg

スコア37

title CHANGED
File without changes
body CHANGED
@@ -44,9 +44,7 @@
44
44
  HMENU hMen = ::GetMenu(cWnd->GetSafeHwnd()); // cWnd->GetMenu();
45
45
 
46
46
  MENUITEMINFO mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), hMen, _T("表示(V)"));
47
- if (mii.wID >= 0)return;
48
47
  mii = GetSubMenuInfo(cWnd->GetSafeHwnd(), mii.hSubMenu, _T("プログラマ(P)"));
49
- if (mii.wID >= 0)return;
50
48
  ::SendMessage(cWnd->GetSafeHwnd(), WM_COMMAND, mii.wID, 0);
51
49
  }
52
50
  // メニューバーから目的の項目を見つける