概要‎ > ‎

Win32アプリ操作




このコードとアプリはこちらからダウンロードできます。

ネイティブアプリを操作する場合、もちろんFriendly基本機能も使うのですが、
以下のライブラリを使うとさらに簡単に操作できます。

ここでは、.Netアプリでも使用されるメッセージボックス、ファイルダイアログ、フォルダダイアログの対応を紹介します。
メニュー操作の例も出ています。
メニュー操作はネイティブではほとんどはWM_COMMANDを送信することにより対応できます。

ただ、フォルダダイアログ、ファイルダイアログに関してはPCにより挙動に差分が出るので避けることをお勧めします。
TestSkipFolderDialogを参照してください。

NativeStandardControlsに関しては、ここではごく一部しか使っておりませんが、ネイティブの標準的なコントロールには対応しております。
APIリファレンスをご参照ください。
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Diagnostics;
using Codeer.Friendly;
using Codeer.Friendly.Dynamic;
using Codeer.Friendly.Windows;
using Codeer.Friendly.Windows.Grasp;
using Codeer.Friendly.Windows.NativeStandardControls;
using System.Runtime.InteropServices;
using System.Text;

namespace Win32Sample
{
    [
TestClass]
   
public class UnitTest
    {
       
const int WM_COMMAND = 0x0111;
       
const int ID_DIALOGS_MESSAGEBOX = 32771;
       
const int ID_DIALOGS_FILEDIALOG = 32772;
       
const int ID_DIALOGS_FOLDERDIALOG = 32773;

       
WindowsAppFriend _app;
       
        [
TestInitialize]
       
public void TestInitialize()
        {
#if DEBUG
            var dir = "Debug";
#else
           
var dir = "Release";
#endif
           
var pathExe = Path.GetFullPath("../../../Win32Target/" + dir + "/Win32Target.exe");
            _app =
new WindowsAppFriend(Process.Start(pathExe));
        }

        [
TestCleanup]
       
public void TestCleanup()
        {
           
Process.GetProcessById(_app.ProcessId).CloseMainWindow();
        }

        [
TestMethod]
       
public void TestMessageBox()
        {
           
//最前面ウィンドウを取得
           
var main = WindowControl.FromZTop(_app);

           
//非同期でメッセージボックスを表示
           
//メニューの実行は多くの場合WM_COMMANDを使う
           
var async = new Async();
            main.SendMessage(WM_COMMAND,
new IntPtr(ID_DIALOGS_MESSAGEBOX), IntPtr.Zero, async);

           
//メッセージボックスが表示されるのを待つ
           
var next = main.WaitForNextModal();

           
//メッセージボックスは操作用のクラスがNativeStandardControlsで提供されているのでそれを使う。
           
var msg = new NativeMessageBox(next);
           
Assert.AreEqual(msg.Message, "Message");
            msg.EmulateButtonClick(
"OK");

           
//非同期で実行した処理が完全に終了するのを待つ
            async.WaitForCompletion();
        }

        [
TestMethod]
       
public void TestFileDialog()
        {
           
var main = WindowControl.FromZTop(_app);

            
var async = new Async();
            main.SendMessage(WM_COMMAND,
new IntPtr(ID_DIALOGS_FILEDIALOG), IntPtr.Zero, async);

           
//ファイルダイアログのGUIマッピング
           
var fileDialog = main.WaitForNextModal();
           
var buttonOpen = new NativeButton(fileDialog.IdentifyFromWindowText("開く(&O)"));
           
//コンボボックスは二つある場合がある。
           
//下の方を採用。
           
WindowControl comboBoxPathSrc = null;
           
int top = 0;
           
foreach(var c in fileDialog.GetFromWindowClass("ComboBoxEx32"))
            {
               
RECT rc;
                GetWindowRect(c.Handle,
out rc);
               
if (top < rc.Top)
                {
                    comboBoxPathSrc = c;
                    top = rc.Top;
                }
            }
           
var comboBoxPath = new NativeComboBox(comboBoxPathSrc);

           
//自分のアセンブリのパスを指定する
           
string myPath = GetType().Assembly.Location;
            comboBoxPath.EmulateChangeEditText(myPath);

           
//開くボタンを押す
            buttonOpen.EmulateClick();

           
//非同期で実行した処理が完全に終了するのを待つ
            async.WaitForCompletion();

           
//プロダクトプロセスがテスト用に公開したDLL公開を使って選択されたパスを取得
           
WindowsAppExpander.LoadAssembly(_app, GetType().Assembly);
           
string path = _app.Type(GetType()).GetCurrentPathEx();
           
Assert.AreEqual(myPath, path);
        }

        [
TestMethod]
       
public void TestFolderDialog()
        {
           
var main = WindowControl.FromZTop(_app);

           
var async = new Async();
            main.SendMessage(WM_COMMAND,
new IntPtr(ID_DIALOGS_FOLDERDIALOG), IntPtr.Zero, async);

           
//フォルダダイアログのGUIマッピング
           
var folderDialog = main.WaitForNextModal();
           
NativeTree tree = new NativeTree(folderDialog.IdentifyFromWindowClass("SysTreeView32"));
           
NativeButton buttonOK = new NativeButton(folderDialog.IdentifyFromWindowText("OK"));

           
//ツリー操作
            tree.EmulateExpand(tree.FindNode(
@"デスクトップ", @"PC"), true);
            tree.EmulateExpand(tree.FindNode(
@"デスクトップ", @"PC", @"Windows (C:)"), true);
            tree.EmulateSelectItem(tree.FindNode(
@"デスクトップ", @"PC", @"Windows (C:)", @"Program Files"));

           
//OKボタンを押す
            buttonOK.EmulateClick();

            
//非同期で実行した処理が完全に終了するのを待つ
            async.WaitForCompletion();

           
//プロダクトプロセスがテスト用に公開したDLL公開を使って選択されたパスを取得
           
WindowsAppExpander.LoadAssembly(_app, GetType().Assembly);
           
string path = _app.Type(GetType()).GetCurrentPathEx();
           
Assert.AreEqual(@"C:\Program Files".ToLower(), path.ToLower());
        }

        [
TestMethod]
       
public void TestSkipFolderDialog()
        {
           
WindowsAppExpander.LoadAssembly(_app, GetType().Assembly);

           
//テスト用インターフェイスを使って、フォルダダイアログを表示した次のロジックから実行
           
string myPath = GetType().Assembly.Location;
            _app.Type(GetType()).ShowFolderDialogCoreLogic(myPath);

           
//チェック
           
string path = _app.Type(GetType()).GetCurrentPathEx();
           
Assert.AreEqual(myPath, path);
        }

        [
DllImport("user32.dll")]
        [
return: MarshalAs(UnmanagedType.Bool)]
       
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

        [
DllImport("Win32Target.exe", CallingConvention = CallingConvention.Cdecl)]
       
static extern void ShowFolderDialogCoreLogic(string path);

        [
DllImport("Win32Target.exe", CallingConvention = CallingConvention.Cdecl)]
        
static extern void GetCurrentPath(StringBuilder buf, int size);

       
static string GetCurrentPathEx()
        {
           
StringBuilder buf = new StringBuilder(1024);
            GetCurrentPath(buf, 1024);
           
return buf.ToString();
        }
    }
}