CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    Aug 2005
    Location
    Bangalore, India
    Posts
    99

    Question Declaring pointers

    How can we declare and address pointer of this structure

    public struct PASSTHRU_MSG
    {
    unsafe public System.Int32 ProtocolID;
    unsafe public System.Int32 RxStatus;
    unsafe public System.Int32 TxFlags;
    unsafe public System.Int32 Timestamp;
    unsafe public System.Int32 DataSize;
    unsafe public System.Int32 ExtraDataIndex;
    unsafe public System.Byte[] Data;
    }

    where Data is fixed array of 4000 bytes
    When I try
    unsafe
    {
    PASSTHRU_MSG1* test;
    test = &ptrMsg;
    }

    It gives error
    Error 1 Cannot take the address of, get the size of, or declare a pointer to a managed type ('project.Form1.PASSTHRU_MSG1')

  2. #2
    Join Date
    Oct 2002
    Location
    Timisoara, Romania
    Posts
    14,360

    Re: Declaring pointers

    What are you trying to do with that unsafe code?
    Marius Bancila
    Home Page
    My CodeGuru articles

    I do not offer technical support via PM or e-mail. Please use vbBulletin codes.

  3. #3
    Join Date
    May 2007
    Posts
    1,546

    Re: Declaring pointers

    Also, none of those 'unsafe' keywords are necessary, they should all be removed. Is is also possible to pass a struct to native code without using pointers, i.e. using completely safe code. So paste the signature of the native function you're trying to call.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  4. #4
    Join Date
    Mar 2008
    Location
    IRAN
    Posts
    811

    Re: Declaring pointers

    Revise your code like this:
    Code:
    unsafe
    {
    PASSTHRU_MSG ptrMsg = new PASSTHRU_MSG();
    
    PASSTHRU_MSG *test;
    test = &ptrMsg;
    }
    Please rate my post if it was helpful for you.
    Java, C#, C++, PHP, ASP.NET
    SQL Server, MySQL
    DirectX
    MATH
    Touraj Ebrahimi
    [toraj_e] [at] [yahoo] [dot] [com]

  5. #5
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940

    Re: Declaring pointers

    (a) You have to do a 'fixed' to get a native pointer to a managed block of memory. This executes a 'pin' on the memory, preventing the GC from moving it after you've gained its native address e.g.

    Code:
    unsafe void Example(int [] values)
    {
        fixed (int *pValues = &values[0])
        {
        }
    }
    (b) You HAVE to tell the runtime how big the fixed-size byte[] array is :

    Code:
    using System.Runtime.InteropServices;
    
    [StructLayout(LayoutKind.Sequential)]
    public struct PASSTHRU_MSG
    {
        public System.Int32 ProtocolID;
        public System.Int32 RxStatus;
        public System.Int32 TxFlags;
        public System.Int32 Timestamp;
        public System.Int32 DataSize;
        public System.Int32 ExtraDataIndex;
    
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=4000)]
        public System.Byte[] Data;
    }
    (c) Since your structure contains a byte array, you can't just pin it (which is what the above does). Because of the byte [] array the struct doesn't lie in contiguous memory - the byte [] array may not exist at the same address as the structure member variable.

    So instead you must allocate a byte[] array of the same size as the structure then call Marshal.StructureToPtr. This will marshal the structure into the byte [] array and therefore make the "Data" member variable occupy the correct memory space.

    Code:
    static unsafe void Example()
    {
        PASSTHRU_MSG msg = new PASSTHRU_MSG();
        byte [] msgData = new byte[Marshal.SizeOf(typeof(PASSTHRU_MSG))];
    
        fixed (byte *pMsgData = &msgData[0])
        {
            Marshal.StructureToPtr(msg, (IntPtr)pMsgData, true);
        }
    }
    You can do this WITHOUT using unsafe code (highly advisable as it will then produce verifyable code) by pinning the byte[] array using the GCHandle class :

    Code:
    static void SafeExample()
    {
        PASSTHRU_MSG msg = new PASSTHRU_MSG();
        byte[] msgData = new byte[Marshal.SizeOf(typeof(PASSTHRU_MSG))];
    
        GCHandle handle;
    
        try
        {
            handle = GCHandle.Alloc(msgData, GCHandleType.Pinned);
            IntPtr addressOfStruct = handle.AddrOfPinnedObject();
            Marshal.StructureToPtr(msg, handle.AddrOfPinnedObject(), true);
    
            // use "addressOfStruct" in your interop calls.
        }
        finally
        {
            if (handle.IsAllocated)
            {
                handle.Free();
            }
        }
    }
    You could also create the memory needed for the struct by using Marshal.AllocHGlobal or one of the other Marshal class memory allocation methods. However you have to destroy this memory manually so I prefer to use a pinned managed byte[] array since no cleanup is necessary (apart from the unpinning after use).

    All of this is moot if you define your p/invoke method signature appropriately in the first place e.g. for

    Code:
    // C++
    __declspec(dllexport) void PassMyStruct(PASSTHRU_MSG *pMsg);
    use

    Code:
    [DllImport(...)]
    public static extern void PassMyStruct([MarshalAs(UnmanagedType.LPStruct)] PASSTHRU_MSG msg);
    Darwen.
    Last edited by darwen; February 10th, 2009 at 06:17 PM.
    www.pinvoker.com - PInvoker - the .NET PInvoke Interface Exporter for C++ Dlls.

  6. #6
    Join Date
    Mar 2007
    Posts
    274

    Re: Declaring pointers

    I feel incredibly stupid after reading darwen's post. More so than usual. You are one smart person.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured