Вызов функций Win32, возвращающих строки с инопланетянами в Lua

Я пытаюсь использовать alien для вызова функций Win32. Я пробовал этот код, но он падает, и я не понимаю, почему.

require( "alien" )

local f = alien.Kernel32.ExpandEnvironmentStringsA
f:types( "int", "string", "pointer", "int" )
local buffer = alien.buffer( 512 )
f( "%USERPROFILE%", 0, 512 )

Ответ 1

Это хороший вопрос, так как это для меня возможность проверить Инопланетянина...

Если вы не возражаете, я воспользуюсь возможностью, чтобы объяснить, как использовать Alien, поэтому люди, подобные мне (не очень привыкшие к require), наткнулись на этот поток, начнутся...

Вы передаете ссылку на страницу LuaForge, я поехал туда и увидел, что мне нужен LuaRock, чтобы получить ее.:-( Я должен установить последний когда-нибудь, но я решил пропустить это пока. Поэтому я пошел в репозиторий и загрузил alien-0.4.1-1.win32-x86.rock. Я узнал, что это обычный файл Zip, который я мог бы распаковать, как обычно.

Немного поработав с require, я закончил хакерские пути в Lua script для быстрого теста. Я должен создать LUA_PATH и LUA_CPATH в моей среде, я сделаю это позже.

Итак, я взял alien.lua, core.dll и struct.dll из распакованных папок и поместил их под каталогом Alien в общий репозиторий библиотеки.
И я добавил следующие строки в начало моего script (предупреждение о плохом взломе!):

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

Затем я попробовал это с простой, без излишеств функцией с немедленным визуальным результатом: MessageBox.

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

Да, я получил окно сообщения! Но, щелкнув ОК, я получил крах Lua, вероятно, как вы. После быстрого сканирования документов Alien я обнаружил (неназванного) преступника: нам нужно использовать соглашение о вызове stdcall для Windows API:

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

Так что было бы тривиально заставить ваш звонок работать:

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

Примечание. Я поместил параметр буфера в вызов eev...