Calling Win32 functions returning strings with alien in Lua

lua, winapi

Solution

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...

Problem

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 ) ```

Original source