PInvoke with a void * versus a struct with an IntPtr
Asked Answered
I

1

6

Imagine I have a function called

Myfunction(const void * x);

My C# declaration could be

MyFunction(IntPtr x);

Is this functionally and technically equivalent to

struct MyStruct { IntPtr P; }

MyFunction(MyStruct x);

Or will there be a difference in how they are marshalled.

I'm asking this because the library I'm calling is all void *, typedef'd to other names, and in C# I'd like to get type safety, for what it's worth.

Irmgardirmina answered 12/2, 2015 at 0:55 Comment(2)
This question boils down to: Is a struct with a single member marshaled the same as the type of that member? While I don't know, I strongly suspect not.Fritter
Not a direct answer, but in the past I've always made a new struct that wraps the IntPtr (just like you're proposing) called "WhateverPtr" where "Whatever" is my unmanaged type, and then used a custom marshaller using the ICustomMarshaller interface msdn.microsoft.com/en-us/library/d3cxf9f0(v=vs.90).aspx Then you can't screw up and mix up your IntPtrs. It's also more self documenting, although you do have to churn out a bit of boilerplate code. It seems extremely unlikely that the marshaller would magically spit out or accept your structCharla
A
3

If your StructLayout is Sequential, then it is indeed identical.

Easiest way to verify this for yourself is to try it out, of course:

Make a C++ Win32 DLL project:

extern "C"
{
    __declspec(dllexport) void MyFunction(const void* ptr)
    {
       // put a breakpoint and inspect
    }
}

Make a C# project:

    public struct Foo
    {
        public IntPtr x;
    }

    [DllImport(@"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
    public static extern void MyFunctionWithIntPtr(IntPtr x);

    [DllImport(@"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
    public static extern void MyFunctionWithStruct(Foo x);

    static void Main(string[] args)
    {
        IntPtr j = new IntPtr(10);
        var s = new Foo();
        s.x = new IntPtr(10);
        MyFunctionWithIntPtr(j);
        MyFunctionWithStruct(s);
    }

In your debug settings, make sure you select Native debugging is enabled.

You'll see both values to be 0xA.

Note, however, if you use out/ref parameters for your IntPtr vs Struct, they will be different values.

Ataxia answered 12/2, 2015 at 1:21 Comment(1)
Trial and error proves nothing. How do you know that another example doesn't behave differently?Caracal

© 2022 - 2024 — McMap. All rights reserved.