Lua 中多线程用法 for Win32Exts
目前 Lua 中并没有 真正的抢占式 thread 的概念,只有一个类似的协程:coroutine 对象,
同一时间只能运行一个 coroutine ,并且需要显式的进行切换才能执行。与实际应用需求相差甚远。
(coroutine 用法参见: https://blog.csdn.net/wzzfeitian/article/details/8832017)
Win32Exts for Lua 中实现了真正的 抢占式线程 thead 的相关操作,并做了各种强化。
Win32Exts 是一个支持多种脚本语言(VBS, JS, Lua, Python, Java, CEF框架等 )的 Win32 扩展库, 通过它,你能够像C/C++ 一般
调用任意系统或者第三方API,实现强大的功能需求。
库地址: https://github.com/tankaishuai/win32exts_for_Lua
用法:
1、创建线程:
h = win32exts.create_thread( lua_file, [arg] )
h = win32exts.create_thread( lua_script, [arg] )
成功返回线程对象 h,失败返回 nil。在 Lua 脚本里面通过全局变量 __args 获取传入参数。
以上 可选参数 arg 只能传入一个整数给新线程。
如果希望更灵活的传入各种参数,可以使用下列增强接口:
h = win32exts.create_thread_v2( lua_file, [arg1, arg2, arg3 ... ] )
h = win32exts.create_thread_v2( lua_script, [arg1, arg2, arg3 ... ] )
其中参数个数以及类型随便(除了Lua的thread与function这两种对象不支持之外,userdata类型弱支持),
也可以包装成一个 table 对象传入。
例如:
h = win32exts.create_thread_v2( "C:\\test.lua", "第一个参数", 2, {[true] = false}, 3.14, "第五个参数" )
或者以上等价于:
tbl = { "第一个参数", 2, {[true] = false}, 3.14, "第五个参数" }
h = win32exts.create_thread_v2( "C:\\test.lua", tbl )
在 Lua 脚本里面通过全局变量 __args[1], __args[2], ... , __args[5] 获取传入的参数。
2、结束线程并获取返回值:
ret = win32exts.end_thread( h, [timeout] )
ret 为 lua 脚本返回值。 在 Lua 脚本里面通过全局变量 __ret 设置返回值。
例如, 简单地获取传入参数,加一后返回之:
> require "win32exts"
> script = [[print("args:" .. __args)]] .. "\n" .. [[__ret = __args+1]]
> h = win32exts.create_thread(script, 333)
args:333
> print( win32exts.end_thread(h, 0) )
334
大块数据 buffer 也可以考虑先分配一块内存,然后传入指针给线程:
> script2 = [[ print(win32exts.read_wstring(__args)) ]]
> g_buf = win32exts.malloc(520)
> win32exts.write_wstring(g_buf, 0, -1, "~~~test_string_data~~~")
> h = win32exts.create_thread(script2, g_buf)
~~~test_string_data~~~
3、除了支持创建本地线程之外,win32exts ver 38.2020.2.21 以后版本也支持创建远程线程,
亦即使得目标 Lua 脚本运行在其它进程之内:
h = win32exts.create_remote_thread( process_id, lua_file, [arg] )
h = win32exts.create_remote_thread( process_id, lua_script, [arg] )
以及增强接口:
h = win32exts.create_remote_thread_v2( process_id, lua_file, [arg1, arg2, arg3 ... ] )
h = win32exts.create_remote_thread_v2( process_id, lua_script, [arg1, arg2, arg3 ... ] )
使用方法与本地线程完全一致。
获取远程Lua脚本返回值使用:
ret = win32exts.end_remote_thread( h, [timeout] )
4、以上都是直接在当前进程或者其它进程上面 新建线程执行 Lua,
如果想在当前已有的线程上直接执行 Lua脚本,可以使用下列接口:
h = win32exts.inject_remote_thread( thread_id, lua_file, [arg] )
h = win32exts.inject_remote_thread( thread_id, lua_script, [arg] )
以及增强接口:
h = win32exts.inject_remote_thread_v2( thread_id, lua_file, [arg1, arg2, arg3 ... ] )
h = win32exts.inject_remote_thread_v2( thread_id, lua_script, [arg1, arg2, arg3 ... ] )
例如,尝试取指定线程队列中 的一个消息:
code = [=[
win32exts.load_sym("user32", "*")
pMsg = win32exts.malloc( 0x20 );
win32exts.PeekMessageW( pMsg, nil, 0, 0, 0)
]=]
h = win32exts.inject_remote_thread( thread_id, code )
除了以上接口之外,如果目标线程含有用户界面,v41 以后版本还可以使用以下几个接口:
ret = win32exts.inject_remote_window( hwnd, lua_file, [arg] )
ret = win32exts.inject_remote_window( hwnd, lua_script, [arg] )
ret = win32exts.inject_remote_thread_ex( thread_id, lua_file, [arg] )
ret = win32exts.inject_remote_thread_ex( thread_id, lua_script, [arg] )
以及增强接口:
ret = win32exts.inject_remote_window_v2( hwnd, lua_file, [arg1, arg2, arg3 ... ] )
ret = win32exts.inject_remote_window_v2( hwnd, lua_script, [arg1, arg2, arg3 ... ] )
ret = win32exts.inject_remote_thread_ex_v2( thread_id, lua_file, [arg1, arg2, arg3 ... ] )
ret = win32exts.inject_remote_thread_ex_v2( thread_id, lua_script, [arg1, arg2, arg3 ... ] )
5、除了线程之外,还有几个异步操作相关的函数可以直接使用:
线程池操作:
is_ok = win32exts.queue_task( lua_file, [arg] )
is_ok = win32exts.queue_task( lua_script, [arg] )
is_ok = win32exts.queue_task_v2( lua_file, [arg1, arg2, arg3, ... ] )
is_ok = win32exts.queue_task_v2( lua_script, [arg1, arg2, arg3, ... ] )
APC操作:
is_ok = win32exts.queue_apc( lua_file, [arg] )
is_ok = win32exts.queue_apc( lua_script, [arg] )
is_ok = win32exts.queue_apc_v2( lua_file, [arg1, arg2, arg3, ... ] )
is_ok = win32exts.queue_apc_v2( lua_script, [arg1, arg2, arg3, ... ] )
以及远程 APC操作:
is_ok = win32exts.queue_remote_apc( thread_id, lua_file, [arg] )
is_ok = win32exts.queue_remote_apc( thread_id, lua_script, [arg] )
is_ok = win32exts.queue_remote_apc_v2( thread_id, lua_file, [arg1, arg2, arg3, ... ] )
is_ok = win32exts.queue_remote_apc_v2( thread_id, lua_script, [arg1, arg2, arg3, ... ] )
功能相当强大。
例如,以下代码查找 某聊天软件进程,并在其进程中执行指定的 Lua 脚本, 显示消息框:
code = [=[
win32exts.load_sym("*", "*") --加载所有库
win32exts.HideModuleByModule( win32exts.current_dll() ) --把自己隐藏了,这样别人就无法发现了←___←‘
__ret = win32exts.MessageBoxA( __args[1], __args[2], __args[3], 1) --在里面弹出我们的消息
]=]
win32exts.load_sym("*", "*")
hWnd = win32exts.FindWindowA( "TXGuiFoundation", "QQ" )
g_buf = win32exts.malloc(4)
win32exts.GetWindowThreadProcessId( hWnd, g_buf ) --以上获取进程Id,懂C/C++的毫无理解难度
dwProcessId = win32exts.read_value(g_buf, 0, 4)
h = win32exts.create_remote_thread_v2( dwProcessId, code, hWnd, "请点击:http://my.com", "这是官方的推送哦!!")
if win32exts.end_remote_thread(h) == 1 then
-- 用户点击了 OK 按钮
win32exts.WinExec( "explorer.exe http://my.com", 1 )
end