none
Cannot take the address of, get the size of, or declare a pointer to a managed type? RRS feed

  • Question

  •  I wrote code to access structre from C# .net where structure is in C dll .here are the two files .When i build i  get the error message saying that "Cannot take the address of, get the size of, or declare a pointer to a managed type ('StructureExample.Program.Detail')"

    ------------------------- StrcutreDisplay.dll---------------------------------

    #include<iostream.h>

    #include<conio.h>

    #include<malloc.h>

    #include<string.h>

    extern "C"

    {

    typedef struct

    {

    char *fname;

    char *lname;

    char abc[5];

    }Detail;



    __declspec(dllexport) Detail * Disp()

    {

    Detail *ptr=(Detail *)malloc(sizeof(Detail));

    ptr->fname = (char*)malloc(50);

    memset(ptr->fname, 0x00, 50);

    ptr->lname = (char*)malloc(50);

    memset(ptr->lname, 0x00, 50);

    memset(ptr->abc, 0x00, 5);

    strcpy(ptr->fname, "larson");

    strcpy(ptr->lname, "scolari");

    strcpy(ptr->abc, "ABC");
    return ptr;

    }

    }


    ----------------------------StructureExample---------------------------------




    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Runtime.InteropServices;

    namespace StructureExample

    {

    class Program

    {

    [StructLayout(LayoutKind.Explicit)]

    public struct Detail

    { // [MarshalAs(UnmanagedType.LPStr)]

    public unsafe sbyte* fname;

    public unsafe sbyte* lname;

    public char[] arr;

    }



    // strucure DLL

    [DllImport("StructureDisplay.dll")]

    public static unsafe extern Detail * Disp();//here i get error

    static void Main(string[] args)

    {

    unsafe

    {

    Detail * var = Disp();

    string a = new string(var->fname);

    string b = new string(var->lname);

     

    string e = new string(var->abc);


    }

    Console.WriteLine("hello world");

    Console.WriteLine(a);

    Console.WriteLine(b);

     

    Console.WriteLine(e);


    Console
    .Read();

    }

    }

    }


    ------------------------------------------------------------------------------------------------

    How to solve this problem?can anyone help me out?





    Any help appreciated.
    Thanks in advance.

    Tuesday, June 24, 2008 8:20 AM

Answers

  • Hi cristi,

    In this case, I am afraid that you cannot use unsafe pointer, try to use the managed IntPtr type, I have done test it, it works, please check the code snippet below.

    //== unmanaged API code

    extern "C"

    {

           

             typedef struct

             {

                     char * fname;

                     char * lname;

                     char * abc; //cannot use the array here, because the C# code cannot access it

             }Detail;

    }

     

    __declspec(dllexport) Detail * Disp()

    {

            Detail *ptr=(Detail *)malloc(sizeof(Detail));

     

            ptr->fname = (char *)malloc(50);

     

            memset(ptr->fname, 0x00, 50);

     

            ptr->lname = (char*)malloc(50);

     

            memset(ptr->lname, 0x00, 50);

     

            ptr->abc = (char*)malloc(5);

            memset(ptr->abc, 0x00, 5);

           

            strcpy(ptr->fname, "larson");

     

            strcpy(ptr->lname, "scolari");

     

            strcpy(ptr->abc, "ABC");

            return ptr;

    }

    //C# code

    class Program

        {

            [StructLayout(LayoutKind.Sequential)]

            public struct Detail

            {

                public IntPtr fname;

                public IntPtr lname;

                public IntPtr arr;

            }

     

            // strucure DLL

            [DllImport(@"E:\VCS_Sample\Call_DLL_Console\bin\Debug\DemoDll.dll")]

            public static extern IntPtr Disp();

            public static void Main()

            {

     

                const int Max_len = 100;

                IntPtr var = Disp();

                Detail det;

                det.arr = det.fname = det.lname = IntPtr.Zero;

     

     

                det = (Detail)(Marshal.PtrToStructure(var, det.GetType()));

     

                byte[] temp = new byte[Max_len];

     

                Marshal.Copy(det.fname, temp, 0, 7);

                string a = "";

                for (int i = 0; i < 7; i++ )

                    a += Convert.ToChar(temp[i]);

     

     

                Marshal.Copy(det.lname, temp, 0, 8);

                string b = "";

                for (int i = 0; i < 8; i++)

                    b += Convert.ToChar(temp[i]);

     

     

                Marshal.Copy(det.arr, temp, 0, 5);

                string e = "";

                for (int i = 0; i < 5; i++)

                    e += Convert.ToChar(temp[i]);

     

                Console.WriteLine("hello world");

                Console.WriteLine(a);

                Console.WriteLine(b);

                Console.WriteLine(e);

                Console.Read();

            }

    }

    //==Output below.

    hello world

    Larson

    Scolari

    ABC

     

    Regards,

    Xun


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Marked as answer by jack 321 Monday, June 30, 2008 10:28 AM
    Friday, June 27, 2008 4:09 AM

All replies

  • I have a couple of comments and the answer.

    The answer first: You cannot use pointers to refer to 'Detail' unless the structure is WHOLLY composed of Value types, your is not because it contains: public char[] arr; and arrays are NOT value types. That is why you get the error message.

    However you can declare that field like this: public fixed Byte arr[5]; and that WILL compile.

    But note these points:

    1. Char in C# is a TWO byte field (16 bits) your C struct contains a C 'char' array but in C 'char' is ONE byte. Char in C# is for full support of unicode. A C 'char' is a C# SByte and a C 'unsigned char' is a C# Byte.

    2. You have declared two pointers (fname and lname) in the C# struct, although this is legal and will (probably compile) it may cayse serious runtime problems unless the code is 100% perfect.

    The way to declare these strings all depends on whether you are passing stuff ONLY from C# to C ot ONLY from C to C# or BOTH.

    In your example it seems that the called C code will allocate memory and assign values to it, I think this will work as you want but unless this is just experimentation I would advise extreme caution here. You could make each of the struct fields a String and decide on a sensible max length. Your called code can then use strcpy_s and other safe functions to build the string and would not have to allocate memory.

    If you declare a string field and use a suitable attribute, you can do what you are trying to do.

    In the C# struct you coulde use this attribute: [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]  by way of example, where the value (256) is the length of your String fields, and is the length of the buffer that the C code will 'see'.

    e.g.

    class Program

    {

    [StructLayout(LayoutKind.Explicit)]

    public struct Detail


    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] // Called C code can 'assume' it has a char fname[256] to work with
    public string fname;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
    public
     string lname;

    public fixed byte arr[5];

    }

    I suggest that in the C code you delcare fname and lname the same way: char fname[256];

    Hugh

     

     

     

     

    Tuesday, June 24, 2008 3:28 PM
  •  Hi Hugh.Thanks for the reply .As per you said i changed array declaration in my program.

    public unsafe fixed char abc[5];

    Now my code gets compiled but i got runtime exception  i.e MarshalDirectiveException saying that Cannot marshal 'return value': Pointers cannot reference marshaled structures.  Use ByRef instead.


    I get this exception at the following line :

     

    Detail * var = Disp();//Cannot marshal 'return value': Pointers cannot reference marshaled structures.  Use ByRef instead.



    I guess reason for this error is when i return a structure pointer with array element in that stucture ,the CLR cannot marshal it properly and therefor it cannot return the value.

    How can i solve this problem ?Can anyone help me out?


    Any help appreciated.
    thanks in advance.

    Wednesday, June 25, 2008 5:14 AM
  • Hi cristi,

    In this case, I am afraid that you cannot use unsafe pointer, try to use the managed IntPtr type, I have done test it, it works, please check the code snippet below.

    //== unmanaged API code

    extern "C"

    {

           

             typedef struct

             {

                     char * fname;

                     char * lname;

                     char * abc; //cannot use the array here, because the C# code cannot access it

             }Detail;

    }

     

    __declspec(dllexport) Detail * Disp()

    {

            Detail *ptr=(Detail *)malloc(sizeof(Detail));

     

            ptr->fname = (char *)malloc(50);

     

            memset(ptr->fname, 0x00, 50);

     

            ptr->lname = (char*)malloc(50);

     

            memset(ptr->lname, 0x00, 50);

     

            ptr->abc = (char*)malloc(5);

            memset(ptr->abc, 0x00, 5);

           

            strcpy(ptr->fname, "larson");

     

            strcpy(ptr->lname, "scolari");

     

            strcpy(ptr->abc, "ABC");

            return ptr;

    }

    //C# code

    class Program

        {

            [StructLayout(LayoutKind.Sequential)]

            public struct Detail

            {

                public IntPtr fname;

                public IntPtr lname;

                public IntPtr arr;

            }

     

            // strucure DLL

            [DllImport(@"E:\VCS_Sample\Call_DLL_Console\bin\Debug\DemoDll.dll")]

            public static extern IntPtr Disp();

            public static void Main()

            {

     

                const int Max_len = 100;

                IntPtr var = Disp();

                Detail det;

                det.arr = det.fname = det.lname = IntPtr.Zero;

     

     

                det = (Detail)(Marshal.PtrToStructure(var, det.GetType()));

     

                byte[] temp = new byte[Max_len];

     

                Marshal.Copy(det.fname, temp, 0, 7);

                string a = "";

                for (int i = 0; i < 7; i++ )

                    a += Convert.ToChar(temp[i]);

     

     

                Marshal.Copy(det.lname, temp, 0, 8);

                string b = "";

                for (int i = 0; i < 8; i++)

                    b += Convert.ToChar(temp[i]);

     

     

                Marshal.Copy(det.arr, temp, 0, 5);

                string e = "";

                for (int i = 0; i < 5; i++)

                    e += Convert.ToChar(temp[i]);

     

                Console.WriteLine("hello world");

                Console.WriteLine(a);

                Console.WriteLine(b);

                Console.WriteLine(e);

                Console.Read();

            }

    }

    //==Output below.

    hello world

    Larson

    Scolari

    ABC

     

    Regards,

    Xun


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    • Marked as answer by jack 321 Monday, June 30, 2008 10:28 AM
    Friday, June 27, 2008 4:09 AM