P / Invoke:指针内存损坏

时间:2014-11-10 12:28:30

标签: c++ mono pinvoke

我将部分FBX SDK(使用公共API关闭)包含Mono(因此COM,CLI不是选项)和一堆extern' s顺利,直到我必须返回一个非指针实例。 See here

关键是我必须将它返回到C ++以进行另一次调用。因为我不知道你如何在没有指针的情况下做到这一点,我就这样回复了:

FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
{
    return &obj->GetFirstProperty();
}

..并且直到我尝试下一个代码片段,我得到了" System.AccessViolationException:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。" 消息。

FBXAPI const wchar_t* Property_GetName(FbxProperty* prop)
{
    int c = prop->GetSrcPropertyCount();
    return L"Test";
}

如果我在C ++中使用相同的调用使用几乎相同的代码,那很好。我以相同的方式完成了另外~20个函数调用,但没有" pointerfy"它,它们一切都很好,所以我不认为我的DllImport应该受到责备。因此,如果引用是责任,我该怎么做呢?当然,我之所以不在某处存储全局静态引用,只是因为有人从API中调用它?

感谢任何帮助,C / C ++和它处理内存的明确方式对我来说是新的。

1 个答案:

答案 0 :(得分:1)

我认为您的程序崩溃了,因为您获取指针的属性不再存在。让我澄清并首先剖析以下内容:

FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
{
    return &obj->GetFirstProperty();
}

我查找了FBX的文档,FbxObject::GetFirstProperty()的返回类型为FbxProperty。请注意,返回值不是任何指针或引用?这意味着你得到一个所谓的“自动变量”,或者在这种情况下是一个“临时的”。这种对象只会持续到你离开范围,在这种情况下是你的包装的Object_GetFirstProperty()。之后,清理对象并从内存堆栈中删除。 FbxObject::GetFirstProperty()会为您提供该属性的副本,而不是实际的引用。在内部它可能会有所不同,但你的包装器关注的是属性对象本身,而不是它的内容。

所以你正在做的是当你把它传递给Property_GetName()时,你得到一个指向一个不再有效的地址的指针。

C ++在对象生存期方面的行为与C#不同。 C#中的一个名为MyObj的对象可以被认为是像MyObject*这样的C ++指针类型 - 它就像一个参考值。在C#中,您还有像struct之类的值类型,它们等同于C ++自动变量。所有自动变量在其生命周期范围被删除时都会被销毁。

要解决问题,您必须做的是直接保存从FbxObject::GetFirstProperty()获得的对象,而不是指向它的指针。您基本上必须将对象编组到正确的.NET类中,以便它的内容不会丢失。

或者,您可以只分配动态内存并将FbxObject::GetFirstPoperty()中的对象复制到那里,并返回指向您自己内存的指针。当然,您以后必须手动删除此内存。这是一个简单的例子:

FBXAPI FbxProperty* Object_GetFirstProperty(FbxObject* obj)
{
    // Allocate custom memory.
    char* myMem = new char[sizeof(FbxProperty)];

    // Copy the property's content there.
    std::memcpy(myMem, &obj->GetFirstProperty(), sizeof(FbxProperty));

    // Return custom memory address.
    return reinterpret_cast<FbxProperty*>(myMem);
}

这应该可以解决您的内存损坏问题。但是在C ++中你必须手动释放这个内存,当你完成属性时:

FBXAPI void Property_Free(FbxProperty* prop)
{
    // Free previously allocated memory
    delete[] prop;
}

但是这种尝试可能会导致其他问题,具体取决于实际FbxProperty处理其内部数据的方式。你正在创建一个对象的副本,但是如果原始的temporaty / auto-variable在破坏时删除了重要的内存,那么你将获得类似于现在的内存。

如果你真的很机智,你可以为你需要的每个FBX类型编写真正的包装类,并编组整个类类型而不是生成separete C函数,每次你想获得一个值或属性时你必须P / Invoke