[Mono-list] Need help with DllImport (P/Invoke) and UCS-4 unicode

Jonathan Pryor jonpryor at vt.edu
Mon Jul 16 06:08:04 EDT 2007


On Mon, 2007-07-16 at 02:57 +0200, Christian Heimes wrote:
> One of the problematic function look like:
> 
>     [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
>            EntryPoint = "PyUnicodeUCS4_FromUnicode",
>            ExactSpelling = true, CharSet = CharSet.Unicode)]
>     internal unsafe static extern IntPtr
>     PyUnicode_FromUnicode(string s, int size);
> 
> More functions can be found at
> https://pythonnet.svn.sourceforge.net/svnroot/pythonnet/branches/clr-2.0-python-2.5-branch/src/runtime/runtime.cs
> 
> How should I solve the issue? Has Mono some generic solution for the
> general issue of UCS-4 vs. UCS-2 unicode

No.

>  or do I have to convert the
> stuff manually by wrapping every external method?

Yes.  Or use a custom marshaler as Jonathan Chambers suggested.

> If I have to convert
> it manually is System.Text.Encoding.UTF32 the right module?

Yes.

What you'd basically need to do is:

        [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl)]
        internal unsafe static extern IntPtr
        PyUnicode_FromUnicode(IntPtr s, int size);

To manually call:

        string s = ".NET string";
        IntPtr p = Mono.Unix.UnixMarshal.StringToHeap (s,
        	System.Text.Encoding.UTF32);
        try {
        	PyUnicode_FromUnicode (p, s.Length);
        }
        finally {
        	Mono.Unix.UnixMarshal.FreeHeap (p);
        }

This uses the Mono.Unix.UnixMarshal class within Mono.Posix.dll.

For a custom marshaler, your DllImport would be:

        [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl)]
        internal unsafe static extern IntPtr
        PyUnicode_FromUnicode(
                [MarshalAs (UnmanagedType.CustomMarshaler, 
                 MarshalTypeRef=typeof(Utf32Marshaler)]
                string path, int size);

with a custom marshaler similar to:

        class Utf32Marshaler : ICustomMarshaler {
                private static Utf32Marshaler instance = new
                Utf32Marshaler ();
                
                public static ICustomMarshaler GetInstance (string s)
                {
                        return instance;
                }
                
                public void CleanUpManagedData (object o)
                {
                }
                
                public void CleanUpNativeData (IntPtr pNativeData)
                {
                        UnixMarshal.FreeHeap (pNativeData);
                }
                
                public int GetNativeDataSize ()
                {
                        return IntPtr.Size;
                }
                
                public IntPtr MarshalManagedToNative (object obj)
                {
                        string s = obj as string;
                        if (s == null)
                                return IntPtr.Zero;
                        return UnixMarshal.StringToHeap (s,
                        Encoding.UTF32);
                }
                
                public object MarshalNativeToManaged (IntPtr
                pNativeData)
                {
                        return UnixMarshal.PtrToString (pNativeData, 
                                Encoding.UTF32);
                }
        }

This permits easier usage:

        string s = ".NET string";
        PyUnicode_FromUnicode (s, s.Length);

at the cost of greater runtime overhead to invoke the custom marshaler
(which hopefully won't be too significant, but it depends on how often
it's invoked compared to doing "real work").

 - Jon




More information about the Mono-list mailing list