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



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
162
# File 'lib/chef/win32/api/installer.rb', line 133

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
end

#get_product_property(package_path, property_name) ⇒ Object

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



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
112
# File 'lib/chef/win32/api/installer.rb', line 82

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)
  return buffer
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)


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

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
  return pkg_ptr        
end