指向非托管代码的 Int 指针
我对 C# 很陌生,有一个简单的(?)问题。从非托管代码中,我收到一个 int 指针:
public foo(ref IntPtr state)
{
_myState = state;
}
_myState
是该类的 IntPtr
成员。现在我想通过 _myState
与非托管 C++ 代码交换状态。如果我这样写,一切都会正常:
public foo(ref IntPtr state)
{
_myState = state;
....do some stuff
state = 7;
}
在非托管应用程序中,我可以看到新值 7
。但如果我这样写:
public foo(ref IntPtr state)
{
_myState = state;
...do some stuff
_myState = 7;
}
那么什么也不会发生。 state 的初始值为 0
,当将 myState
更改为 7
时,它不会在非托管应用程序中更新。 如何将像 _myState
这样的成员变量作为“指针”分配给 state 参数,以便当状态更新时,_myState
也会更新? 在 C++ 中,这对于指针来说是没有问题的...
好吧,这是真正的代码:
[DllExport("QFX_InitializeInterfaceObject", CallingConvention = CallingConvention.StdCall)]
public static void QFX_InitializeInterfaceObject(
long windowHandle,
ref IntPtr processState)
{
ChartWindowHandle = (IntPtr)windowHandle;
OrderCommandProcessState = processState;
}
我想要的只是 OrderCommandProcessState
获得与 processState
对其值相同的引用。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,我想确保这一点很清楚:IntPtr 只是一个整数,恰好与该机器体系结构上的本机指针大小相同 - 例如,它在 x64 系统上是一个 64 位整数。它不一定具有指针的语义,尽管互操作代码将指针填充到 IntPtr 中作为安全编组它们的一种方式当然很常见。
继续讨论您的具体问题,让我们忽略它是 IntPtr 的事实。假设它只是一个 int,因为它基本上就是这样:
改变 y 不会以任何方式改变 x; x 是另一个变量的别名,y 简要地具有该变量内容的副本。它无论如何都不是同一变量的别名。
如今,在安全子集中,您只能通过方法的“ref”和“out”参数来执行此操作。 “ref”参数成为给定变量的别名。 这是直接将一个变量设为另一个变量的别名的唯一安全方法。
CLR 也支持 ref 局部变量。我们可以实现这样的功能,事实上我已经用 C# 对其进行了原型设计。在我的原型中,您可以说:
但是我们还没有将此功能添加到 C# 中,并且短期内也没有计划这样做。如果您有一个令人信服的用例,我很想听听。 (更新:该功能已添加到 C# 7 中。)
(CLR 还允许“ref”返回类型。但是,CLR 不允许为变量创建别名,然后将该别名存储在字段中!该字段可能是比链接变量的生命周期更长,并且 CLR 设计者希望避免困扰 C 和 C++ 的整类错误。)
如果您知道该变量被固定到内存中的特定位置,那么您可以关闭安全系统并让指向该变量的指针;然后你就有了一个完全普通的指针,你可以像在 C++ 中一样使用它。 (也就是说,如果指针
ptr
引用变量,则*ptr
就是该变量的别名。)CLR 对指针的使用方式没有限制;如果您愿意,您可以自由地将它们存储在字段中。但是,如果您关闭安全系统,那么您有责任确保垃圾收集器(或拥有该存储的任何内存管理器 - 它可能不是托管内存)不会在指针的生命周期内更改别名变量的位置。除非您真正知道自己在做什么,否则不要关闭该安全系统;该安全系统可以保护您。
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:
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.
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:
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.)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.