Module: Chef::ReservedNames::Win32::API::Installer

Extended by:
Chef::ReservedNames::Win32, Chef::ReservedNames::Win32::API
Included in:
Provider::Package::Windows::MSI
Defined in:
lib/chef/win32/api/installer.rb

Instance Method Summary collapse

Instance Method Details

#get_installed_version(product_code) ⇒ Object

All installed product_codes should have a VersionString Returns a version if installed, nil if not installed

[View source]

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/chef/win32/api/installer.rb', line 132

def get_installed_version(product_code)
  version = 0.chr
  version_length = FFI::Buffer.new(:long).write_long(0)

  status = msi_get_product_info(product_code, "VersionString", version, version_length)

  return nil if status == 1605 # ERROR_UNKNOWN_PRODUCT (0x645)

  # We expect error ERROR_MORE_DATA (234) here because we passed a buffer length of 0
  if status != 234
    msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
    msg << Chef::ReservedNames::Win32::Error.format_message(status)
    raise Chef::Exceptions::Package, msg
  end

  # We could fetch the product version now that we know the variable length, but we don't need it here.

  version_length = FFI::Buffer.new(:long).write_long(version_length.read_long + 1)
  version = 0.chr * version_length.read_long

  status = msi_get_product_info(product_code, "VersionString", version, version_length)

  if status != 0
    msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
    msg << Chef::ReservedNames::Win32::Error.format_message(status)
    raise Chef::Exceptions::Package, msg
  end

  version.chomp(0.chr)
end

#get_product_property(package_path, property_name) ⇒ Object

Opens a Microsoft Installer (MSI) file from an absolute path and returns the specified property

[View source]

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/chef/win32/api/installer.rb', line 81

def get_product_property(package_path, property_name)
  pkg_ptr = open_package(package_path)

  buffer = 0.chr
  buffer_length = FFI::Buffer.new(:long).write_long(0)

  # Fetch the length of the property
  status = msi_get_product_property(pkg_ptr.read_pointer, property_name, buffer, buffer_length)

  # We expect error ERROR_MORE_DATA (234) here because we passed a buffer length of 0
  if status != 234
    msg = "msi_get_product_property: returned unknown error #{status} when retrieving #{property_name}: "
    msg << Chef::ReservedNames::Win32::Error.format_message(status)
    raise Chef::Exceptions::Package, msg
  end

  buffer_length = FFI::Buffer.new(:long).write_long(buffer_length.read_long + 1)
  buffer = 0.chr * buffer_length.read_long

  # Fetch the property
  status = msi_get_product_property(pkg_ptr.read_pointer, property_name, buffer, buffer_length)

  if status != 0
    msg = "msi_get_product_property: returned unknown error #{status} when retrieving #{property_name}: "
    msg << Chef::ReservedNames::Win32::Error.format_message(status)
    raise Chef::Exceptions::Package, msg
  end

  msi_close_handle(pkg_ptr.read_pointer)
  buffer.chomp(0.chr)
end

#open_package(package_path) ⇒ Object

Opens a Microsoft Installer (MSI) file from an absolute path and returns a pointer to a handle Remember to close the handle with msi_close_handle()

Raises:

  • (ArgumentError)
[View source]

115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/chef/win32/api/installer.rb', line 115

def open_package(package_path)
  # MsiOpenPackage expects a perfect absolute Windows path to the MSI
  raise ArgumentError, "Provided path '#{package_path}' must be an absolute path" unless Pathname.new(package_path).absolute?

  pkg_ptr = FFI::MemoryPointer.new(:pointer, 4)
  status = msi_open_package(package_path, 1, pkg_ptr)
  case status
  when 0
    # success
  else
    raise Chef::Exceptions::Package, "msi_open_package: unexpected status #{status}: #{Chef::ReservedNames::Win32::Error.format_message(status)}"
  end
  pkg_ptr
end