最終更新日 2024-09-25

WPFのアプリの形態をそのまま利用する方法

概要

これまで比較的 WinForms を利用したサンプルを掲載してきましたが、WPFでも問題はありません。
.dll 形式である必要もなく、.exeのままでも hm.NET.dll から利用することが出来ます。

WPFのアプリケーションを「.NET Framework」で作成

.NET5/.NET6 といったCore系列ではなく、.NET Frameworkを選択する必要性があるので注意してください。
hm.NET.dllは .NET Frameworkのみの対応です。
.NET5や.NET6などのWPFで制作したい場合は、hm_Hm.NetCOMを利用してください。

hm.NET.dll を参照に追加

MainWindows.xaml を編集して、my_textbox と my_button を作りましょう。

my_button の Click のイベントハンドラからメソッドを自動生成して...

自動生成しなくとも、ご自分で MainWindow.xaml.cs を直接編集する形でももちろんOKです。

my_textbox の内容を、秀丸のアウトプット枠へと出力する短いソース例にしてみましょう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Hidemaru;

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void On_Click(object sender, RoutedEventArgs e)
        {
            String text = this.my_textbox.Text;
            Hm.OutputPane.Output(text + "\r\n");
        }
    }
}

秀丸マクロから直接呼び出されるメソッドを定義

定義場所に迷うところですがが、 App.xaml.cs が空っぽですので、ここが良いでしょう。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
        public static Window wpfWindow;


        public static IntPtr CreateForm()
        {
            // 秀丸マクロから呼び出されたときに実行されるメソッド
            if (wpfWindow != null)
            {
                wpfWindow.Close();
                wpfWindow = null;
            }
            wpfWindow = new MainWindow();
            wpfWindow.Show();
            return (IntPtr)1;
        }

        public static IntPtr OnDetachMethod(IntPtr close_reason)
        {
            // 秀丸エディタが閉じられる前に実行されるコード
            // このWPFアプリケーションを終了します。
            if (wpfWindow != null)
            {
                wpfWindow.Close();
                wpfWindow = null;

                // このメソッドが通過したことをわかりやすくするため、終了理由の番号をダイアログボックスで表示
                MessageBox.Show(close_reason.ToString());
            }
            return (IntPtr)1;
        }
    }
}

秀丸マクロ側のソース

呼び出し側のマクロを用意しましょう。

WpfTest.mac
#dll = loaddll(hidemarudir + @"\hm.NET.dll");

#r = dllfuncw(#dll, "SetDetachMethod", currentmacrodirectory + @"\WpfApp1.exe", "WpfApp1.App", "OnDetachMethod");
#r = dllfuncw(#dll, "CallMethod", currentmacrodirectory + @"\WpfApp1.exe", "WpfApp1.App", "CreateForm");

WpfApp1.exeと、このWpfWpfTest.mac の2つのファイルを同一のディレクトリに配置して、マクロを実行してみましょう。

On_Click は非同期メソッドなので...

非同期メソッド中は、通常マクロ中ではないため、hm.NET.dllで利用できる機能が制限されてしまいます、
それを打開する Hm.Macro.Exec.DoMethod(...) があることを思い出してください。

MainWindowのインスタンス(this)を static メソッドから参照するため、static変数 self へと this を伝搬しているところが工夫となります。

using Hidemaru;
using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        static MainWindow self; // 自分自身のインスタンスをstaticメソッドから参照するためのもの。
        public static IntPtr ScopeMethod(string message_parameter)
        {
            String text = self.my_textbox.Text;
            String date = (String)Hm.Macro.Var["date"];
            Hm.OutputPane.Output($"現在の日付は{date}です\r\n");
            Hm.OutputPane.Output(text + "\r\n");
            var menu = new List<String> { "aaa", "bbb", "ccc" };
            var ret = Hm.Macro.Statement("menuarray", menu, menu.Count);
            if (ret.Error == null)
            {
                // menuarrayの選択メニューの結果は、秀丸マクロではresultに入っている。
                // 32bitでも64bitでも大丈夫なように、dynamicを挟むのを忘れないようにしよう。
                int result = (int)(dynamic)Hm.Macro.Var["result"];

                Hm.OutputPane.Output($"選択結果{result}" + "\r\n");
            }
            return (IntPtr)1;
        }

        private void On_Click(object sender, RoutedEventArgs e)
        {
            self = this; // 暗黙のインスタンス変数を直接 staticメソッドから参照できないため、this を static 変数の selfへと代入する。
            Func<String, IntPtr> method = ScopeMethod;
            Hm.Macro.Exec.Method("my_method", method);
        }
    }
}

Hm.Macro.Exec.DoMethod を利用することで、非同期メソッド中であっても、秀丸マクロを「改めて実行」するため、
Hm.Macro.Var["..."] や Hm.Macro.Funtion(...)、Hm.Macro.Statement(...) が利用可能となります。
これにより、非同期中独特の制限が大きく解けて、秀丸側から提供されているマクロ関数等の機能を利用しやすくなります。