从 Lua 调用 C# 时出现 AccessViolationException
AccessViolationException when calling C# from Lua
我正在尝试将 Lua (C) 与 C# 一起使用,我导入了一些函数来测试它,一切似乎都正常,直到我尝试从 [=30 调用 C# 函数=].
static void Main(string[] args)
{
var L = Lua.luaL_newstate();
Lua.luaL_openlibs(L);
Lua.lua_register(L, "test", Test);
Lua.luaL_dostring(L, "test()");
}
static int Test(IntPtr L)
{
Console.WriteLine("Test from lua->C#");
return 0;
}
如果我 运行 此代码,我会收到测试消息,但紧接着它会在此处抛出 AccessViolationException:
// #define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
public static int luaL_dostring(IntPtr L, string s)
{
if (luaL_loadstring(L, s) != 0)
return 1;
if (lua_pcall(L, 0, LUA_MULTRET, 0) != 0) // <<<<<<<<<<<<<<<<<<<<<<<<
return 1;
return 0;
}
这是我的整个导入代码:
public static class Lua
{
public const int LUA_MULTRET = -1;
//[return: MarshalAs(UnmanagedType.SysInt)]
public delegate int LuaNativeFunction(IntPtr L);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr luaL_newstate();
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void luaL_openlibs(IntPtr L);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int luaL_loadbuffer(IntPtr L, [MarshalAs(UnmanagedType.LPStr)] string buff, int size, [MarshalAs(UnmanagedType.LPStr)] string name);
// LUA_API int lua_resume (lua_State *L, int nargs)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_resume(IntPtr L, int nargs);
// static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_pcall(IntPtr L, int nargs, int nresults, int errfunc);
// static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_pushcclosure(IntPtr L, LuaNativeFunction fn, int n);
// static void lua_setfield(lua_State*L,int idx,const char*k);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_setfield(IntPtr L, int idx, [MarshalAs(UnmanagedType.LPStr)] string k);
// LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s)
public static int luaL_loadstring(IntPtr L, string s)
{
return luaL_loadbuffer(L, s, s.Length, s);
}
// #define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
public static int luaL_dostring(IntPtr L, string s)
{
if (luaL_loadstring(L, s) != 0)
return 1;
if (lua_pcall(L, 0, LUA_MULTRET, 0) != 0)
return 1;
return 0;
}
// #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
public static void lua_register(IntPtr L, string n, LuaNativeFunction f)
{
lua_pushcfunction(L, f);
lua_setglobal(L, n);
}
// #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
public static void lua_pushcfunction(IntPtr L, LuaNativeFunction f)
{
lua_pushcclosure(L, f, 0);
}
// #define lua_setglobal(L,s)lua_setfield(L,(-10002),(s))
public static void lua_setglobal(IntPtr L, string s)
{
lua_setfield(L, -10002, s);
}
}
因为我读到这可能是由委托的 return 值中的类型不匹配引起的:我是 运行ning Windows 7 x64,Lua dll是x86的,项目也设置为使用x86。我还尝试为 LuaNativeFunction 设置一个 return marshal,因为这是在其他地方建议的,但这并没有改变任何东西。
[return: MarshalAs(UnmanagedType.I4)]
public delegate int LuaNativeFunction(IntPtr L);
有人知道问题出在哪里吗?
更新:使用带有 x64 目标的 x64 Lua 库解决了这个问题,所以我想这就是问题所在,但我不太明白 为什么 。
Lua DLL 是使用 CDecl 调用约定编译的,您需要在所有 DllImport 属性和所有用作回调的委托上指定它。因此,例如,您的 LuaNativeFunction 委托需要声明为:
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public delegate int LuaNativeFunction(IntPtr L);
此致,
我正在尝试将 Lua (C) 与 C# 一起使用,我导入了一些函数来测试它,一切似乎都正常,直到我尝试从 [=30 调用 C# 函数=].
static void Main(string[] args)
{
var L = Lua.luaL_newstate();
Lua.luaL_openlibs(L);
Lua.lua_register(L, "test", Test);
Lua.luaL_dostring(L, "test()");
}
static int Test(IntPtr L)
{
Console.WriteLine("Test from lua->C#");
return 0;
}
如果我 运行 此代码,我会收到测试消息,但紧接着它会在此处抛出 AccessViolationException:
// #define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
public static int luaL_dostring(IntPtr L, string s)
{
if (luaL_loadstring(L, s) != 0)
return 1;
if (lua_pcall(L, 0, LUA_MULTRET, 0) != 0) // <<<<<<<<<<<<<<<<<<<<<<<<
return 1;
return 0;
}
这是我的整个导入代码:
public static class Lua
{
public const int LUA_MULTRET = -1;
//[return: MarshalAs(UnmanagedType.SysInt)]
public delegate int LuaNativeFunction(IntPtr L);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr luaL_newstate();
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void luaL_openlibs(IntPtr L);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int luaL_loadbuffer(IntPtr L, [MarshalAs(UnmanagedType.LPStr)] string buff, int size, [MarshalAs(UnmanagedType.LPStr)] string name);
// LUA_API int lua_resume (lua_State *L, int nargs)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_resume(IntPtr L, int nargs);
// static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_pcall(IntPtr L, int nargs, int nresults, int errfunc);
// static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n)
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_pushcclosure(IntPtr L, LuaNativeFunction fn, int n);
// static void lua_setfield(lua_State*L,int idx,const char*k);
[DllImport("lua51.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int lua_setfield(IntPtr L, int idx, [MarshalAs(UnmanagedType.LPStr)] string k);
// LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s)
public static int luaL_loadstring(IntPtr L, string s)
{
return luaL_loadbuffer(L, s, s.Length, s);
}
// #define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
public static int luaL_dostring(IntPtr L, string s)
{
if (luaL_loadstring(L, s) != 0)
return 1;
if (lua_pcall(L, 0, LUA_MULTRET, 0) != 0)
return 1;
return 0;
}
// #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
public static void lua_register(IntPtr L, string n, LuaNativeFunction f)
{
lua_pushcfunction(L, f);
lua_setglobal(L, n);
}
// #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
public static void lua_pushcfunction(IntPtr L, LuaNativeFunction f)
{
lua_pushcclosure(L, f, 0);
}
// #define lua_setglobal(L,s)lua_setfield(L,(-10002),(s))
public static void lua_setglobal(IntPtr L, string s)
{
lua_setfield(L, -10002, s);
}
}
因为我读到这可能是由委托的 return 值中的类型不匹配引起的:我是 运行ning Windows 7 x64,Lua dll是x86的,项目也设置为使用x86。我还尝试为 LuaNativeFunction 设置一个 return marshal,因为这是在其他地方建议的,但这并没有改变任何东西。
[return: MarshalAs(UnmanagedType.I4)]
public delegate int LuaNativeFunction(IntPtr L);
有人知道问题出在哪里吗?
更新:使用带有 x64 目标的 x64 Lua 库解决了这个问题,所以我想这就是问题所在,但我不太明白 为什么 。
Lua DLL 是使用 CDecl 调用约定编译的,您需要在所有 DllImport 属性和所有用作回调的委托上指定它。因此,例如,您的 LuaNativeFunction 委托需要声明为:
[UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public delegate int LuaNativeFunction(IntPtr L);
此致,