入門編 ~秀丸マクロの「(関数のような)命令文」を文字列で実行~

概要

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

Hm.Macro.doEval(...)を「命令向けに特化」したものとして、「Hm.Macro.doStatement」が用意されています。

秀丸マクロにおいて「(関数のような)文」や「(関数のような)命令文」とは

moveto X座標, Y座標

のように呼び出しに「( )」が使われず、かつ、返り値を受け取らないものです。

一方、文と類似ですが「返り値」があり、「( )」を付けて呼び出すものを「関数」としています。

秀丸マクロの(関数のような)文を実行可能です。

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

decltype(Hm.Macro)::IStatementResult Hm.Macro.doStatement(wstring statement_name, ...ステートメントの引数);
  • C++側のソース

    dllmain.cpp
    #include "HmCppInvoke.h"
    
    using namespace Hidemaru;
    using namespace std;
    
    extern "C" __declspec(dllexport) THmNumber test() {
    
        Hm.funcDllExport();
    
        auto ret = Hm.Macro.doStatement(L"moveto", 10, 2); // X:10, Y:2 の位置に移動
        if (ret.getException() == std::nullopt) // ret.getResult() > 0 という判定でも同一の意味
        {
            Hm.OutputPane.output(L"実行成功\r\n");
        }
        else
        {
            Hm.OutputPane.output(L"実行失敗\r\n");
        }
    
    
        return 1;
    }
    

引数として「配列」を必要とする関数のような文

秀丸マクロの文や関数にはごく一部には「menuarray」など 引数として「配列」を必要とするものがあります。

今回は「秀丸マクロ文のmenuarray」を利用してみましょう。

setVar(...)、getVar(...)、doEval(...) などを組み合わせ、自分でラップしてC++上に menuarray 関数を作成しまえばよいでしょう。

  • C++側のソース

    MyTestForm.cs
    #include "HmCppInvoke.h"
    
    using namespace Hidemaru;
    using namespace std;
    
    
    int menuarray(vector<wstring> menu) {
        // setVarを使って、秀丸マクロ上の $tmpmenu[ix] にmenuの内容を複製
        for ( int ix=0; ix<(int)menu.size(); ix++) {
            wstring keyname = L"$tmpmenu[" + to_wstring(ix) + L"]";
            Hm.Macro.setVar(keyname, menu[ix]);
        }
    
        Hm.Macro.setVar(L"#menulen", (THmNumber)menu.size());
    
        auto ret = Hm.Macro.doEval(LR"MACRO(
            menuarray $tmpmenu, #menulen;
        )MACRO"
        );
    
        if (ret.getException() != std::nullopt) { // 例外がある
            return -1;
        }
    
        auto selected_menu_id = Hm.Macro.getVar<THmNumber>(L"result");
    
        // 一時的に秀丸マクロ上に作成した変数をすべて削除
        for (int ix = 0; ix < (int)menu.size(); ix++) {
            // 文字列タイプなら空文字を代入しておくことで、秀丸マクロ上の該当の変数は消去される。
            wstring keyname = L"$tmpmenu[" + to_wstring(ix) + L"]";
            Hm.Macro.setVar(keyname, L"");
        }
    
        // 数値タイプなら0に、しておくことで、秀丸マクロ上の該当の変数は消去される。
        Hm.Macro.setVar(L"#menulen", (THmNumber)menu.size());
    
        return (int)selected_menu_id;
    }
    
    extern "C" __declspec(dllexport) THmNumber test() {
    
        Hm.funcDllExport();
    
        vector<wstring> menu = { L"あいうえお", L"かきくけこ", L"さしすせそ" };
        int selected_id = menuarray(menu);
    
        Hm.OutputPane.output(to_wstring(selected_id));
    
        return 1;
    }
    

Hm.Macro.doStatement(...) 返り値、IStatementResult 型のオブジェクト

  • getResult()メソッド

    実行した秀丸マクロ文が無事成功したなら「1」失敗したなら「0」以下がint型で入っています。
    0とは限らないので注意してください。

  • getArgs()メソッド

    秀丸マク関数を実行した後、秀丸マクロ関数に渡した引数が最終的にどういった値になったかを取得できます。
    vector<THmMacroObject>型で、関数に渡した最初の引数が[0], 次の引数が[1], ... といった形で格納されています。 各種リスト要素はTHmMacroObject型になっていますので、取得するにはstd::get<THmNumver|wstring>での取得が必要です。

  • getException()メソッド

    何か明確な例外が発生した場合はexception型の例外インスタンスが入っています。
    例外が入っていない場合は、std::nullopt が入っっている。

  • getMessage()メソッド

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