Tech Off Thread

7 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Problem with P/Invoke

Back to Forum: Tech Off
  • User profile image
    BitFlipper

    I've done a fair amount of P/Invoking but for some reason I'm having problem with this one case. I need to define a delegate because I need to dynamically create the delegate at runtime using Marshal.GetDelegateForFunctionPointer(). Anyway, I don't think that is directly related to my problem, it is more to do with how I declare the delegate and use it. So say I have this:

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct MyStruct
    {
        public bool Value1;
        public int Value2;
        public IntPtr Ptr1;
        public IntPtr Ptr2;
    }
    
    [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
    public delegate void Foo([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    ref MyStruct[] structs, int arrayLength);

    Note that the structs array is both in and out, so I need to use ref (the native method modifies the structures). Now when I do this:
    var structs = new MyStruct[10];
    
    for (var idx = 0; idx < structs.Length; idx++)
    {
        structs[idx].Value2 = idx;
        ....
    }
    
    Foo(ref structs, structs.Length);

    ...The call fails. Note I simplified the code in this example but in the real code the function returns a value indicating failure.

    Now if I change the delegate declaration and the way I call it to the following...

    [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
    public delegate void Foo(IntPtr structs, int arrayLength);
    
    fixed (MyStruct* pStructs = &structs[0])
    {
        Foo(pStructs, structs.Length);
    }

    The call succeeds. It seems that the two should be the same from the native code's perspective. I would prefer if I don't have to use unsafe methods and the need to mark the assembly as using unsafe code. So what is wrong with my 1st delegate declaration?

     

  • User profile image
    Richard_​Andrew_x64

    I think this might be the problem:

    SizeParamIndex = 1

    Does that mean the size is 1 byte or am I mistaken?

  • User profile image
    Sven Groot

    I don't think you need the ref in your first delegate signature, unless the native method uses a pointer to an array (double indirection).

  • User profile image
    BitFlipper

    @Sven Groot:

    If I do that, the call succeeds but the contents of the array of structures are not updated by the native function. Or at least, after the call, I am not seeing the changes on the managed side. Remember it needs to be in/out.

    @Richard_Andrew_x64:

    What SizeParamIndex means is that it indicates the index of the parameter that defines the number of structures in the array. So I set it to 1 in this case because my second parameter (starting from 0), indicates the number of structures. In native function calls, that is often the way that the length of arrays are indicated. See here for more details.

    
  • User profile image
    Sven Groot

    Maybe try marking it with explicit [In, Out] attributes? I'm fairly sure it shouldn't be ref for this scenario (unless, as I said, it's a double pointer) but it might not marshal the results back by default. Adding the attribute would take care of that, I think.

  • User profile image
    BitFlipper

    @Sven Groot:

    Yes, that actually did it! I forgot that you could mark it like that. For some reason I thought "[In, Out]" is the same as "ref", which of course isn't true.

    Thanks for your help!

  • User profile image
    teslaBytes

    try using a binary, contex helper method. use a mux/demux for the in/out, sent in one direction by decodes to di-directiocal com.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.