note
	description: "[
		Exception for a COM error
	]"
	library: "Free implementation of ELKS library"
	status: "See notice at end of class."
	legal: "See notice at end of class."
	date: "$Date: 2020-05-19 14:32:38 +0000 (Tue, 19 May 2020) $"
	revision: "$Revision: 104260 $"

class 
	COM_FAILURE

inherit
	OPERATING_SYSTEM_EXCEPTION

create 
	default_create

feature -- Access

	hresult: INTEGER_32
			-- Original HRESULT.

	hresult_code: INTEGER_32
			-- Error code of COM

	code: INTEGER_32
			-- Exception code
		do
			Result := {EXCEP_CONST}.com_exception
		end

	Tag: IMMUTABLE_STRING_32
			-- A short message describing what current exception is
		once
			create Result.make_from_string_8 ("COM error.")
		end
	
feature -- Status setting

	set_hresult_code (a_code: like hresult_code)
			-- Set hresult_code with a_code.
		do
			hresult_code := a_code
		end

	hresult_facility: INTEGER_32
			-- Facility code.
		do
			Result := ccom_hresult_facility (hresult)
		end

	hresult_message: STRING_8
			-- Error message.
		local
			r: detachable STRING_8
		do
			r := exception_information
			if r /= Void then
				r := r.twin;
				r.remove_head (10);
				r.adjust
			end
			if r = Void or else r.is_empty and then hresult_code > 0 then
				r := error_message (hresult_code).out
			end
			if r = Void then
				create Result.make_empty
			else
				Result := r
			end
		ensure
			non_void_message: Result /= Void
		end
	
feature -- Element Change

	trigger (a_code: INTEGER_32)
			-- Raise exception with code code.
			-- See class ECOM_EXCEPTION_CODES in EiffelCom for possible values.
		local
			l_hresult_string: STRING_8
		do
			hresult_code := a_code
			l_hresult_string := ccom_hresult_to_string (a_code)
			set_description (l_hresult_string)
			set_exception_information (l_hresult_string)
			raise
		end
	
feature {EXCEPTION_MANAGER} -- Implementation

	exception_information: detachable STRING_8
			-- Stream holding exception information.

	set_exception_information (a_message: STRING_8)
			-- Initialize current with stream of a_message.
		require
			a_message_not_void: a_message /= Void
		local
			c_string: C_STRING
		do
			exception_information := a_message
			if hresult_code > 0 then
				create c_string.make (ccom_hresult_to_string (hresult_code))
				hresult := ccom_hresult (c_string.item)
			else
				create c_string.make (a_message)
				hresult := ccom_hresult (c_string.item)
				hresult_code := ccom_hresult_code (hresult)
			end
		end
	
feature {NONE} -- Implementation

	frozen ccom_hresult_to_string (a_code: INTEGER_32): STRING_8
		do
			Result := a_code.to_hex_string
			Result := {STRING_8}"0x" + Result
		end

	frozen ccom_hresult (an_exception_code: POINTER): INTEGER_32
		external
			"C inline"
		alias
			"[
						#ifdef EIF_WINDOWS
							char *stopstring = NULL;
							long result = 0, high_bits = 0, low_bits = 0;
							char high_str [7];
							char *exception_code = (char *)($an_exception_code);
							  
							if (NULL != exception_code)
							{
								strncpy (high_str, exception_code, 6);
								high_str [6] = '\0';
				
								high_bits = strtol (high_str, &stopstring, 16);
								low_bits = strtol (exception_code + 6, &stopstring, 16);
								result = (high_bits << 16) + low_bits;
							}
							return (EIF_INTEGER)result;
						#else
							return 0;
						#endif
			]"
		end

	frozen ccom_hresult_code (an_hresult: INTEGER_32): INTEGER_32
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					return HRESULT_CODE($an_hresult);
				#else
					return 0;
				#endif
			]"
		end

	frozen ccom_hresult_facility (an_hresult: INTEGER_32): INTEGER_32
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					return HRESULT_FACILITY($an_hresult);
				#else
					return 0;
				#endif
			]"
		end

	frozen cwin_error_text (a_code: INTEGER_32): POINTER
			-- Get text from error a_code. It is up to the caller to free
			-- the returned buffer using cwin_local_free.
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					LPVOID result;
					FormatMessage( 
						FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
						NULL,
						$a_code,
						MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
						(LPTSTR) &result,
						0,
						NULL 
						);
					return result;
				#else
					return 0;
				#endif
			]"
		end

	frozen c_strlen (ptr: POINTER): INTEGER_32
			-- Number of characters in ptr.
			-- (export status {NONE})
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					return (EIF_INTEGER_32) _tcslen ((wchar_t *) $ptr);
				#else
					return 0;
				#endif
			]"
		end

	frozen character_size: INTEGER_32
			-- Number of bytes occupied by a TCHAR.
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					return sizeof(TCHAR);
				#else
					return 0;
				#endif
			]"
		end

	frozen cwin_local_free (a_ptr: POINTER)
			-- Free a_ptr using LocalFree.
		external
			"C inline use %"eif_com_exception.h%""
		alias
			"[
				#ifdef EIF_WINDOWS
					LocalFree((HLOCAL) $a_ptr);
				#endif
			]"
		end
	
feature {NONE} -- Accesss

	error_message (a_code: like hresult_code): STRING_32
		require
			a_code_non_negative: a_code >= 0
		local
			l_ptr: POINTER
			l_mptr: MANAGED_POINTER
			i, n: INTEGER_32
		do
			l_ptr := cwin_error_text (a_code)
			if l_ptr = default_pointer then
				Result := {STRING_32}""
			else
				from
					i := 0
					n := c_strlen (l_ptr)
					create l_mptr.make_from_pointer (l_ptr, n * character_size)
					create Result.make (n)
				until
					i = n
				loop
					Result.append_code (l_mptr.read_natural_16 (i * character_size).to_natural_32)
					i := i + 1
				end
				cwin_local_free (l_ptr)
			end
		ensure
			error_message_not_void: Result /= Void
		end
	
note
	copyright: "Copyright (c) 1984-2020, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class COM_FAILURE

Generated by ISE EiffelStudio