4

I'm pretty new to C# and have a simple(?) question. From unmanaged code I receive an int-pointer:

public foo(ref IntPtr state)
{
   _myState = state;
}

_myState is a IntPtr member of the class. Now I want to exchange states via _myState with the unmanaged C++ code. Everything works if I write this:

public foo(ref IntPtr state)
{
   _myState = state;
   ....do some stuff
   state = 7;
}

In the unmanaged application I can see the new value 7. But if I write this:

public foo(ref IntPtr state)
{
   _myState = state;
   ...do some stuff
   _myState = 7;
}

then nothing happens. The initial value of state is 0, and when changing myState to 7 it is not updated in the unmanaged application. How can I assign a member variable like _myState to the state parameter as a "pointer", so when state is updated, _myState is also updated? In C++ this would be no problem with a pointer...

Ok, here is the real code:

[DllExport("QFX_InitializeInterfaceObject", CallingConvention = CallingConvention.StdCall)]
    public static void QFX_InitializeInterfaceObject(
        long windowHandle,
        ref IntPtr processState)
    {
        ChartWindowHandle = (IntPtr)windowHandle;
        OrderCommandProcessState = processState;
    }

All I want is that OrderCommandProcessState gets the same reference as processState to its value.

nawfal
  • 70,104
  • 56
  • 326
  • 368
Juergen
  • 3,489
  • 6
  • 35
  • 59
  • 1
    It's apparent that you put pseudocode here (as it isn't proper C#). Can you provide proper code and describe what exactly you're trying to achieve. Sorry, but it isn't apparent from your description. – elder_george Sep 21 '11 at 17:27
  • 1
    IntPtr is a value type. You are updating a *copy* of the value. – Hans Passant Sep 21 '11 at 17:31
  • @Hans: Which type does the member _myState need to have, so that it is linked with state? – Juergen Sep 21 '11 at 17:37
  • 1
    A pointer, IntPtr*. Unsafe code required. You'd be better off with Marshal.WriteIntPtr(). There's at least one dark cloud beyond the killer poke behavior, pretty unlikely that this is actually an IntPtr in the native code. – Hans Passant Sep 21 '11 at 17:42
  • @Hans: In the native code its a C++ int. – Juergen Sep 21 '11 at 17:47
  • If the setting itself will be done via managed code, as is the case here, you could use closures to accomplish this. Eric Lippert has sample code for this in [Is it Possible to Return a Reference to a Variable in C#?](http://stackoverflow.com/questions/4542536/is-it-possible-to-return-a-reference-to-a-variable-in-c/4543089#4543089) – Brian Sep 21 '11 at 17:50
  • @Juergen - If its an integer just send the reference to an integer varaible. IntPtr isn't the correct variable type. What you want to do is not exactly clear. You should be modifying state not _myState you can always before you exit the method set _myState to the value of state. – Security Hound Sep 21 '11 at 17:59
  • 2
    @Ramhound: What if the integer is of different sizes on different architectures? – Eric Lippert Sep 21 '11 at 18:16

1 Answers1

12

First off, I want to make sure this point is clear: an IntPtr is just an integer that happens to be the same size as a native pointer on that machine architecture -- it's a 64 bit integer on x64 systems, for example. It does not necessarily have the semantics of a pointer, though of course it is common for interop code to stuff pointers into IntPtrs as a way of marshalling them around safely.

Moving on to your specific question, let's ignore the fact that it's an IntPtr. Pretend it's just an int, because that's basically what it is:

public void Foo(ref int x) // x is an alias to another variable of type int.
{
    int y = x; // y is a copy of the contents of x
    y = 7; // The contents of y are no longer a copy of the contents of x
}

Changing y does not in any way change x; x is an alias to a different variable, and y briefly has a copy of the contents of that variable. It is not in any way an alias to that same variable.

How can I make one variable into an alias to another variable, so when the state of the one variable is updated, the linked variable is also updated? In C++ this would be no problem with a pointer.

Today in the safe subset you can only do so via "ref" and "out" parameters to methods. The "ref" parameter becomes an alias to the given variable. That is the only safe way that you can directly make one variable into an alias for another.

The CLR supports ref locals as well. We could implement such a feature, and in fact I have prototyped it in C#. In my prototype you could say:

public void Foo(ref int x) // x is an alias to another variable of type int.
{
    ref int y = ref x; // y is now an alias to the same variable that x aliases!
    y = 7; // changing y now changes x, and whatever x 
           // aliases, because those are all the same variable
}

But we have not added this feature to C# and have no plans to do so any time soon. If you have a compelling usage case for it, I'd love to hear it. (UPDATE: The feature was added to C# 7.)

(The CLR also permits "ref" return types. However, the CLR does NOT permit making an alias to a variable and then storing that alias in a field! The field might be of longer lifetime than the linked variable, and the CLR designers wish to avoid that whole class of bugs that plagues C and C++.)

If you know that the variable is pinned to a particular location in memory then you can turn off the safety system and make a pointer to that variable; you then have a perfectly ordinary pointer that you can use as you would in C++. (That is, if a pointer ptr refers to a variable then *ptr is an alias to that variable.)

unsafe public void Foo(int* x) // *x is an alias to a variable of type int.
{
    int* y = x; // *y is now an alias to the same variable that *x aliases
    *y = 7; // changing *y now changes *x, and whatever *x 
            // aliases, because those are all the same variable
}

The CLR puts no restrictions on how pointers can be used; you are free to store them in fields if you want. However, if you turn the safety system off then you are responsible for ensuring that the garbage collector (or whatever memory manager owns that storage -- it might not be managed memory) is not going to change the location of the aliased variable for the lifetime of the pointer. Do not turn off that safety system unless you really know what you are doing; that safety system is there to protect you.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    @pst, are you misreading the answer or am I misreading your comment? One *can't*, not unless Microsoft shipped the code that Eric has only prototyped to this point, which Eric also indicates they have no plans to do in the near future. – Anthony Pegram Sep 21 '11 at 17:40
  • @Anthony Pegram I am misreading. I jump on the code blocks more readily, unfortunately :( –  Sep 21 '11 at 17:44
  • 1
    Do you consider closures another way that you can make one variable appear to be an alias for another? Obviously, the mechanism behaind closures is quite different than that of ref/out, but the appearance to the developer is that a variable has been "captured" and can be modified in another context. – LBushkin Sep 21 '11 at 18:01
  • 1
    @LBushkin: I suppose that is true! Also, of course there are other ways to "capture a reference" to a variable. An array, for example, is nothing more than an indexed collection of variables that can be passed around by reference. However, it appears that the original poster has a reference *to unmanaged memory*, so solutions which attempt to use managed constructs like arrays or closures or whatever are unlikely to solve his problem. – Eric Lippert Sep 21 '11 at 18:05
  • Just a heads up to anyone reading this now. Starting with C# 7.0, C# supports ref locals[1](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/ref-returns#ref-locals)[2](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-locals) so it is now possible to write `ref int y = ref x;` without getting an error. Apparently _'not any time soon'_, by @EricLippert means some time in the next 6 years. – Alex Essilfie Feb 20 '18 at 14:30
  • @AlexEssilfie: It's hard to make predictions, especially about the future. – Eric Lippert Feb 20 '18 at 15:09