aevitas
aevitas

Reputation: 3833

Is there any point in declaring arguments as [In] when PInvoking?

When using platform invokes, does specifying arguments as [In] make a difference in how the runtime approaches these?

For instance, when PInvoking CreateRemoteThread, lpThreadId is specified as out as per the article on MSDN:

HANDLE WINAPI CreateRemoteThread(
  _In_   HANDLE hProcess,
  _In_   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_   SIZE_T dwStackSize,
  _In_   LPTHREAD_START_ROUTINE lpStartAddress,
  _In_   LPVOID lpParameter,
  _In_   DWORD dwCreationFlags,
  _Out_  LPDWORD lpThreadId
);

And all other arguments are _In_. In my C# code, I handle that specific function like so:

    [DllImport("kernel32.dll", EntryPoint = "CreateRemoteThread", SetLastError = true)]
    public static extern IntPtr CreateRemoteThread(
        IntPtr hProcess,
        IntPtr lpThreadAttributes,
        uint dwStackSize,
        IntPtr lpStartAddress,
        IntPtr lpParameter,
        uint dwCreationFlags,
        [Out] IntPtr lpThreadId);

Adding the [Out] attribute to lpThreadId so the runtime knows to marshal it back to the caller. Would the runtime handle my function any different if I'd change the function signature to this:

    [DllImport("kernel32.dll", EntryPoint = "CreateRemoteThread", SetLastError = true)]
    public static extern IntPtr CreateRemoteThread(
        [In] IntPtr hProcess,
        [In] IntPtr lpThreadAttributes,
        [In] uint dwStackSize,
        [In] IntPtr lpStartAddress,
        [In] IntPtr lpParameter,
        [In] uint dwCreationFlags,
        [Out] IntPtr lpThreadId);

Or would it be the exact same thing; are arguments considered [In] by default?

Upvotes: 1

Views: 220

Answers (1)

Mgetz
Mgetz

Reputation: 5128

The [In] and [Out] attributes actually are very important, they tell the framework whether or not it needs to concern itself with marshaling a parameter in a particular direction. This is particularly useful for things like structs which are very expensive to marshal. By default the framework assumes that marshaling is bidirectional, which may have a large performance impact.

Update:

Some of the comments have brought up the fact that primitive types are marshaled as [In] by default, this is correct. However the fact that marshaling is complicated gives onus to being as explicit as possible in PInvoke declarations, leave as little as possible to the framework to decide even it it is already supposed to be that way.

Upvotes: 5

Related Questions