2
require 'puppet/util/windows/string'
4
module Puppet::Util::Windows::APITypes
8
# standard Win32 error codes
13
# Wrapper method for attach_function + private
14
def attach_function_private(*args)
15
attach_function(*args)
22
NULL_TERMINATOR_WCHAR = 0
24
def self.from_string_to_wide_string(str, &block)
25
str = Puppet::Util::Windows::String.wide_string(str)
26
FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
27
# uchar here is synonymous with byte
28
ptr.put_array_of_uchar(0, str.bytes.to_a)
33
# ptr has already had free called, so nothing to return
38
# BOOL is always a 32-bit integer in Win32
39
# some Win32 APIs return 1 for true, while others are non-0
40
read_int32 != FFI::WIN32_FALSE
43
alias_method :read_dword, :read_uint32
44
alias_method :read_win32_ulong, :read_uint32
46
alias_method :read_hresult, :read_int32
49
type_size == 4 ? read_uint32 : read_uint64
52
alias_method :read_wchar, :read_uint16
53
alias_method :read_word, :read_uint16
55
def read_wide_string(char_length)
56
# char_length is number of wide chars (typically excluding NULLs), *not* bytes
57
str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
58
str.encode(Encoding.default_external)
61
def read_arbitrary_wide_string_up_to(max_char_length = 512)
62
# max_char_length is number of wide chars (typically excluding NULLs), *not* bytes
63
# use a pointer to read one UTF-16LE char (2 bytes) at a time
64
wchar_ptr = FFI::Pointer.new(:wchar, address)
66
# now iterate 2 bytes at a time until an offset lower than max_char_length is found
67
0.upto(max_char_length - 1) do |i|
68
if wchar_ptr[i].read_wchar == NULL_TERMINATOR_WCHAR
69
return read_wide_string(i)
73
read_wide_string(max_char_length)
76
def read_win32_local_pointer(&block)
83
if FFI::WIN32::LocalFree(ptr.address) != FFI::Pointer::NULL_HANDLE
84
Puppet.debug "LocalFree memory leak"
89
# ptr has already had LocalFree called, so nothing to return
93
def read_com_memory_pointer(&block)
99
FFI::WIN32::CoTaskMemFree(ptr) if ptr && ! ptr.null?
102
# ptr has already had CoTaskMemFree called, so nothing to return
107
alias_method :write_dword, :write_uint32
108
alias_method :write_word, :write_uint16
112
# https://github.com/ffi/ffi/wiki/Types
114
# Windows - Common Data Types
115
# http://msdn.microsoft.com/en-us/library/cc230309.aspx
118
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
120
FFI.typedef :uint16, :word
121
FFI.typedef :uint32, :dword
122
# uintptr_t is defined in an FFI conf as platform specific, either
123
# ulong_long on x64 or just ulong on x86
124
FFI.typedef :uintptr_t, :handle
125
FFI.typedef :uintptr_t, :hwnd
127
# buffer_inout is similar to pointer (platform specific), but optimized for buffers
128
FFI.typedef :buffer_inout, :lpwstr
129
# buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
130
FFI.typedef :buffer_in, :lpcwstr
131
FFI.typedef :buffer_in, :lpcolestr
133
# string is also similar to pointer, but should be used for const char *
134
# NOTE that this is not wide, useful only for A suffixed functions
135
FFI.typedef :string, :lpcstr
137
# pointer in FFI is platform specific
138
# NOTE: for API calls with reserved lpvoid parameters, pass a FFI::Pointer::NULL
139
FFI.typedef :pointer, :lpcvoid
140
FFI.typedef :pointer, :lpvoid
141
FFI.typedef :pointer, :lpword
142
FFI.typedef :pointer, :lpdword
143
FFI.typedef :pointer, :pdword
144
FFI.typedef :pointer, :phandle
145
FFI.typedef :pointer, :ulong_ptr
146
FFI.typedef :pointer, :pbool
147
FFI.typedef :pointer, :lpunknown
149
# any time LONG / ULONG is in a win32 API definition DO NOT USE platform specific width
150
# which is what FFI uses by default
151
# instead create new aliases for these very special cases
152
# NOTE: not a good idea to redefine FFI :ulong since other typedefs may rely on it
153
FFI.typedef :uint32, :win32_ulong
154
FFI.typedef :int32, :win32_long
155
# FFI bool can be only 1 byte at times,
156
# Win32 BOOL is a signed int, and is always 4 bytes, even on x64
157
# http://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
158
FFI.typedef :int32, :win32_bool
160
# Same as a LONG, a 32-bit signed integer
161
FFI.typedef :int32, :hresult
163
# NOTE: FFI already defines (u)short as a 16-bit (un)signed like this:
164
# FFI.typedef :uint16, :ushort
165
# FFI.typedef :int16, :short
168
FFI.typedef :uchar, :byte
169
FFI.typedef :uint16, :wchar
172
extend ::FFI::Library
174
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx
175
# typedef struct _GUID {
181
class GUID < FFI::Struct
182
layout :Data1, :dword,
188
raise 'Bad GUID format.' unless s =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
191
guid[:Data1] = s[0, 8].to_i(16)
192
guid[:Data2] = s[9, 4].to_i(16)
193
guid[:Data3] = s[14, 4].to_i(16)
194
guid[:Data4][0] = s[19, 2].to_i(16)
195
guid[:Data4][1] = s[21, 2].to_i(16)
196
s[24, 12].split('').each_slice(2).with_index do |a, i|
197
guid[:Data4][i + 2] = a.join('').to_i(16)
202
def ==(other) Windows.memcmp(other, self, size) == 0 end
205
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
206
# typedef struct _SYSTEMTIME {
214
# WORD wMilliseconds;
215
# } SYSTEMTIME, *PSYSTEMTIME;
216
class SYSTEMTIME < FFI::Struct
217
layout :wYear, :word,
224
:wMilliseconds, :word
227
Time.local(self[:wYear], self[:wMonth], self[:wDay],
228
self[:wHour], self[:wMinute], self[:wSecond], self[:wMilliseconds] * 1000)
232
ffi_convention :stdcall
234
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa366730(v=vs.85).aspx
235
# HLOCAL WINAPI LocalFree(
239
attach_function :LocalFree, [:handle], :handle
241
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
242
# BOOL WINAPI CloseHandle(
243
# _In_ HANDLE hObject
246
attach_function_private :CloseHandle, [:handle], :win32_bool
248
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms680722(v=vs.85).aspx
249
# void CoTaskMemFree(
253
attach_function :CoTaskMemFree, [:lpvoid], :void