# encoding: ascii-8bit # Copyright 2022 Ball Aerospace & Technologies Corp. # All Rights Reserved. # # This program is free software; you can modify and/or redistribute it # under the terms of the GNU Affero General Public License # as published by the Free Software Foundation; version 3 with # attribution addendums as found in the LICENSE.txt # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # Modified by OpenC3, Inc. # All changes Copyright 2022, OpenC3, Inc. # All Rights Reserved # # This file may also be used under the terms of a commercial license # if purchased from OpenC3, Inc. module OpenC3 if RUBY_ENGINE == 'ruby' # Win32API is deprecated in 1.9.x so recreate it require 'fiddle' POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*' class Win32API # Cache to hold already opened dll files DLL_CACHE = {} VALUE_TYPEMAP = { "0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG } def initialize(dll_name, function_name, import, export = "0") # Convert all input parameters into either 0, S, or I @function_prototype = [import].join.tr("VPpNnLlIiCc", "0SSI") params = [] @function_prototype.split('').each do |param| params << VALUE_TYPEMAP[param] end # Get handle to dll file and add to cache if necessary dll_handle = DLL_CACHE[dll_name] ||= Fiddle.dlopen(dll_name) # Create Fiddle::Function necessary to call a function with proper return type and name @function = Fiddle::Function.new(dll_handle[function_name], params, VALUE_TYPEMAP[export.tr("VPpNnLlIi", "0SSI")]) end def call(*args) # Break up prototype into characters import = @function_prototype.split('') args.each_with_index do |arg, index| case import[index] when 'S' # Handle NULL specified with 0 value arg = nil if arg == 0 # Convert argument into array of longs args[index], = [arg].pack("p").unpack(POINTER_TYPE) when 'I' # Handle integers larger than 2^31 - 1 args[index], = [arg].pack("I").unpack("i") end end # Call the function and return its return value return_value = @function.call(*args) return_value ||= 0 return_value end # Make an equivalent capital C call method alias Call call end else require 'Win32API' end # Win32 class # # This class implements the Win32 # class Win32 # Data Types BOOL = 'i' BYTE = 'C' DWORD = 'L' HANDLE = 'L' LP = 'P' LPSECURITY_ATTRIBUTES = DWORD # Misc Constants NULL = 0 INVALID_HANDLE_VALUE = -1 # Generic Rights (WinNT.h) GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 GENERIC_EXECUTE = 0x20000000 GENERIC_ALL = 0x10000000 # File Sharing (WinNT.h) FILE_UNSHARED = 0x00000000 # not defined in WinNT.h FILE_SHARE_READ = 0x00000001 FILE_SHARE_WRITE = 0x00000002 FILE_SHARE_DELETE = 0x00000004 # File Open Options (WinBase.h) CREATE_NEW = 1 CREATE_ALWAYS = 2 OPEN_EXISTING = 3 OPEN_ALWAYS = 4 TRUNCATE_EXISTING = 5 # File Attributes (WinNT.h) FILE_ATTRIBUTE_READONLY = 0x00000001 FILE_ATTRIBUTE_HIDDEN = 0x00000002 FILE_ATTRIBUTE_SYSTEM = 0x00000004 FILE_ATTRIBUTE_DIRECTORY = 0x00000010 FILE_ATTRIBUTE_ARCHIVE = 0x00000020 FILE_ATTRIBUTE_DEVICE = 0x00000040 FILE_ATTRIBUTE_NORMAL = 0x00000080 FILE_ATTRIBUTE_TEMPORARY = 0x00000100 FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 FILE_ATTRIBUTE_COMPRESSED = 0x00000800 FILE_ATTRIBUTE_OFFLINE = 0x00001000 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 FILE_ATTRIBUTE_VIRTUAL = 0x00010000 # Baud Rates CBR_110 = 110 CBR_300 = 300 CBR_600 = 600 CBR_1200 = 1200 CBR_2400 = 2400 CBR_4800 = 4800 CBR_9600 = 9600 CBR_14400 = 14400 CBR_19200 = 19200 CBR_38400 = 38400 CBR_56000 = 56000 CBR_57600 = 57600 CBR_115200 = 115200 CBR_128000 = 128000 CBR_256000 = 256000 BAUD_RATES = [ CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 3000000, 3500000, 4000000 ] # Parity NOPARITY = 0 ODDPARITY = 1 EVENPARITY = 2 MARKPARITY = 3 SPACEPARITY = 4 PARITY_SETTINGS = [NOPARITY, ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY] # Stop Bits ONESTOPBIT = 0 ONE5STOPBITS = 1 TWOSTOPBITS = 2 STOP_BIT_SETTINGS = [ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS] # Dialog Box Command Ids IDOK = 1 IDCANCEL = 2 IDABORT = 3 IDRETRY = 4 IDIGNORE = 5 IDYES = 6 IDNO = 7 IDCLOSE = 8 IDHELP = 9 # Message Box Types MB_OK = 0x00000000 MB_OKCANCEL = 0x00000001 MB_ABORTRETRYIGNORE = 0x00000002 MB_YESNOCANCEL = 0x00000003 MB_YESNO = 0x00000004 MB_RETRYCANCEL = 0x00000005 # Message Box Icons MB_ICONHAND = 0x00000010 MB_ICONQUESTION = 0x00000020 MB_ICONEXCLAMATION = 0x00000030 MB_ICONASTERISK = 0x00000040 # Heap Information Types HEAP_COMPATIBILITY_INFORMATION = 0 HEAP_ENABLE_TERMINATION_ON_CORRUPTION = 1 # Heap Information Values HEAP_STANDARD = 0 HEAP_LOOKASIDE = 1 HEAP_LOW_FRAGMENTATION = 2 # Open Filename Constants OFN_READONLY = 0x00000001 OFN_OVERWRITEPROMPT = 0x00000002 OFN_HIDEREADONLY = 0x00000004 OFN_NOCHANGEDIR = 0x00000008 OFN_SHOWHELP = 0x00000010 OFN_ENABLEHOOK = 0x00000020 OFN_ENABLETEMPLATE = 0x00000040 OFN_ENABLETEMPLATEHANDLE = 0x00000080 OFN_NOVALIDATE = 0x00000100 OFN_ALLOWMULTISELECT = 0x00000200 OFN_EXTENSIONDIFFERENT = 0x00000400 OFN_PATHMUSTEXIST = 0x00000800 OFN_FILEMUSTEXIST = 0x00001000 OFN_CREATEPROMPT = 0x00002000 OFN_SHAREAWARE = 0x00004000 OFN_NOREADONLYRETURN = 0x00008000 OFN_NOTESTFILECREATE = 0x00010000 OFN_NONETWORKBUTTON = 0x00020000 OFN_NOLONGNAMES = 0x00040000 OFN_EXPLORER = 0x00080000 OFN_NODEREFERENCELINKS = 0x00100000 OFN_LONGNAMES = 0x00200000 OFN_ENABLEINCLUDENOTIFY = 0x00400000 OFN_ENABLESIZING = 0x00800000 OFN_DONTADDTORECENT = 0x02000000 OFN_FORCESHOWHIDDEN = 0x10000000 OFN_EX_NOPLACESBAR = 0x00000001 # Format Message Settings FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100 FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200 FORMAT_MESSAGE_FROM_STRING = 0x00000400 FORMAT_MESSAGE_FROM_HMODULE = 0x00000800 FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF # Primary Language Ids LANG_NEUTRAL = 0x00 # Sub Language Ids SUBLANG_DEFAULT = 0x01 SUBLANG_SYS_DEFAULT = 0x02 # Calculate a language id def self.make_lang_id(primary_language_id, sub_language_id) (sub_language_id << 10) | primary_language_id end # Creates a Message Box def self.message_box(message, title = 'Error', options = 0) Win32API.new('user32', 'MessageBox', ['L', 'P', 'P', 'L'], 'I').call(0, message, title, options) end # Gets the window handle for the foreground window or NULL def self.get_foreground_window Win32API.new('user32', 'GetForegroundWindow', [], 'I').call() end # Gets the error code of the most recent error def self.get_last_error Win32API.new("Kernel32", "GetLastError", [], "I").call end # Formats a message def self.format_message(flags, source, message_id, language_id) buffer = ' ' * 1024 api = Win32API.new('Kernel32', 'FormatMessage', [DWORD, LP, DWORD, DWORD, LP, DWORD, LP], DWORD) buffer_length = api.call(flags, source, message_id, language_id, buffer, buffer.length, NULL) if buffer_length == 0 '' else buffer[0..(buffer_length - 1)] end end # Gets the error message from the last error def self.get_last_error_message last_error = Win32.get_last_error language_id = Win32.make_lang_id(LANG_NEUTRAL, SUBLANG_DEFAULT) Win32.format_message(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, language_id) end # Returns the computer name def self.computer_name name = ' ' * 128 size = [name.length].pack('i') Win32API.new('kernel32', 'GetComputerName', ['P', 'P'], 'I').call(name, size) name.unpack('A*')[0] end # Returns current logged in Windows user name def self.user_name name = ' ' * 128 size = [name.length].pack('i') Win32API.new('advapi32', 'GetUserName', ['P', 'P'], 'I').call(name, size) name.unpack('A*')[0] end # Get the Process's Heap Handle def self.get_process_heap Win32API.new('Kernel32', 'GetProcessHeap', [], 'i').call end # Set Heap Information def self.heap_set_information(heap_handle, heap_information_type, value) heap_info = [value].pack('i') api = Win32API.new('Kernel32', 'HeapSetInformation', ['i', 'i', 'P', 'i'], 'i') return_value = api.call(heap_handle, heap_information_type, heap_info, heap_info.length) raise "HeapSetInformation Error: #{get_last_error_message()}" if return_value == 0 end # Get Heap Information def self.heap_query_information(heap_handle, heap_information_type) heap_info = ' ' * 8 size = ' ' * 8 api = Win32API.new('Kernel32', 'HeapQueryInformation', ['i', 'i', 'P', 'i', 'P'], 'i') api.call(heap_handle, heap_information_type, heap_info, heap_info.length, size) heap_info.unpack("i")[0] end # Enable the Low Fragmentation Heap def self.enable_low_fragmentation_heap(heap_handle) heap_set_information(heap_handle, HEAP_COMPATIBILITY_INFORMATION, HEAP_LOW_FRAGMENTATION) heap_info = heap_query_information(heap_handle, HEAP_COMPATIBILITY_INFORMATION) raise "Unable to enable Low Fragmentation Heap" if heap_info != HEAP_LOW_FRAGMENTATION end end # class Win32 end