在Ruby中调用FormatMessageW的正确方法是什么?
require 'win32api'
FormatMessage = Win32API.new 'kernel32', 'FormatMessageW', 'IPIIPII', 'I'
msg = '\0' * 255
FormatMessage.call 0x00001000 | 0x00000100, nil, 6, 1024, msg, 0, 0
FormatMessage返回非null结果,但msg包含不可读消息。怎么了?
答案 0 :(得分:0)
我相信这是您正在寻找的代码:
require 'win32api'
FORMAT_MESSAGE_FROM_SYSTEM = 0x1000
FormatMessage = Win32API.new 'kernel32', 'FormatMessageW', 'IPIIPIP', 'I'
msgw = ("\x00" * 256).force_encoding("UTF-16LE")
count = FormatMessage.call FORMAT_MESSAGE_FROM_SYSTEM, nil, 6, 1033, msgw, msgw.size, nil
msgw = msgw[0, count]
msg = msgw.encode("UTF-8")
puts msg
当我使用Ruby运行时,输出为"句柄无效。",这是错误代码6的正确Windows错误消息。
您的原始代码存在一些问题。
P
而不是I
,尤其是如果您希望它在64位Windows上运行。'\0'
实际上是一个双字节的ASCII字符串,而不是单字节的空字符。您可以通过运行p '\0'.bytes.to_a
来确认这一点。看起来你试图分配255个字节,但实际上你分配了510个字节。您应该分配偶数个字节,因为Windows中的宽字符占用2个字节。FormatMessageW
的第一个参数是错误的,因为你指定FormatMessageW
应该分配自己的缓冲区。force_encoding
将字符串的编码设置为UTF-16LE,因为这是用于Windows中宽字符串的编码(或者如果它不完全相同,至少它大部分时间是兼容的。)String#size
之类的内容会返回令人惊讶的结果。 FormatMessageW
返回格式化消息中的字符数,因此我们可以使用它来删除末尾的空字符。 (方便的是,FormatMessageW
如果有错误则返回0,因此我们的修剪会导致空字符串。)String#encode
将字符串从UTF-16LE转换为UTF-8,因为UTF-8字符串更容易操作并在Ruby中打印。如果您不关心国际化和unicode,您可以使用FormatMessageA
代替。以下是一些适用于此的代码:
require 'win32api'
FORMAT_MESSAGE_FROM_SYSTEM = 0x1000
FormatMessage = Win32API.new 'kernel32', 'FormatMessageA', 'IPIIPIP', 'I'
msg = ("\x00" * 256).force_encoding("ASCII-8BIT")
count = FormatMessage.call FORMAT_MESSAGE_FROM_SYSTEM, nil, 6, 1033, msg, msg.size, nil
msg = msg[0, count]
puts msg
P.S。 DWORD是无符号整数类型。我不确定Ruby的Win32API类中有哪些正确的字母;可能是I
表示有符号整数,应该用其他东西替换。