C++ 如何在Lua中使用Win32迭代器?

C++ 如何在Lua中使用Win32迭代器?,c++,lua,C++,Lua,我有一个使用Lua5.2.1的VisualStudio2008C++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_t

我有一个使用Lua5.2.1的VisualStudio2008C++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;
}
当我运行它时,只会调用
进程\u iter\u first
。当
Process32First
成功时,如何用
process iter\u next
替换在
l\u列表中创建的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\u pushlightuserdata
),然后在第一次调用时更新它

或者将userdata更改为包含句柄和函数指针的结构,并在第一次调用时更新函数指针


对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;
}

只需将要调用的函数的地址作为闭包的另一个向上值(
lua\u pushlightuserdata
),然后在第一次调用时更新它

或者将userdata更改为包含句柄和函数指针的结构,并在第一次调用时更新函数指针


对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;
}

请参阅我的编辑。用指向
Process32Next
函数的指针替换用户数据时遇到问题。请参阅我的编辑。用指向
Process32Next
函数的指针替换用户数据时遇到问题。