using System; using System.Runtime.InteropServices; using System.Text; namespace Xpace { #if _WIN64 [StructLayout(LayoutKind.Explicit, Size = 8)] #else [StructLayout(LayoutKind.Explicit, Size = 4)] #endif public unsafe struct Xpace_Error { [FieldOffset(0)] public void* v; } [Serializable] public class XpaceException : ApplicationException, IDisposable { #region DLL calls //void Xpace_String_Destroy // (Xpace_String); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static unsafe extern void Xpace_String_Destroy (char* str); //XPACE_EXPORT Xpace_Error Xpace_Error_Copy // (Xpace_Error); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static extern Xpace_Error Xpace_Error_Copy (Xpace_Error err); //XPACE_EXPORT void Xpace_Error_Destroy // (Xpace_Error); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static extern void Xpace_Error_Destroy (IntPtr err); //XPACE_EXPORT Xpace_Error Xpace_Error_Why // (Xpace_Error); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static extern IntPtr Xpace_Error_Why (IntPtr err); //XPACE_EXPORT const Xpace_String Xpace_Error_getTemplate // (Xpace_Error); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static extern IntPtr Xpace_Error_getTemplate (IntPtr err); //XPACE_EXPORT const Xpace_String Xpace_Error_getMessage // (const Xpace_Error, // const Xpace_String templ); [DllImport("xpace.dll", CharSet = CharSet.Unicode)] private static extern IntPtr Xpace_Error_getMessage (IntPtr err, [MarshalAs(UnmanagedType.LPWStr)] String templ); #endregion #region private data private IntPtr _err; // the Xpace_Error private readonly bool _destroy_xpace_error = false; // true only for the top-level error private bool _disposed = false; #endregion #region Constructor / Destructor public XpaceException () { } public XpaceException (string msg, Exception inner) : base(msg, inner) { } protected XpaceException (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } /// /// Construct from an IntPtr representing an Xpace_Error /// /// The Xpace_Error public XpaceException (IntPtr err) : base(get_msg(err)) { _destroy_xpace_error = true; _err = err; } /// /// Private constructor from an IntPtr representing Xpace_Error, used to create why() exceptions /// /// The Xpace_Error /// Always false (so the underlying Xpace_Error won't be destroyed.) private unsafe XpaceException (IntPtr err, bool destroy) : base(get_msg(err)) { _destroy_xpace_error = destroy; _err = err; } public void Dispose () { CleanUp(); GC.SuppressFinalize(this); } public void CleanUp () { if (!_disposed) { if (_destroy_xpace_error) Xpace_Error_Destroy(_err); _disposed = true; } } ~XpaceException () { CleanUp(); } #endregion #region public functions /// /// Get the exception that caused this one (if any) /// public XpaceException why { get { unsafe { return new XpaceException(Xpace_Error_Why(_err), false); } } } /// /// Get the English template for the exception's message. /// public string template { get { unsafe { if (_err == null) return String.Empty; IntPtr s = Xpace_Error_getTemplate(_err); string ret = Marshal.PtrToStringUni(s); Xpace_String_Destroy((char*)s); return ret; } } } /// /// Translate the message using template. /// /// The translation of the English template returned by getTemplate. /// The translated message. public string translateMessage (string template) { unsafe { if (_err == null) return Message; IntPtr s = Xpace_Error_getMessage(_err, template); string ret = Marshal.PtrToStringUni(s); Xpace_String_Destroy((char*)s); return ret; } } #endregion #region private function /// /// Used to set the exception's message to be English /// /// The Xpace_Error /// The message static private string get_msg (IntPtr err) { unsafe { IntPtr s = Xpace_Error_getMessage(err, null); return Marshal.PtrToStringUni(s); } } #endregion } }