Skip to content

Instantly share code, notes, and snippets.

@adamedx
Created January 14, 2014 19:07
Show Gist options
  • Save adamedx/8423887 to your computer and use it in GitHub Desktop.
Save adamedx/8423887 to your computer and use it in GitHub Desktop.
Quick script to read a property from a Windows Installer file
#!/usr/bin/env ruby
current_dir = File.dirname(__FILE__)
require 'ffi'
module Win32
extend FFI::Library
ffi_lib 'msi'
attach_function :msi_open_package_ex,
:MsiOpenPackageExA, [:string, :long, :pointer], :int
end
module Win32
extend FFI::Library
ffi_lib 'msi'
attach_function :msi_close_handle,
:MsiCloseHandle, [:pointer], :int
end
module Win32
extend FFI::Library
ffi_lib 'kernel32'
attach_function :local_free,
:LocalFree, [ :pointer ], :long
end
module Win32
extend FFI::Library
ffi_lib 'msi'
attach_function :msi_get_product_property,
:MsiGetProductPropertyA, [:pointer, :pointer, :pointer, :pointer], :int
end
module Win32
extend FFI::Library
ffi_lib 'msi'
attach_function :msi_open_database,
:MsiOpenDatabaseA, [:pointer, :pointer, :pointer], :int
end
def print_usage
puts "Usage:\n"
puts "\tmsiprop <package path> <property name> [property name2] [property name 3]...\n"
puts
end
if ( ARGV.length < 2 )
print_usage
exit 1
end
package_path = ARGV[0]
properties = Array.new(ARGV.length - 1)
properties.length.times do | index |
properties[index] = ARGV[index + 1]
end
def show_package_properties(package_path, property_names)
properties = get_package_properties(package_path, property_names)
properties.each_pair do | property |
puts "#{property[0]}:\t #{property[1]}"
end
puts
end
def get_package_properties(package_path, property_names)
package_handle_result = FFI::MemoryPointer.new(:pointer, 4)
status = Win32.msi_open_package_ex(package_path, 1, package_handle_result)
# status = Win32.msi_open_database(package_path, nil, package_handle_result)
raise RuntimeError, "MsiOpenPackageEx failed with status #{status}" if status != 0
results = {}
begin
property_names.each do | property_name |
property_value = get_package_property(package_handle_result.read_pointer, property_name)
if property_value && ! property_value.empty?
results[property_name] = property_value
end
end
ensure
Win32.msi_close_handle(package_handle_result.read_pointer)
end
results
end
def get_package_property(msi_handle, property_name)
property_value = 0.chr
property_length = FFI::Buffer.new(:long).write_long(0)
status = Win32.msi_get_product_property(
msi_handle,
property_name,
property_value,
property_length)
if ( status != 234 )
raise "Unexpected status #{status}"
end
new_property_size = FFI::Buffer.new(:long).write_long(property_length.read_long + 1)
property_value = 0.chr * new_property_size.read_long
status = Win32.msi_get_product_property(
msi_handle,
property_name,
property_value,
new_property_size)
if status != 0
raise RuntimeError, "MsiGetProductProperty Failed with status #{status}"
end
property_value
end
show_package_properties(package_path, properties)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment