//-----------------------------------------------------------------------------
// wx.NET - wxString.cs
//
// The wxString wrapper class.
//
// Written by Bryan Bulten (bryan@bulten.ca)
// (C) 2003 Bryan Bulten
// major changes 2006 Dr. Harald Meyer auf'm Hofe
// Licensed under the wxWidgets license, see LICENSE.txt for details.
//
// $Id: wxString.cs,v 1.24 2007/12/08 23:21:15 harald_meyer Exp $
//-----------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
namespace wx{
/** Wrapper for the \e wxWidgets string class \c wxString.
*
* Objectives:
* \li Several \c wx.NET implementations interchange string data with the used \e wxWidgets library.
* Conversion from .NET strings to \e wxWidgets strings shall be hidden. .NET implementations shall
* be able to use something like a lazy conversion: Simply getting a string from one method of
* \e wxWidgets and sending it to another shall be possible without conversion to .NET strings.
* \li \e wxWidgets class might be compiled in Unicode or ANSI mode. This shall be hidden completely to
* the \c wx.NET implementation.
*
* The changed implementation follows the guidelines of the \e wxWidgets manual for implementations.
* The internal character encoding within the .NET framework is uniquely defined to UTF 16.
* The used constructors and selectors use an explicit conversion as argument (on the \c wx-c side)
* to convert from or to this encoding. So, the interface provided by \c wx-c is always UTF 16 whether
* the library is able to represent such strings internally or not.
* An \c MarshalAsAttribute is used to define a more verbatim marshalling scheme on DLL import.
*
* So, any kind of conversion is done by \e wxWidgets (if necessary) and not by the .NET framework.
*
* Refer to wxWCharBuffer and DisposableStringBox for remarks on helper classes for dealing with strings.
*/
public class wxString : Object
{
[DllImport("wx-c")] static extern IntPtr wxString_ctorUTF16([MarshalAs(UnmanagedType.LPWStr)]string str);
[DllImport("wx-c")] static extern IntPtr wxString_ctorUTF8([MarshalAs(UnmanagedType.LPWStr)]string str);
[DllImport("wx-c")] static extern void wxString_dtor(IntPtr self);
[DllImport("wx-c")] [return: MarshalAs(UnmanagedType.U2)] static extern char wxString_CharAtUTF16(IntPtr self, int pos);
[DllImport("wx-c")] static extern int wxString_GetLength(IntPtr self);
[DllImport("wx-c")] static extern IntPtr wxString_Conversion(IntPtr self);
//---------------------------------------------------------------------
public wxString(IntPtr wxObject)
: base(wxObject, Object.StorageMode.VolatileObject)
{
this.wxObject = wxObject;
}
internal wxString(IntPtr wxObject, bool memOwn)
: base(wxObject, Object.StorageMode.VolatileObject, memOwn)
{
this.wxObject = wxObject;
}
public wxString()
: this("") { }
#if WXNET_INTERNAL_USE_UTF8
public wxString(string str)
: this(wxString_ctorUTF8(str), true)
{
}
#else
public wxString(string str)
: this(wxString_ctorUTF16(str), true)
{
}
#endif
/** This will safely create an instance of wx.wxString without throwing exceptions on argument \c null.
* Instead the method will return result \c null on argument \c null.
*/
public static wxString SafeNew(string str)
{
if (str == null)
return null;
else
return new wxString(str);
}
//---------------------------------------------------------------------
public override void Dispose()
{
if (!disposed)
{
if (wxObject != IntPtr.Zero)
{
if (memOwn)
{
wxString_dtor(wxObject);
memOwn = false;
}
}
RemoveObject(wxObject);
wxObject = IntPtr.Zero;
--validInstancesCount;
disposed = true;
}
base.Dispose();
GC.SuppressFinalize(this);
}
//---------------------------------------------------------------------
~wxString()
{
Dispose();
}
//---------------------------------------------------------------------
public static implicit operator string(wxString str)
{
if (str == null) return null;
return str.ToString();
}
/** Conversion of \c wxString into a string.
* This method works different on Unicode- and ANSI-builds of \e wxWidgets.
* On Unicode builds we can directly refer to the internal buffer using
* the indexer of this class. Otherwise we read a wxWCharBuffer and convert this.
*
* Special case: PNET with internal UTF8 character encoding if \c WXNET_INTERNAL_USE_UTF8.
* In this case, we always have to decode.
* */
public override string ToString()
{
#if WXNET_INTERNAL_USE_UTF8
wxWCharBuffer conversion = new wxWCharBuffer(wxString_ConversionUTF8(this.wxObject));
return conversion.ToString();
#else
if (ReflectConfig.CheckUseUnicode())
{
int length = this.Length;
char[] result = new char[length];
for (int i = 0; i < length; ++i)
result[i] = this[i];
return new string(result);
}
else
{
wxWCharBuffer conversion = new wxWCharBuffer(wxString_Conversion(this.wxObject));
return conversion.ToString();
}
#endif
}
/*
public static implicit operator wxString (string str)
{
if (str == null) return null;
return new wxString(str);
}
*/
//---------------------------------------------------------------------
/** Get the n-th character.
* Returns a 2 byte UTF16 character. Only \c get implemented.
* Undefined positions will result in a 0.
* This works perfect on a Unicode build (ReflectConfig.CheckUseUnicode)
* since internal characer encoding of \c wxString is the same as the encoding
* in C#. On ANSI builds this will return blanks as replacemetns of non-ascii
* characters.
*
* Correction: Microsoft and Mono use UTF16 as internal string representation just
* like \c wxWidgets with wide character Unicode support compiled in. However, PNET
* seems to use UTF 8 instead. If this assumes internal UTF 8 strings, this method
* will return ASCII only.
*/
public char this[int n]
{
get
{
#if WXNET_INTERNAL_USE_UTF8
char result=wxString_CharAtUTF16(wxObject, n);
if (result < 0 || result >= 128)
return ' ';
else
return result;
#else
return wxString_CharAtUTF16(wxObject, n);
#endif
}
}
//---------------------------------------------------------------------
/** Returns the length of the encapsulated string.
*/
public int Length
{
get
{
return wxString_GetLength(wxObject);
}
}
//---------------------------------------------------------------------
internal static IntPtr SafePtr(wxString obj)
{
return (obj == null) ? IntPtr.Zero : obj.wxObject;
}
}
/** This is a wrapper for the \e wxWidgets class of the same type.
* This class is required for interchanging strings with ANSI builds of \e wxWidgets.
* In such situations, we have to request the \c wxString, that internally holds an
* ANSI representation, into a wide character UTF-16 string buffer.
* */
public class wxWCharBuffer : Object
{
[DllImport("wx-c")]
static extern IntPtr wxWCharBuffer_ctorUTF16([MarshalAs(UnmanagedType.LPWStr)]string str);
[DllImport("wx-c")]
static extern void wxWCharBuffer_dtor(IntPtr self);
[DllImport("wx-c")] [return: MarshalAs(UnmanagedType.U2)]
static extern char wxWCharBuffer_WideCharAt(IntPtr self, int pos);
[DllImport("wx-c")]
static extern bool wxWCharBuffer_IsEmpty(IntPtr self);
[DllImport("wx-c")]
static extern int wxWCharBuffer_GetLength(IntPtr self);
//---------------------------------------------------------------------
public wxWCharBuffer(IntPtr wxObject)
: base(wxObject)
{
this.wxObject = wxObject;
}
internal wxWCharBuffer(IntPtr wxObject, bool memOwn)
: base(wxObject)
{
this.memOwn = memOwn;
this.wxObject = wxObject;
}
public wxWCharBuffer()
: this("") { }
public wxWCharBuffer(string str)
: this(wxWCharBuffer_ctorUTF16(str), true) { }
//---------------------------------------------------------------------
public override void Dispose()
{
if (!disposed)
{
--validInstancesCount;
if (wxObject != IntPtr.Zero)
{
if (memOwn)
{
wxWCharBuffer_dtor(wxObject);
memOwn = false;
}
}
RemoveObject(wxObject);
wxObject = IntPtr.Zero;
disposed = true;
}
base.Dispose();
GC.SuppressFinalize(this);
}
//---------------------------------------------------------------------
~wxWCharBuffer()
{
Dispose();
}
//---------------------------------------------------------------------
#region Public Properties
public bool IsEmpty
{
get { return wxWCharBuffer_IsEmpty(this.wxObject); }
}
public int Length
{
get { return wxWCharBuffer_GetLength(this.wxObject); }
}
#endregion
/** Conversion into a string.
* Copies character by character into a .NET string.
*/
public override string ToString()
{
int length = this.Length;
char[] result = new char[length];
for (int i = 0; i < length; ++i)
{
result[i] = this[i];
}
return new string(result);
}
public char this[int n]
{
get
{
return wxWCharBuffer_WideCharAt(this.wxObject, n);
}
}
}
/** This is a box for instances of wxString that calls wxString.Dispose() on deletion of the box and deletes the string instance.
* Use this class to pass instances of wxString from C# callbacks implementing virtual methods.
* Refer to \c wx.ListCtrl.OnDoGetItemText() for an example.
*/
internal class DisposableStringBox : Object
{
[DllImport("wx-c")]
static extern IntPtr DisposableStringBox_CTor(IntPtr val);
[DllImport("wx-c")]
static extern void DisposableStringBox_RegisterDispose(IntPtr self, Virtual_Dispose virtualDispose);
wxString _val;
static int validStringsCount = 0;
/** This is the number of valid string instances.
*/
new public static int InstancesCount { get { return validStringsCount; } }
public DisposableStringBox(wxString val)
: base(DisposableStringBox_CTor(val.wxObject))
{
virtual_Dispose = new Virtual_Dispose(VirtualDispose);
DisposableStringBox_RegisterDispose(this.wxObject, virtual_Dispose);
this._val = val;
++validStringsCount;
}
new internal void VirtualDispose()
{
base.VirtualDispose();
--validStringsCount;
this._val.VirtualDispose();
this._val = null;
}
public override string ToString()
{
return string.Format("DisposableStringBox({0})", this._val);
}
}
}
|