![](/img/trans.png)
[英]How do I call the Win32 API function `WriteFile()` with C++ iterators?
[英]How do I use Win32 iterators in Lua?
我有一個使用Lua 5.2.1的Visual Studio 2008 C ++ 03項目,在這里我希望允許Lua腳本使用Win32迭代函數(FindFirst *,FindNext *等)。
例如,我希望能夠列出正在運行的進程:
#include <tlhelp32.h>
#pragma comment( lib, "toolhelp.lib" )
static int process_iter_next( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32Next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
return 1;
}
return 0;
}
static int process_iter_first( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( ::Process32First( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
// How do I replace the closure with process_iter_next?
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushcclosure( L, process_iter_first, 1 );
return 1;
}
static int process_gc( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, 1 );
if( INVALID_HANDLE_VALUE != h )
::CloseToolhelp32Snapshot( h );
return 0;
}
extern "C" int luaopen_process( lua_State *L )
{
static const luaL_Reg process[] = {
{ "list", l_list },
{ NULL, NULL }
};
luaL_newmetatable( L, "process.list" );
lua_pushstring( L, "__gc" );
lua_pushcfunction( L, process_gc );
lua_settable( L, -3 );
luaL_newlib( L, process );
return 1;
}
我的Lua腳本:
for p in process.list() do
print(p)
end
當我運行此命令時,將僅調用process_iter_first
。 當Process32First
成功時, l_list
用process_iter_next
替換l_list
創建的c閉包?
根據@Mud的建議進行編輯*
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL ( *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
lua_pushlightuserdata( L, Process32Next );
// not sure how to use this function. The docs are not enlightening.
// lua_setupvalue( L, ???, ??? );
// This looked like a good idea from the docs, but it causes an access violation
// lua_setuservalue( L, lua_upvalueindex( 2 ) );
return 1;
}
return 0;
}
static int l_list( lua_State *L )
{
HANDLE* h = ( HANDLE* )lua_newuserdata( L, sizeof( HANDLE ) );
luaL_getmetatable( L, "process.list" );
lua_setmetatable( L, -2 );
*h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 );
if( INVALID_HANDLE_VALUE == *h )
luaL_error( L, "Failed to list processes. EC: %d", ::GetLastError() );
lua_pushlightuserdata( L, Process32First );
lua_pushcclosure( L, process_iter, 2 );
return 1;
}
只需將函數的地址作為另一個閉包的lua_pushlightuserdata
( lua_pushlightuserdata
) lua_pushlightuserdata
然后在第一次調用時對其進行更新。
或將用戶數據更改為包含句柄和函數指針的結構,並在首次調用時更新函數指針。
回應PaulH的編輯:
static int process_iter( lua_State* L )
{
HANDLE h = *( HANDLE* )lua_touserdata( L, lua_upvalueindex( 1 ) );
typedef BOOL (WINAPI *PFN_ProcessIter )( HANDLE, LPPROCESSENTRY32 );
PFN_ProcessIter next = ( PFN_ProcessIter )lua_touserdata( L, lua_upvalueindex( 2 ) );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
if( next( h, &pe ) )
{
lua_pushstring( L, pe.szExeFile );
if (next == Process32First)
{
lua_pushlightuserdata(L, Process32Next);
lua_replace(L, lua_upvalueindex(2));
}
return 1;
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.