Lua Alien - 调用特定API

时间:2009-10-30 03:56:31

标签: winapi api lua

我目前遇到一个问题,同时玩Lua和外星人模块使用Win32 API等来自Lua脚本。到目前为止,我只有一个与外星人有关的问题,即使用API​​,使用某些结构,如CreateFontIndirect。

例如:

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' } -- This line isn't working properly.
 }



 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中吗?

2 个答案:

答案 0 :(得分:3)

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

-- LF_FACESIZE = ? -- put the value of the LF_FACESIZE constant here

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 -- so Alien allocates enough space
                                              -- for the whole array

function get_lfname(lf) -- gets the lfFaceName field as a Lua string
  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) -- sets the Lua string s as the 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中直接支持它。

答案 1 :(得分:-1)

非常感谢mascarenhas的回应,这个解决方案很有效。我确实需要调整你的set_lfname函数,因为偏移+ i-1未对齐并且覆盖了结构中的lfPitchAndFamily字节,删除了-1并且它工作得很好。 :)