今回はWin32の話です。
プロダクトによっては、過去の資産を持っていて、一部ネイティブで作っているものもありますよね。
そうでなくて完全な.Netのアプリでも、実はネイティブの画面は出てくるのです。
と言うことで、ネイティブの画面も操作できるようにしておく必要がありますね。
FriendlyはネイティブのDLL公開関数も実行させることができます。
ネイティブDLL公開関数の呼び出し - 株式会社Codeer (コーディア)
ただ、.Netに比べてかなり面倒です。
なので、一般的なコントロール操作に関してはラップしたライブラリを用意しています。
Friendly.Windows.NativeStandardControlsです。これをご利用ください。
APIリファレンス
ソースコード
対応表
Windowクラス | Friendly.Windows.NativeStandardControls |
---|---|
Button | NativeButton |
ComboBox、ComboBoxEx32 | NativeComboBox |
SysDateTimePick32 | NativeDateTimePicker |
Edit、RichEdit20A、RichEdit20W | NativeEdit |
IPAddress32 | NativeIPAddress |
ListBox | NativeListBox |
SysListView32 | NativeListControl |
SysMonthCal32 | NativeMonthCalendar |
msctls_progress32 | NativeProgress |
ScrollBar | NativeScrollBar |
msctls_trackbar32 | NativeSlider |
msctls_updown32 | NativeSpinButton |
SysTabControl32 | NativeTab |
SysTreeView32 | NativeTree |
特殊なものとして、メッセージボックスに対応したクラスもあります。
特殊 | Friendly.Windows.NativeStandardControls |
---|---|
メッセージボックス | NativeMessageBox |
ハンズオンの練習用プロジェクト
こちらからダウンロードしてください。ブロック解除もお願いします。
https://github.com/Ishikawa-Tatsuya/HandsOn9
対象アプリはMFCで作っています。
ビルドできない人もいるかもしれないので、ソースコードも入れていますが、exeも作っています。
対象はMFCApplication.exeです。
ListBoxとTreeViewがあります。
OKボタンを押すと、メッセージボックス(モーダル)が表示されます。
Resource.hには次のように定義されています。
ListBoxとTreeViewにそれぞれ割り当たっているダイアログIDです。あ、OKボタンにはIDOKが割り当たっています。
#define IDC_LIST 1000#define IDC_TREE 1001
テストプロジェクトはいつものように参照設定とusingまで終わっています。
自分のテストに組み込む場合はNugetからFriendly.Windows.NativeStandardControlsを取得してください。
ハンズオン開始
ListBox
まずはリストボックスです。
選択を変えてみましょう。
[TestMethod] publicvoid TestListBox() { var listBox = new NativeListBox(_dlg.IdentifyFromDialogId(IDC_LIST)); listBox.EmulateChangeCurrentSelectedIndex(3); Assert.AreEqual(3, listBox.CurrentSelectedIndex); }
.Netの場合はラッパークラスのコンストラクタの引数に対象アプリ内のコントロールのオブジェクトを渡していました。しかし、ネイティブの場合はそれがありません。渡すものは次のいずれかです。
- Windowハンドル
- WindowControl
今回の場合はWindowControlを渡しています。
それはIdentifyFromDialogIdを使って取得しています。ネイティブの場合はダイアログIDから取得するのが一番いいですね。これなら対象アプリで変えないようにコントロールしやすいです。
特定すると、後はWinFormsのものと同じような感覚で使えます。
TreeView
次はTreeViewです。
ノードの文字列を編集してみます。
[TestMethod] publicvoid TestTreeView() { var treeView = new NativeTree(_dlg.IdentifyFromDialogId(IDC_TREE)); var node = treeView.FindNode("0", "2"); treeView.EmulateEdit(node, "x"); Assert.AreEqual("x", treeView.GetItemText(node)); }
これも特定方法は同じですね。
NativeTreeのインターフェイスはネイティブのTreeViewのインターフェイスを少し意識した感じになっています。ノードはIntPtrで返ってきます。
メッセージボックス
少し特殊です。
コントロールではなくメッセージボックスをラップしたものです。
[TestMethod] publicvoid TestMessageBox() { //OKボタンを非同期で押す var buttonOK = new NativeButton(_dlg.IdentifyFromDialogId(IDOK)); var async = new Async(); buttonOK.EmulateClick(async); //メッセージボックスを取得してラップ var msg = new NativeMessageBox(_dlg.WaitForNextModal()); //メッセージを取得 Assert.AreEqual("Msg", msg.Message); //テキストからボタンを検索して押す msg.EmulateButtonClick("OK"); //非同期処理の完了待ち async.WaitForCompletion(); }
メッセージボックスはほとんどのアプリで使います。なので、このクラスは頻繁に使うと思います。
ラッパーを使う分にはネイティブでもさほど変わりませんね
特定方法は異なりますが、ラッパーを使うとネイティブのアプリでも割と簡単に操作できます。
でも、本気でWin32のアプリを自動化するには恐らくこれだけでは足りなくて、独自に定義したDLL公開関数を呼び出したりも必要になってくると思います。その辺もおいおいやっていきますが一旦.Netアプリ操作をメインで解説していきます。