この記事はアドカレに参加しています。
luajitでnewしたメモリのポインタはlua_topointerで受け取る
小ネタとも言えないような小ネタです。
obj.getpixeldataしたやつの場合
lua側でobj.getpixeldataしたメモリの場合、dll側でポインタを受け取る際には、
char* data = reinterpret_cast<char*>(lua_touserdata(L, 1));
…のようにします。これは、obj.getpixeldataがライトユーザーデータ(たぶん)を返す関数であり、ライトユーザーデーターをdllで受けとるにはlua_touserdata関数を使用する必要があるからです。
ffi.newしたものはどうするのか…?
さて、luajitでnewしたとします。
local a=ffi.new("int[10]",{})
そして、dllの関数に引数として渡したとします。
d.func0(a)
このときにdll側でlua_touserdata関数を使用していると、NULLが返されます。
newしたメモリはライトユーザーデーターではないからです。
そこで、lua_topointer関数を使用します。
char* data = reinterpret_cast<char*>(const_cast<void*>(lua_topointer(L, 1)));
こうすることで、dll内でnewしたメモリにアクセスすることができます。
サンプル
<?--サイズ60のテキストボックスに
local ffi=require("ffi")
local a=ffi.new("int[10]",{})
for i=0,9 do
obj.load(a[i])
obj.draw(-50,50*i+50)
end
local d=require("test_dll")
d.func0(a,0)
obj.load(string.format("%s",a))
obj.draw()
for i=0,9 do
obj.load(a[i])
obj.draw(50,50*i+50)
end
?>
#include <lua.hpp>
#include "windows.h"
int func0(lua_State* L) {
char t[100];
ZeroMemory(t, 100);
int* data = reinterpret_cast<int*>(const_cast<void*>(lua_topointer(L, 1)));
if (lua_tointeger(L, 2) == 1) {
wsprintfA(t, "%p", data);
MessageBoxA(NULL, t, "test.exe", MB_OKCANCEL);
}
for (int i = 0; i < 10; i++) {
data[i] = i;
}
return 0;
}
static luaL_Reg functions[] = {
{"func0",func0},
{nullptr,nullptr}
};
extern "C" {
__declspec(dllexport) int luaopen_test_dll(lua_State* L) {
luaL_register(L, "test_dll", functions);
return 1;
}
}
おわりに
けっこう詰まっていたことだったので、記事にして残しておきます。
これだけのことで数日潰したんですが、長文読みたくなくて避けていたリファレンスマニュアルに普通に書かれていたりするので、マニュアル熟読大事ですね。