Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Win32 functions returning strings with alien in Lua

Tags:

winapi

lua

I'm trying to use alien to call Win32 functions. I tried this code, but it crashes and I don't understand why.

require( "alien" )

local f = alien.Kernel32.ExpandEnvironmentStringsA
f:types( "int", "string", "pointer", "int" )
local buffer = alien.buffer( 512 )
f( "%USERPROFILE%", 0, 512 )
like image 997
Jazz Avatar asked Nov 07 '08 15:11

Jazz


1 Answers

It is a good question as it is, for me, an opportunity to test out Alien...

If you don't mind, I take the opportunity to explain how to use Alien, so people like me (not very used to require) stumbling upon this thread will get started...

You give the link to the LuaForge page, I went there, and saw I needed LuaRock to get it. :-( I should install the latter someday, but I chose to skip that for now. So I went to the repository and downloaded the alien-0.4.1-1.win32-x86.rock. I found out it was a plain Zip file, which I could unzip as usual.

After fumbling a bit with require, I ended hacking the paths in the Lua script for a quick test. I should create LUA_PATH and LUA_CPATH in my environment instead, I will do that later.

So I took alien.lua, core.dll and struct.dll from the unzipped folders and put them under a directory named Alien in a common library repository.
And I added the following lines to the start of my script (bad hack warning!):

package.path = 'C:/PrgCmdLine/Tecgraf/lib/?.lua;' .. package.path
package.cpath = 'C:/PrgCmdLine/Tecgraf/lib/?.dll;' .. package.path
require[[Alien/alien]]

Then I tried it with a simple, no-frills function with immediate visual result: MessageBox.

local mb = alien.User32.MessageBoxA
mb:types{ 'long', 'long', 'string', 'string', 'long' }
print(mb(0, "Hello World!", "Cliché", 64))

Yes, I got the message box! But upon clicking OK, I got a crash of Lua, probably like you. After a quick scan of the Alien docs, I found out the (unnamed) culprit: we need to use the stdcall calling convention for the Windows API:

mb:types{ ret = 'long', abi = 'stdcall', 'long', 'string', 'string', 'long' }

So it was trivial to make your call to work:

local eev = alien.Kernel32.ExpandEnvironmentStringsA
eev:types{ ret = "long", abi = 'stdcall', "string", "pointer", "long" }
local buffer = alien.buffer(512)
eev("%USERPROFILE%", buffer, 512)
print(tostring(buffer))

Note I put the buffer parameter in the eev call...

like image 70
PhiLho Avatar answered Sep 20 '22 04:09

PhiLho