从C#调用C ++ / CLI包装器时出现AccessViolationException

时间:2014-03-13 14:13:03

标签: c# c++-cli wrapper

我正在尝试创建一个C ++ / CLI包装器,用于将类对象从非托管C ++ DLL传递到托管C#代码(随后在网页上显示对象的内容)。我在非托管C ++代码中有这个函数:

ProbeState _cdecl ManagerAPI::getProbeState()
{
    ProbeState ps = psdao.getLastProbeStateByProbeId(1);
    return ps;
}

我在C ++ / CLI包装器中调用该函数:

using namespace System;

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "../ManagerApp/ProbeState.h"

typedef ProbeState(*PSFunc)(void);

public ref class ManagerAPIWrapper
{
private:
    HINSTANCE managerApp;

public:
    ManagerAPIWrapper()
    {
        managerApp = LoadLibrary(L"ManagerApp.dll");
    }

    System::String^ testFunc()
    { 
        PSFunc psFunc = (PSFunc)GetProcAddress(managerApp, "?getProbeState@ManagerAPI@@QAA?AVProbeState@@XZ");

        ProbeState *ps = new ProbeState(psFunc());

        System::String ^s = gcnew System::String(ps->getName().c_str());

        delete ps;

        return s;
    }
};

最后我从C#控制器调用包装器:

ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
ViewBag.DllMessage = wrapper.testFunc();

它总是在行 ProbeState * ps = new ProbeState(psFunc());

上引发异常

奇怪的是,当我将C ++ / CLI包装器编译为具有附加主函数的控制台应用程序时:

int _tmain(int argc, _TCHAR* argv[])
{
ManagerAPIWrapper::ManagerAPIWrapper wrapper;

System::Console::WriteLine(wrapper.testFunc());

getchar();

return 0;
}

此代码工作正常,并打印出C ++ DLL从数据库中检索的状态名称。为什么C ++ / CLI在控制台应用程序中工作,并在从C#调用时抛出异常?

P.S。:使用/ clr选项编译包装器。当我使用/ clr:pure编译包装器时,异常与C#调用相同。是否意味着当包装器在C#app中编译并调用时,它需要纯选项吗?

包装器用于在C ++和C#之间转换数据,因此根据我的意见,它不应该在C#app中使用更严格的选项进行编译。有没有办法告诉C#编译器这个程序集包含混合代码?

1 个答案:

答案 0 :(得分:0)

好的,我终于完成了这件事。使用try&amp; fail方法找到解决方案花了好几个小时后,我试图直接从C#代码中调用非托管DLL中的函数,然后调用包装器的构造函数,该函数在LoadLibrary调用中成功。 C#控制器中的代码现在看起来像这样:

 [DllImport("C:\\ManagerApp.dll", CharSet = CharSet.Unicode, 
      EntryPoint = "?initFunc@ManagerAPI@@QAEHXZ")]
    private static extern int initFunc();

    public ActionResult APITest()
    {
        ViewBag.Message = "API output test page.";

        if (initFunc() == 0)
        {
            ViewBag.Error = "Could not initialize the library.";

            return View();
        }

        ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
        ViewBag.DllMessage = wrapper.testFunc();

        return View();
    }

我认为可能有助于在非托管DLL上为包装器DLL添加依赖项,因此无需调用initFunc