2

Microsoft's documentation on .NET native interoperability gives the most common example (even calls it that, actually) of a call from C# to unmanaged code:

using System.Runtime.InteropServices;

public class Program
{
    // Import user32.dll (containing the function we need) and define
    // the method corresponding to the native function.

    [DllImport("user32.dll")]
    public static extern int MessageBox(IntPtr hWnd, String text, String caption, int options);

    public static void Main(string[] args)
    {
        // Invoke the function as a regular managed method.

        MessageBox(IntPtr.Zero, "Command-line message box", "Attention!", 0);
    }
}

That seems pretty straightforward and does work fine. But I'm puzzled about the second and third parameters of the MessageBox call. If MessageBox were a managed method, those would be string reference types, with their actual data residing on the heap. The garbage collector might rearrange the heap, but (being a managed function) that wouldn't have any effect that MessageBox could see, as the reference would always be to the current location, no matter where that was. But the unmanaged version expects a pointer containing the actual memory address itself of the string.

Now, maybe my question reflects my experience with Java (and relative lack of experience with C#), but I'm wondering why the above call to the unmanaged function MessageBox isn't at risk of the garbage collector moving the actual data in the string from one location on the heap to another, after MessageBox is called, and before MessageBox dereferences the pointer.

In other words, how can we be sure the address passed to MessageBox continues to point to the actual string data until after it returns?

Stevens Miller
  • 1,387
  • 8
  • 25
  • is that not what [pinning is for](https://manski.net/2012/06/pinvoke-tutorial-pinning-part-4)? – Cee McSharpface Jul 31 '17 at 16:35
  • 1
    Yes, that other question appears spot on. Alas, the link to their source of info no longer works. It appears to be from an article in the October, 2004 edition, which is available via a link on that page, however. Thanks for the redirect! It would have taken me forever to find that. – Stevens Miller Jul 31 '17 at 17:08
  • 1
    The correct answer is as [Microsoft states](https://learn.microsoft.com/en-us/cpp/dotnet/how-to-marshal-strings-using-pinvoke?view=msvc-170) that "The marshaler wraps the call to the unmanaged function in a hidden wrapper routine...". The linked question is regarding `char[]` which is not related to passing a string. – wezten Aug 21 '23 at 10:36

1 Answers1

0

If it expects address, unfortunately GC changes it on every garbage collection. Refer to MSDN documentation

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69