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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With