Lua Alien - 调用特定的 API Lua Alien 是一个用于调用和使用动态链接库的 Lua 库。它可以加载动态链接库,并在 Lua 中调用其中的函数和变量。使用 Lua Alien 可以方便地访问操作系统提供的 API 接口。此外,它还支持自定义数据类型和绑定 C 函数。 调用特定的 API 是使用 Lua Alien 的一个重要功能。这意味着,对于不同的操作系统和库,您可以调用特定的函数并访问特定的变量。要调用一个 API,您需要指定 API 的名称和参数类型。然后使用 load 或 loadfile 函数将库加载到 Lua 中,并将其赋值给一个变量。最后,使用 Lua Alien 的 call 函数调用 API 中的函数。 Lua Alien 同时还提供了一些其他的函数,如 tostring、 tonumber 等,以便您可以将 API 函数返回的值转换为正确的 Lua 类型。 总之,通过 Lua Alien,您可以很方便地调用和使用动态链接库,包括访问操作系统提供的 API 接口和自定义数据类型。这对于编写高性能和可扩展的 Lua 脚本非常有用。

我最近在玩 Lua 和 alien 模块,以便从 Lua 脚本中使用 Win32 API。到目前为止,我只遇到了一个使用 alien 的问题,该问题涉及使用某些结构(比如 CreateFontIndirect)的 API。

例如:

HFONT CreateFontIndirectA( const LOGFONT& lplf );

LOGFONT:

typedef struct tagLOGFONT {
 LONG  lfHeight;
 LONG  lfWidth;
 LONG  lfEscapement;
 LONG  lfOrientation;
 LONG  lfWeight;
 BYTE  lfItalic;
 BYTE  lfUnderline;
 BYTE  lfStrikeOut;
 BYTE  lfCharSet;
 BYTE  lfOutPrecision;
 BYTE  lfClipPrecision;
 BYTE  lfQuality;
 BYTE  lfPitchAndFamily;
 TCHAR lfFaceName[LF_FACESIZE];
}LOGFONT, *PLOGFONT;

问题在于字体名称。我不能让 Lua 在结构本身内保留字符串,它总是将一个指针推送到结构中。所以,我没有找到一种纯粹从 Lua 使用此 API 的方法。

这是我能做到的:

 LOGFONT = alien.defstruct {
  { 'lfHeight', 'long' },
  { 'lfWidth', 'long' },
  { 'lfEscapement', 'long' },
  { 'lfOrientation', 'long' },
  { 'lfWeight', 'long' },
  { 'lfItalic', 'byte' },
  { 'lfUnderline', 'byte' },
  { 'lfStrikeOut', 'byte' },
  { 'lfCharSet', 'byte' },
  { 'lfOutPrecision', 'byte' },
  { 'lfClipPrecision', 'byte' },
  { 'lfQuality', 'byte' },
  { 'lfPitchAndFamily', 'byte' },
  { 'lfFaceName', 'string' } -- 此行无法正常工作。
 }

 gdi32 = alien.load( "gdi32.dll" )
 gdi32.CreateFontIndirectA:types {
  ret = 'long',
  abi = 'stdcall',
  'pointer'
 }

调用的例子:

 local lf = LOGFONT:new()
 lf.lfHeight   = 14
 lf.lfWidth    = 0
 lf.lfEscapement  = 0
 lf.lfOrientation = 0
 lf.lfWeight   = 400
 lf.lfItalic   = 0
 lf.lfUnderline  = 0
 lf.lfStrikeOut  = 0
 lf.lfCharSet  = 0
 lf.lfOutPrecision = 0
 lf.lfClipPrecision = 0
 lf.lfQuality  = 0
 lf.lfPitchAndFamily = 0
 lf.lfFaceName   = 'Terminal'

 local hFont = gdi32.CreateFontIndirectA( lf() )

调试运行我的脚本的应用程序显示 API 被正确调用,一切都被正确传递,除了字体名称。我尝试了各种不同的方法来让它工作,但我无法得到它按照所需的方式运行。

有没有什么方法可以在不将任何其他内容硬编码到 exe 中的情况下解决这个问题?

原文链接 https://stackoverflow.com/questions/1647943

点赞
stackoverflow用户199086
stackoverflow用户199086

Alien 的字符串类型仅用于指向字符串的指针,这就是为什么您的示例不起作用的原因。 请尝试以下示例:

-- LF_FACESIZE = ? -- 在这里放置 LF_FACESIZE 常量的值

LOGFONT = alien.defstruct {
  { 'lfHeight', 'long' },
  { 'lfWidth', 'long' },
  { 'lfEscapement', 'long' },
  { 'lfOrientation', 'long' },
  { 'lfWeight', 'long' },
  { 'lfItalic', 'byte' },
  { 'lfUnderline', 'byte' },
  { 'lfStrikeOut', 'byte' },
  { 'lfCharSet', 'byte' },
  { 'lfOutPrecision', 'byte' },
  { 'lfClipPrecision', 'byte' },
  { 'lfQuality', 'byte' },
  { 'lfPitchAndFamily', 'byte' },
  { 'lfFaceName', 'char' }
 }

LOGFONT.size = LOGFONT.size + LF_FACESIZE - 1 -- 所以 Alien 分配了足够的空间
                                              -- 用于整个数组

function get_lfname(lf) -- 作为 Lua 字符串获取 lfFaceName 字段
  local out = {}
  local offset = LOGFONT.offsets.lfFaceName
  local buf = lf()
  for i = offset, offset+LF_FACESIZE-1 do
    local c = buf:get(i, "char")
    if c ~= 0 then
      out[#out+1] = string.char(c)
    else
      break
    end
  end
  return table.concat(out)
end

function set_lfname(lf, s) -- 将 Lua 字符串 s 设置为 lfFaceName
  local offset = LOGFONT.offsets.lfFaceName
  local buf = lf()
  for i = 1, LF_FACESIZE do
    if i <= #s then
      buf:set(offset+i, string.byte(string.sub(s, i, i)), "char")
    else
      buf:set(offset+i, 0, "char")
      break
    end
  end
end

现在,只需像往常一样分配一个 LOFGONF 结构,但使用 get_lfname 和 set_lfname 函数来处理 lfFaceName 属性:

local lf = LOGFONT:new()
lf.lfHeight   = 14
lf.lfWidth    = 0
lf.lfEscapement  = 0
lf.lfOrientation = 0
lf.lfWeight   = 400
lf.lfItalic   = 0
lf.lfUnderline  = 0
lf.lfStrikeOut  = 0
lf.lfCharSet  = 0
lf.lfOutPrecision = 0
lf.lfClipPrecision = 0
lf.lfQuality  = 0
lf.lfPitchAndFamily = 0
set_lfname(lf, 'Terminal')

local hFont = gdi32.CreateFontIndirectA( lf() )

在 C 编程中,在结构末尾添加一个数组是常见模式,我忘了。 我将在 Alien 的下一个版本中直接支持它。

2009-10-30 13:56:34
stackoverflow用户200336
stackoverflow用户200336

非常感谢回复,mascarenhas,这个解决方案起作用了。不过,我需要调整你的 set_lfname 函数,因为偏移量 + i - 1 对齐错误,正在覆盖结构中的 lfPitchAndFamily 字节,将 -1 删除并且它工作得很好。 :)

2009-10-31 23:45:33