【问题标题】:AccessViolation, when calling C++-DLL from C++/CLIAccessViolation,从 C++/CLI 调用 C++-DLL 时
【发布时间】:2010-12-09 09:21:25
【问题描述】:

我为 C++-DLL 编写了 C++/CLI 包装器,以便在 C# 程序中使用该 DLL。

但是,当我调用一个需要 char* 的函数时,我得到一个 AccessViolation

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    IntPtr ptr = Marshal::StringToHGlobalAnsi(key);
    pin_ptr<char> cKey = static_cast<char*>(ptr.ToPointer());
    int val = methodX(a,cKey, v); // AccessViolation here

    Marshal::FreeHGlobal(ptr);
    return val;
}

C++ 函数的签名是

int methodX(int a, char *Key, long v);

编辑 1

像下面这样“固定”也没有用:

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    IntPtr ptr = Marshal::StringToHGlobalAnsi(key);
    char* cKey = static_cast<char*>(ptr.ToPointer());
    pin_ptr<char> pinned = cKey;
    int val = methodX(a,cKey, v);

    Marshal::FreeHGlobal(ptr);
    return val;
}

编辑 1 结束

编辑 2

我也尝试了 PtrToStringChars 以下方式(感谢马特,还找到了一些文档here):

int Wrapper::Net_methodX(int a, String^ key, long v)
{
    pin_ptr<const wchar_t> wkey = PtrToStringChars(key);

    size_t convertedChars = 0;
    size_t  sizeInBytes = ((key->Length + 1) * 2);
    errno_t err = 0;
    char * ckey = (char * ) malloc(sizeInBytes);

    err = wcstombs_s(&convertedChars, ckey, sizeInBytes, wkey, sizeInBytes);

    int val = methodX(A_Symbol_Table,ckey, Value);

    return val;
}

AccessViolation 仍然发生,可能是 methodX() 中的错误(这是一个第三方 DLL)。

编辑 2 结束

我在这里阅读了一些相关问题,但尚未找到解决方案。

有什么提示吗? 谢谢。

【问题讨论】:

    标签: c++-cli access-violation


    【解决方案1】:

    我知道这是一个老问题,但是对于偶然发现这个问题并寻找答案的人来说,这里有一些更简单的解决方案。

    1. 只需使用sprintf 进行如下转换:sprintf(cStr, "%s", clrString);。有关完整示例,请参阅 my answer to this question
    2. 按照 Matt Smith 的建议阅读 KB311259。如果您使用的是 VS 2008 或更高版本,请使用 marshal_as&lt;&gt;(知识库中的方法 #4)。它比该文档中的其他方法简单得多。

    【讨论】:

    • 刚才遇到了同样的问题。 marshal_as&lt;const char*&gt; 最终为我工作得很好,而我之前遇到过 Marshal::StringToHGlobalAnsi 的问题。
    【解决方案2】:

    西蒙, 我尝试了您的示例,但没有遇到访问冲突。这是我的代码:

    using namespace System;
    using namespace System::Runtime::InteropServices;
    
    ref class Wrapper
    {
    public:
        static int Net_methodX(int a, String^ key, long v);
    };
    
    int methodX(int a, char * pKey, long v)
    {
        IntPtr ptr = static_cast<IntPtr>(pKey);
        String ^ pString = Marshal::PtrToStringAnsi(ptr);
        System::Console::WriteLine(pString);
        return a;
    }
    
    int Wrapper::Net_methodX(int a, String^ pKey, long v)
    {     
        IntPtr ptr = Marshal::StringToHGlobalAnsi(pKey);     
        pin_ptr<char> cKey = static_cast<char*>(ptr.ToPointer());     
        int val = methodX(a,cKey, v); // AccessViolation here      
        Marshal::FreeHGlobal(ptr);     
        return val; 
    }
    
    void main()
    {
        Wrapper wrapper;
        String ^ p = gcnew String("Hello");
        wrapper.Net_methodX(0, p, 0);
    }
    

    另外,我有几个cmets:

    1. 在这里阅读:http://support.microsoft.com/kb/311259
    2. 您正在对本机内存使用 pin_ptr。 StringToHGlobalAnsi 方法返回本机内存,所以我认为在这里使用 pin_ptr 没有意义。如果您使用的方法可以返回指向托管内存的指针(如 PtrToStringChars),则 pin_ptr 将是有意义的。除非您正在修改字符串,否则您可能无论如何都希望使用 PtrToStringChars 方法——以避免不必要的分配和复制。
    3. 您能发布一个导致问题的methodX 示例版本吗?如果我能重现该问题,我可能会提供更多帮助。

    【讨论】:

    • 感谢 2 的澄清。我尝试使用 PtrToStringChars(请参阅我原始帖子中的编辑 2),但仍然发生 AccessViolation。不幸的是 methodX() 来自第三方 DLL,因此没有源代码,只有糟糕的文档。我只是得到一个跟踪,该方法已使用 a、key 和 v 的值输入。
    • 为了消除 methodX 是问题的可能性,您是否尝试过传入本机分配的 char * (实际上,您的编辑 2 似乎尝试了这个)?如果您收到 TRACE 表明该方法已被输入,那么我怀疑 methodX 是罪魁祸首(或者您传递了它不期望的东西)。
    • 是的,我认为问题也出在 methodX 中。我只是想确保包装器中没有错误。感谢您的帮助。
    【解决方案3】:

    西蒙

    我觉得下面的代码有问题

    pin_ptr<char> cKey = static_cast<char*>(ptr.ToPointer());
    

    您可能想阅读此http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/0bd049fe-844a-4cb6-b9f6-c8f5107bc957

    如果对你有帮助,请告诉我。

    苏杰

    【讨论】:

    • 正如链接中所建议的,我尝试“固定”cKey 以避免 GC,并将 char* 传递给 C++ 函数。但是 AccessViolation 仍然发生。
    猜你喜欢
    • 2019-10-27
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多