~秀丸マクロを「関数」を文字列で実行~

概要

この機能を利用する場合、秀丸エディタ v8.98 (正式版 or β9以上)を強く推奨します。
そうでない場合、数値と文字列の型を間違えて実行すると秀丸が不正な状態となります。

Hm.Macro.Eval(...)を「関数向けに特化」したものとして、「Hm.Macro.Function」が用意されています。

秀丸マクロにおいて「関数」とは

$ret = sprintf(....);

のように呼び出しに「( )」を利用し、返り値を受け取る形になっているものです。

一方、類似ですが関数のようでいて「返り値」がなく、「( )」もないものは秀丸マクロでは「文」もしくは「命令文」としています。

秀丸マクロの関数を実行可能です。

マクロ実行中のみ実行可能

Hm.Macro.Function("秀丸マクロの関数名", ...引数);
  • C#側のソース

    MyTestForm.cs
    using System;
    using HmNetCOM;
    
    ...
        var ret = Hm.Macro.Function("sprintf", "%03d", 555); // 秀丸マクロ関数の「sprintf」を呼び出してみる例。
        if (ret.Error == null)
        {
            string retValue = (String)ret.Result; // Result には「関数(今回の場合sprintf)の返り値」が入っている。
            var updatedArgs = ret.Args; // Argsには引数("%03d", 555)の関数実行後の値がList<Object>の形で格納されている。
                                        // この機能は秀丸マクロの「getlinecount」など引数の値自体を書き換える関数のためにある。
        }
        else
        {
            Hm.OutputPane.Output("実行失敗\r\n");
        }
    

引数が書き換わる関数

C#の型に対する支援を期待するのなら、そのままHm.Macro.Function...と利用するよりも、
ラップするのがおすすめです。
また、秀丸マクロの関数にはごく一部、返り値のみならず、引数に渡している変数自体に値が入ってくるものもあります。
例えばgetlinecount (秀丸v8.94以降)enumregvalue (秀丸v9.00以降)などが該当します。
こういったものも取得できるようになっています。

今回は「秀丸マクロ関数のgetlinecount」をラップしてみましょう。

  • C#側のソース

    MyTestForm.cs
    using System;
    using System.Windows.Forms;
    using HmNetCOM;
    
    ...
        private void SomeMethod()
        {
            (int lineno , int column) = getlinecount( "ABCD\nXYZ", 7 );
            Hm.OutputPane.Output($"{column}, {lineno}\r\n");
        }
    
        private static (int lineno, int column) getlinecount(string text, int index)
        {
            int dummyColumn = 0;
            var ret = Hm.Macro.Function("getlinecount", text, index, dummyColumn);
            if (ret.Error != null)
            {
                throw ret.Error;
            }
    
            int lineno = (int)(dynamic)ret.Result;  // 64bit⇒32bitなどでキャストエラーを起こさないようにdynamicを間にはさむ
            int column = (int)(dynamic)ret.Args[2]; // 関数に渡した引数が、関数の実行後どうなったのかList<Object>の形で格納されている。
                                                     // 引数の3番目 dummyColumn に対応する引数Argsの3番目 (=0オジリンで2) に対応するマクロ変数の書き換えられた値が格納されている。
            return (lineno, column);
        }
    

Hm.Macro.Function(...) の返り値

    • Resultプロパティ

      実行した秀丸マク関数の返り値がObject型で入っています。
      取得するには(string)もしくは(dynamic)にキャストした後、(int)や(long)でのキャストが必要です。

    • Argsプロパティ

      秀丸マク関数を実行した後、秀丸マクロ関数に渡した引数が最終的にどういった値になったかを取得できます。
      List<Object>型で、関数に渡した最初の引数が[0], 次の引数が[1], ... といった形で格納されています。 各種リスト要素はObject型になっていますので、取得するには(string)もしくは(dynamic)にキャストした後、(int)や(long)でのキャストが必要です。

    • Errorプロパティ

      何か明確な例外が発生した場合はErrorプロパティにException型の例外インスタンスが入っています。

    • Messageプロパティ

      基本的には特になにもはいっておらず、空文字が入っています。

関数の返り値の型に対してヒントを与える

秀丸マクロの関数にはCOMなどで利用する「member関数」など、
ごく一部「関数だけではその返り値が数値なのか文字列なのか区別が付かないものがあります。
Hm.Macro.Functionだけだと、そのような「関数の返り値が不定」なものを実行した場合、返り値が正しい状態にならないことがあります。
そこで、「Hm.Macro.Function<String>」やHm.Macro.Function<int>などを利用して、
返り値の型のヒントを秀丸マクロに与えつつ実行することが出来るようになっています。

Hm.Macro.Function<T>("秀丸マクロの関数名", ...引数);
  • C#側のソース

    MyTestForm.cs
        int comID = (int)(dynamic)Hm.Macro.Var["#COM_ID"]; // どこかでCOM呼び出しなど実行しているものとする。
        var ret = Hm.Macro.Function<int>("member", comID, "myfunc", 555); // 秀丸マクロのmember関数だけだと返り値の型が不明であるため、返り値の型が数値系だというヒントを与える。
        if (ret.Error == null)
        {
            int retValue = (int)(dynamic)ret.Result; // Result には「memberの返り値」がObject型で入っている。
        }
        else
        {
            Hm.OutputPane.Output("実行失敗\r\n");
        }