秀丸マクロを改めて実行(メソッド編)

概要

さて、前節ではHm.Macro.Exec.doEval(...)を使った文字列での実行をしました。

これまでの秀丸の様々なメソッドの半数ほどは、「秀丸マクロ実行中のみ実行可能」というものが散見されたはずです

すなわち、一般的には「非同期中」は「秀丸マクロ実行中ではない」ため、

このため、Hm.Macro.Exec.doEval(...)のマクロへと値を伝達しようとしても、「マクロ実行中ではない」ため、Hm.Macro.setVar(...) などが利用できず、
値を伝搬するのも難しいという状況になります。

この問題を一気に解決するのが、「Hm.Macro.Exec.doMethod(...)」です。

Hm.Macro.Exec.doMethod(...)は、指定のC++メソッドを「改めて新規の秀丸マクロ実行中」にしつつ呼び出せ、
という命令となります。

秀丸マクロを改めて実行

マクロを実行していない時にのみ、実行することが出来ます。

decltype(Hm.Macro)::IResult Hm.Macro.Exec.doMethod(wstring message_parameter, THmMacroDoMethodType delegate_method)

呼び出せるメソッドは

static THmNumber your_method(wstring message_parameter)

の形です。

  • 通常の関数
  • static なクラスメソッド
    (=インスタンスメソッドではないという意味)

を呼び出すことができます。

publicかprivateかは問いません。

  • C++側のソース

    dllmain.cpp
    #include "HmCppInvoke.h"
    #include <thread>
    
    using namespace Hidemaru;
    using namespace std;
    
    
    class MYTEST {
    public:
        // 非同期中から呼び出されたこのメソッドは「新たなマクロ実行中」という形で呼び出される。
        // 「マクロ実行中」であるため、このメソッドの間だけ秀丸に対して同期となり、Hm.CppInvokeのメソッド群をおおいに利用することが可能となる。
        static THmNumber mystatic_method(wstring message_parameter)
        {
            Hm.Macro.setVar(L"$myvar", L"abc");
            Hm.OutputPane.output(message_parameter + L"\r\n");
            THmNumber column = Hm.Macro.getVar<THmNumber>(L"column");
    
            Hm.OutputPane.output(to_wstring(column) + +L"\r\n");
            wstring myvar = Hm.Macro.getVar<wstring>(L"$myvar");
            Hm.OutputPane.output(myvar + L"\r\n");
            Hm.Macro.doStatement(L"moveto", 3, 2);
            return (THmNumber)1;
        }
    };
    
    bool bThreadCenceller = false;
    const int sleepInterval = 1000;
    HANDLE hThread = NULL;
    
    DWORD WINAPI ThreadFunc(LPVOID pParam)
    {
    
        while (true) {
            Sleep(sleepInterval);
    
            if (bThreadCenceller) {
                break;
            }
    
            if (!Hm.Macro.isExecuting()) {
    
                // 「あいうえお」という文字列を編集中のテキストに挿入。
                auto result = Hm.Macro.Exec.doMethod(L"current_test_symbol", MYTEST::mystatic_method);
    
                if (result.getMessage() == L"current_test_symbol")
                {
                    Hm.OutputPane.output(L"実行成功\r\n");
                }
                else
                {
                    Hm.OutputPane.output(L"実行失敗\r\n");
                }
            }
        }
    
        Hm.OutputPane.output(L"スレッドが終了");
        return 0;
        // スレッド終了
    }
    
    extern "C" __declspec(dllexport) THmNumber DllDetachFunc_After_Hm866(THmNumber n) {
    
        Hm.funcDllExport();
    
        // スレッドを必ず終了させてから、dllが解放されるようにしておかないと飛んでしまう。
        bThreadCenceller = true;
        WaitForSingleObject(hThread, sleepInterval * 2);
    
        return 0;
    }
    
    extern "C" __declspec(dllexport) THmNumber test() {
    
        Hm.funcDllExport();
    
        bThreadCenceller = false;
    
        hThread = CreateThread(
            NULL,
            0,
            ThreadFunc,
            NULL,
            0,
            NULL
        );
    
        Hm.OutputPane.output(L"test関数の終了直前\r\n");
    
        return 1;
    }
    
  • 秀丸マクロ側のソース

    test.mac
    #dll = loaddll(currentmacrodirectory + @"\dll1.dll");
    #r = dllfuncw(#dll, "test");
    
  • 返り値のgetMessage()メソッド

    Hm.Macro.Exec.doMethod(...)が最後まで実行できたならば、getMessage()メソッドに「message_parameter」で渡した値が入っていることでしょう。

    返り値のgetException()メソッド

    途中でなんらかのエラーが発生した場合は、getException()でなんらかのexceptionオブジェクトが入っています。
    何もエラーがなければ、std::nulloptが入っています。