[Mono-list] DllImport ... help

Jonathan Pryor jonpryor@vt.edu
18 Jun 2002 21:39:26 -0400

Content-Type: text/plain
Content-Transfer-Encoding: 7bit

What happens if `getname' takes `wchar_t*'?  An

The exception is due to two things:
  - .NET appears to marshal as `char' by default, not `wchar_t'
  - Because of the above, `wcsncpy' (the logical equivalent to
    `strncpy') winds up copying *way* past the buffer that .NET 

Marshaling is particularly apparent, because if you make the passed
capacity sufficiently small enough that you can *ensure* you won't
over-write your bounds:

	getname(sb, sb.Capacity/8);

when you write it you'll only get the first character of the passed
string.  Try it.  It's very enlightening.

The fix is to attach a `MarshalAs' attribute, specifying that a
wide-character string should be marshalled.

	private static extern int wgetname(
	    [Out, MarshalAs(UnmanagedType.LPWStr)]
	    StringBuilder sb,
	    uint n);

See the attached example files.

 - Jon

On Mon, 2002-06-17 at 14:05, Paolo Molaro wrote:
    On 06/15/02 Jonathan Pryor wrote:
    > For example, the following works with .NET
    > 	// native.c
    > 	// Native library
    > 	#include <string.h>
    > 	#ifdef _MSC_VER
    > 	__declspec(dllexport)
    > 	#endif
    > 	int getname(char* s, unsigned int n)
    > 	{
    > 	    const char m[] = "This is my message.  Isn't it nice?";
    > 	    strncpy(s, m, n);
    > 	    return 0;
    > 	}
    > 	public class ghbn {
    > 	  [DllImport("native")]
    > 	  private static extern int getname(
    > 	    StringBuilder sb, 
    > 	    uint len);
    What happens if getname() takes a wchar_t? Do you have to specify
    additional information in a MarshalAs attribute?
    BTW, if anyone can find the documentation that the class docs calls
    "Data Marshaling Specification" I'll be grateful.
    lupus@debian.org                                     debian/rules
    lupus@ximian.com                             Monkeys do it better
    Mono-list maillist  -  Mono-list@ximian.com

Content-Disposition: attachment; filename=managed.cs
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; name=managed.cs; charset=UTF-8

// call the native function...=0D
using System;=0D
using System.Text;=0D
using System.Runtime.InteropServices;=0D
public class managed {=0D
    private static extern int wgetname(=0D
        [Out, MarshalAs(UnmanagedType.LPWStr)]=0D
        StringBuilder sb,=20=0D
        uint n);=0D
    private static extern int getname(StringBuilder sb, uint n);=0D
    public static void Main () {=0D
        StringBuilder sb =3D new StringBuilder (255);=0D
        getname(sb, (uint) sb.Capacity);=0D
        Console.WriteLine("name: `{0}'", sb);=0D
        sb =3D new StringBuilder(1024);=0D
        wgetname(sb, (uint) sb.Capacity);=0D
        Console.WriteLine("wide name: `{0}'", sb);=0D

Content-Disposition: attachment; filename=native.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; name=native.c; charset=UTF-8

 * Native DLL.=0D
#include <string.h>=0D
#include <stdio.h>=0D
#ifdef _MSC_VER=0D
#define EXPORT  __declspec(dllexport)=0D
#define EXPORT=0D
wgetname(__wchar_t* s, unsigned int n)=0D
    const wchar_t m[] =3D L"This is my message.  Isn't it nifty?";=0D
    printf("Inside wgetname; n=3D%i\n", n);=0D
    wcsncpy(s, m, n);=0D
    return 0;=0D
getname(char* s, unsigned int n)=0D
    const char m[] =3D "This is my message.  Isn't it nifty?";=0D
    printf("Inside getname; n=3D%i\n", n);=0D
    strncpy(s, m, n);=0D
    return 0;=0D