C# 跟踪对本机引用问题的引用-从C到C++/CLI到C++;AccessViolationException 我试图用VS2010编写一个C++/CLI包装器,C++的API只允许我访问头文件,也可以访问DLL/LIB文件。

C# 跟踪对本机引用问题的引用-从C到C++/CLI到C++;AccessViolationException 我试图用VS2010编写一个C++/CLI包装器,C++的API只允许我访问头文件,也可以访问DLL/LIB文件。,c#,c++,c++-cli,pass-by-reference,C#,C++,C++ Cli,Pass By Reference,我遇到了一个问题,从本机代码中的本机引用冒泡备份到C#代码中的跟踪引用。我收到了一封违反规定的信。代码如下: WrapperCustomObject wrapperCustomObject; WrapperManageCustomObject wrapperManageCustomObject = new WrapperManageCustomObject(); long result; // this works great result = wrapperManageCustomObje

我遇到了一个问题,从本机代码中的本机引用冒泡备份到C#代码中的跟踪引用。我收到了一封违反规定的信。代码如下:

WrapperCustomObject wrapperCustomObject;
WrapperManageCustomObject wrapperManageCustomObject = new WrapperManageCustomObject();

long result;

// this works great
result = wrapperManageCustomObject.CreateCustomObject(ref wrapperCustomObject);

// can utilize wrapperCustomObject here with other native functions no problem, so long as I don't try to modify it...
...

// this throws an AccessViolationException was unhandled message
// essentially I am modifying / returning a different native customObject (though I'm not 100% sure what it does as I do not have access to the code)
result = wrapperManageCustomObject.ModifyCustomObject(ref wrapperCustomObject);

未托管的本机C++标题,用于返回创建和修改自定义对象的引用:

class ManageCustomObject;
    _declspec(dllimport) errorCode CreateCustomObject(CustomObject& customObject);
    _declspec(dllimport) errorCode ModifyCustomObject(CustomObject& customObject);
关于CustomObject需要注意的重要一点是,它只有私有构造函数:

CustomObject(const CustomObject&) { }
CustomObject& operator=(const CustomObject&) { return *this; }
现在,我的C++/CLI层方法如下所示:

public ref class WrapperManageCustomObject {
public:
        errorCode WrapperCreateCustomObject(CustomObject% customObject)
        {
            return CreateCustomObject(customObject);
       }

        errorCode WrapperModifyCustomObject(CustomObject% customObject)
        {
            return ModifyCustomObject(customObject);
        }
};
public class WrapperCustomObject : public CustomObject {
    public:
        WrapperCustomObject(const CustomObject&) {};
};
CustomObject的包装器如下所示:

public ref class WrapperManageCustomObject {
public:
        errorCode WrapperCreateCustomObject(CustomObject% customObject)
        {
            return CreateCustomObject(customObject);
       }

        errorCode WrapperModifyCustomObject(CustomObject% customObject)
        {
            return ModifyCustomObject(customObject);
        }
};
public class WrapperCustomObject : public CustomObject {
    public:
        WrapperCustomObject(const CustomObject&) {};
};
在C#中,代码如下:

WrapperCustomObject wrapperCustomObject;
WrapperManageCustomObject wrapperManageCustomObject = new WrapperManageCustomObject();

long result;

// this works great
result = wrapperManageCustomObject.CreateCustomObject(ref wrapperCustomObject);

// can utilize wrapperCustomObject here with other native functions no problem, so long as I don't try to modify it...
...

// this throws an AccessViolationException was unhandled message
// essentially I am modifying / returning a different native customObject (though I'm not 100% sure what it does as I do not have access to the code)
result = wrapperManageCustomObject.ModifyCustomObject(ref wrapperCustomObject);
正如您在我的评论中看到的,试图通过引用修改该对象会引发“AccessViolationException未处理:试图读取或写入受保护的内存。这通常表示其他内存已损坏。”

现在,如果我从这个方程中消除C和跟踪参考,并在C++或C++ +CLI中执行(只要跟踪引用不存在),这就很好了。我假设这与本机代码试图访问和更新现在位于托管区中的引用有关


有没有任何方法可以从本质上使这段代码在C#中“工作”呢?据我所知,没有办法将本机引用传递给C#。

托管引用与本机引用完全不同。托管引用更像本机指针。据我所知,您不能像
公共类包装器CustomObject:public CustomObject
(其中
CustomObject
是一个本机类)这样做,而且永远都不能指望它会起作用。当您创建托管类时,您告诉CLR您的类在内存中移动时会表现良好。如果
CustomObject
对指针执行任何操作,那么这将不再是真的
CustomObject
不使用托管引用,因此当类实例被移动时,运行时无法知道在何处更新客户端


更糟糕的是,包装器允许在不经过工厂方法的情况下实例化该类。因此,如果工厂方法
CreateCustomObject
对您返回的对象做了任何重要的事情,那么您就违反了所调用代码的约定,它要求您通过工厂方法创建该对象的实例。

如果C++有一个私有构造函数,并且没有工厂函数,那么您应该如何在C++域中创建<代码> CubjultOb/Cuff>?要调用
CreateCustomObject
helper函数,您需要已经有一个
CustomObject
实例。您是如何编译它的?您正在返回一个本机对象指针,但C#代码将其视为托管包装器。是的,当你使用它的时候,它是一个大房间。本机对象指针应该是wrapper.Stu的私有成员-我也可以作为“out”参数来执行这些操作,但仅此而已。Ref参数是c#的东西。Hans-c++/CLI允许跟踪引用。信不信由你,这是有效的。亚当——如果函数已经返回一个引用的引用,你就不必在C++的土地上创建CuffObjor了。您只需要一个容器来保存该引用。i、 e.:CustomObject CustomObject;奇怪的是,您实际上可以将公共类WrapperCustomObject作为托管派生类从公共CustomObject(非托管本机类)继承,并且它实际上可以“工作”。然而,正如你所指出的,我也同意——局限性可能会很快积累起来,我同意你所说的。也许我现在寻找的是任何可能的方法,来绕过这种方法,找到“可能正确工作”的方法。当CreateCustomObject仅通过引用返回该对象时,我似乎找不到任何方法来做一些有用的事情,而这是我能够有效创建或保存它的唯一方法。与引用一起工作非常困难——除了潜在的C++静态奇异实例之外,您不能存储它们,或者,正如我已经演示的那样,通过托管C语言来保持它的跟踪引用。@布瑞恩:不,它实际上并不“工作”——仅仅因为编译它并不意味着它在运行时不会失败(事实上它确实如此)。它编译是因为C++类可以是无状态的,或者可以是无中心的,在这种情况下它可以工作。但是,由于您不知道类的实现,因此它不是您可以依赖的。至于使用“困难”的引用,只有当您试图将本机引用视为托管引用时,它们才是困难的。他们彼此无关。如果您想要托管引用,请创建一个。@Brian:您不能将托管引用转换为本机引用,反之亦然。时期如果您想要一个包装器,您实际上必须制作一个包装器,并为本机方法公开托管等价物。我所有的研究都指出,没有办法从托管/跟踪引用中检索本机引用。但是,我仍然注意到,只要目标引用对象在非托管代码中没有更改,使用C++/CLI的跟踪引用一经向外,就可以“工作”——甚至可以返回到非托管代码,因为非托管代码无法访问托管堆栈。还同意,这进一步取决于所创建类的无状态实例。这里的解决方案是只在本机代码中保存任何本机引用—不要涉及跟踪引用