Int-Pointer to unmanaged code

时间:2011-09-21 17:18:03

标签: c# pointers reference unmanaged

我对C#很新,并且有一个简单的(?)问题。从非托管代码我收到一个int-pointer:

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;
}
然后没有任何反应。状态的初始值为0,将myState更改为7时,未在非托管应用程序中更新。 如何将状态参数中的_myState等成员变量指定为“指针”,因此当状态更新时,_myState也会更新? 在C ++中,这对指针来说没有问题......

好的,这是真正的代码:

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

我想要的是OrderCommandProcessStateprocessState获得与其值相同的引用。

1 个答案:

答案 0 :(得分:12)

首先,我想确保这一点是明确的:IntPtr只是一个整数,恰好与该机器架构上的本机指针大小相同 - 例如x64系统上的64位整数,例如。它不一定必须具有指针的语义,当然,互操作代码通常将指针填充到IntPtrs中作为一种安全地编组它们的方式。

继续讨论你的具体问题,让我们忽略它是一个IntPtr的事实。假装它只是一个int,因为它基本上就是这样:

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
}

改变y不会以任何方式改变x; x是另一个变量的别名,y简要地拥有该变量内容的副本。它绝不是同一个变量的别名。

  

如何将一个变量作为另一个变量的别名,所以当更新一个变量的状态时,链接变量也会更新?在C ++中,指针没有问题。

今天在安全子集中,您只能通过方法的“ref”和“out”参数来实现。 “ref”参数成为给定变量的别名。 这是您可以直接将一个变量转换为另一个变量的唯一安全方式。

CLR也支持ref locals。我们可以实现这样的功能,事实上我已经用C#对其进行了原型化。在我的原型中你可以说:

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
}

但是我们还没有将这个功能添加到C#中,并且没有计划很快就这样做。如果你有一个引人注目的使用案例,我很乐意听到它。 (更新:该功能已添加到C#7中。)

(CLR还允许“ref”返回类型。但是,CLR不允许为变量创建别名,然后将该别名存储在字段中!字段的生命周期可能比链接变量长,并且CLR设计者希望避免困扰C和C ++的那类错误。)

如果您知道变量固定在内存中的特定位置,那么您可以关闭安全系统并指向该变量;然后你有一个完全普通的指针,你可以像在C ++中那样使用它。 (也就是说,如果指针ptr引用变量,则*ptr是该变量的别名。)

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
}

CLR对如何使用指针没有任何限制;如果需要,您可以自由地将它们存储在字段中。但是,如果关闭安全系统,那么负责确保垃圾收集器(或任何内存管理器拥有该存储 - 它可能不是托管内存)不会在指针的生命周期中更改别名变量的位置。除非你真的知道你在做什么,否则不要关闭那个安全系统;那个安全系统可以保护你。