【Curve Editor for AviUtl】のどうでもいい小ネタ
どうでもいいというのは…
(一般のAviUtlユーザーにとっては)どうでもいい小ネタです、その紹介です。
この小ネタというのは、実はCurve Editorが実装されてからずっと気になっていたことで、僕がコミュ障すぎて作製者に訊ねることもできずにずるずる引き摺って、独りでプログラムのコードを見てコンパイルしてみて今年の11月にやっと分かったことです。
1. pluginとlua用のdllの合体
Curve Editorのすごいところは、pluginの機能とlua用のdllの機能が一つのaufファイルになっているところです。
これの利点は結構あって、
・pluginとlua用のdllとで同じ関数を使いまわせる。
・変数の共有も楽。
・ユーザーが導入しやすい。
・ディレクトリが見やすい。
などなど。もっとあるのかな。
合体の方法は、VisualStudioの場合はただ単にpluginのコードとlua用のdllコードを同じプロジェクトでコンパイルするだけです。注意点を挙げるのならば、ヘッダーの参照関連でpluginで使用するヘッダーのパスとluaのパスをしっかり繋いでおく必要があります。
2. luaからaufファイルにある関数を呼ぶ
aufファイル(plugin)をrequireすると、当たり前ですがエラーがでます。
なので、工夫が必要です。
Curve Editorではrequireの仕様を上手く使って、aufファイルにある特定の関数を呼び出しています。
requireをコードみたいに書くとこんなかんじ。
code: a.lua
local function require(modname)
if(modnameがロードされている)then
else--ローダーを探す
local loders_obj=nil
if(package.loadersに関数がある)then
elseif(package.preloadmodnameに関数がある)then elseif(package.pathにあるパスでlua moduleを探す)then
loders_obj=luaモジュール
elseif(package.cpathにあるパスでCのローダーを探す)then
loders_obj=Cのローダー
elseif(modnameのルート名から探す)then
loders_obj=modname.subModule.opneFunc
else
return error
end
--ローダーの実行
end
end
--requireした結果を返す
end
注目するのは、package.preload[modname]のところです。package.cpathを検索するよりも優先順位が高いです。
なので、package.cpathでaufファイルをまるまる読み込んでしまう前に、package.preload[modname]にローダー関数を入れると良いことになります。Cライブラリの任意関数を取得するにはpackage.loadlibを使用します。
a.aufにあるluaopen_test_Module関数をローダーにするには、以下のようなコードになります。
code:b.lua
package.preload"a"=package.loadlib("a.auf","luaopen_test_Module") local t=require("a")
変数共有
pluginとlua用のdllとの間で変数などを共有するにはexternを使用します。
code:c++
extern int DATABOX_M;//例
値の実態(メモリ)はplugin側でグローバル変数として宣言しておき、lua用のdll側でexternするのが基本的な形になると思います。
最後にコード
例文コードです。
code:M_test_plugin.cpp
/*
M_test_plugin.cpp
*/
int DATABOX_M = 10;
//フィルタ構造体定義
FILTER_DLL filter = {
FILTER_FLAG_EX_INFORMATION //フィルタのフラグ…らしい
| FILTER_FLAG_ALWAYS_ACTIVE //フィルタを常にアクティブにします
| FILTER_FLAG_MAIN_MESSAGE //func_WndProc()にWM_FILTER_MAIN_???のメッセージを送るようにします
| FILTER_FLAG_DISP_FILTER //表示フィルタにします
| FILTER_FLAG_WINDOW_THICKFRAME, //サイズ変更可能なウィンドウを作ります
NULL,NULL,
(char*)"M_test_plugin",
NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,
func_proc,
func_init,
func_exit,
NULL,
func_WndProc,
NULL,NULL,
NULL,
NULL,
(char*)"M_test_plugin",
NULL,NULL,
NULL,NULL,NULL,NULL,
NULL,
};
//フィルタ構造体のポインタを渡す関数
EXTERN_C FILTER_DLL __declspec(dllexport)* __stdcall GetFilterTable(void) {return &filter;}
//フィルタ関数
BOOL func_proc(FILTER* fp, FILTER_PROC_INFO* fpip)
{
return TRUE;
}
//初期化
BOOL func_init(FILTER* fp) {DATABOX_M = 10; return TRUE;}
/終了
BOOL func_exit(FILTER* fp) {return TRUE;}
//WndProc
BOOL func_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, void* editp, FILTER* fp) {return FALSE;}
code:M_test_plugin.def
LIBRARY M_test_plugin
EXPORTS
GetFilterTable @1
code:lua.cpp
/*
lua.cpp
*/
extern int DATABOX_M;
int p2(lua_State* L) {
lua_pushinteger(L, DATABOX_M);
return 1;
}
static luaL_Reg functions[] = {
{"p2",p2},
{nullptr,nullptr}
};
extern "C" {
__declspec(dllexport) int luaopen_M_test_Module(lua_State* L) {
luaL_register(L, "M_test_Module", functions);
return 1;
}
}
code:lua
debug_print("strat")
package.preload"M_test_Module"=package.loadlib("M_test_plugin.auf","luaopen_M_test_Module") local t=require("M_test_Module")
debug_print("load ok")
debug_print("test :: "..t.p2())
by metaphysical bard