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
}
}