RTTIを介してDelphiビジュアルコンポーネントを使用するために、Delphi + Luaで簡単なプロジェクトを作成しています。に基づく主な実装アイデアluna.h
。xml に格納されたテンプレートを使用するという Blizzard のアイデア (たとえば、TPanel に複数のオブジェクトを配置してテンプレートとして使用できる場合) が好きなので、それもほぼ実装しました。
問題は、Inject コードとほぼ同じコードで作成された Lua からのコールバックを介してオブジェクトを作成するまで、すべてが正常に機能することluna.h
です。このオブジェクトに "inherits" xml 属性がある場合、コールバック関数は xml に格納されたオブジェクトの作成を呼び出し、さらに別の注入によって別のオブジェクトを作成します。そして、lua51.dll につながるエラーが表示されます。
おそらく、コールバック関数がまだ結果を返していないときに、コールバックとインジェクトの両方でスタックを使用したために発生した問題です。スタックを使用して、コールバックを介してオブジェクトを作成できますか? そうでない場合 - それを実装するための回避策はありますか? ブリザードは本当に何とかそれを作りました.
詳細:
1. Lua オブジェクト (たとえばTPanel
、その他多数) を登録するアプリケーション
cn := T.ClassName;
f := @StaticOnCreate;
lua_pushlightuserdata(L, self); // put offset to self into lightuserdata
lua_pushcclosure(L, f, 1);
lua_setglobal(L, PAnsiChar(UTF8Encode(cn))); // T() in lua will make a new instance.
luna.h との違い - アプリケーションはジェネリック (c テンプレート) を避けるために、オブジェクトへのポインターも格納しました (Delphi オブジェクトはポインターです)
2. 現在、Lua はTPanel
グローバル テーブルに含まれています
3.
p = TPanel("somename")
スクリプトでは、Lua はアプリケーションの StaticOnCreate を呼び出します。
4. StaticOnCreate はオブジェクトを抽出し、クラスの関数を呼び出します
o := TLuaClassTemplate(lua_topointer(L, lua_upvalueindex(1)));
result := o.OnCreate(L);
5.OnCreate
関数はetcのようなパラメータを抽出し、関数と同じコードを使用してname
、タイプの正確なビジュアルオブジェクトを作成しますTPanel
luna.h
inject
lua_newtable(FL); // create a new table for the class object ('self')
obj_index := lua_gettop(FL);
lua_pushnumber(FL, 0);
a := lua_newuserdata(FL, SizeOf(pointer)); // store a ptr to the ptr
a^ := obj; // set the ptr to the ptr to point to the ptr... >.>
luaL_newmetatable(FL, PAnsiChar(UTF8Encode(cn))); // get (or create) the classname_metatable
lua_pushstring(FL, PAnsiChar(UTF8Encode('__gc')));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushcclosure(FL, @StaticGc_T, 1);
lua_settable(FL, -3);
lua_setmetatable(FL, -2); // userdata.metatable = classname_metatable
lua_settable(FL, obj_index); // self[0] = obj;
f := @StaticThunk;
// register the functions
for i := 0 to length(ClassApiArray) - 1 do begin
lua_pushstring(FL, PAnsiChar(UTF8Encode(ClassApiArray[i].name)));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushnumber(FL, i); // let the thunk know which method we mean
lua_pushcclosure(FL, f, 2);
lua_settable(FL, obj_index); // self["function"] = thunk("function")
end;
lua_pushvalue(FL, -1); // dup object on stack top
rec.ref := luaL_ref(FL, LUA_REGISTRYINDEX); // store object as ref
...
result := 1;
はスタックを介して Lua オブジェクトを返すため、p fromp = TPanel("somename")
はオブジェクトのインスタンスです。
ただし、xml テンプレートとステップ 3 を実装しようとすると問題が発生します
p = TPanel("somename", "xmltemplatenodename")
実行中のステップ 5 ではOnCreate
、あることがわかりますinherits = xmltemplatenodename
。そのため、ステップ 5 の前にinject
、アプリケーションは正確な検索を行いxmltemplatenodename
、見つかった場合はinject
for each オブジェクトでさらにオブジェクトを作成します。その後、独自のステップ 5 の実行を継続しinject
ます。から 2 ~ 3 個のオブジェクトを作成した後、lua51.dll につながるエラーが発生しましたxmltemplatenodename
。ただし、アプリケーションがソースと同じ xml を使用し、xmltemplatenodename
外部で同じオブジェクトを作成するOnCreate
場合、エラーは発生しません。
Inject
xml オブジェクトの場合は、オブジェクトをスタックに残す代わりに、オブジェクト名で登録します。
lua_setglobal(FL, PAnsiChar(objName8));