繁体   English   中英

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

[英]AccessViolationException when calling C++/CLI wrapper from C#

我试图创建一个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#调用时,C ++ / CLI如何在控制台应用程序中工作并引发异常?

PS:包装程序使用/ clr选项进行编译。 当我使用/ clr:pure编译包装器时,异常与C#调用相同。 这是否意味着当包装器在C#应用程序中编译并从中调用时,它采用了纯选项?

包装器旨在在C ++和C#之间转换数据,因此,根据我的观点,不应在C#应用程序中使用更严格的选项对其进行编译。 有什么办法告诉C#编译器该程序集包含混合代码?

好的,我终于解决了这个问题。 经过数小时的尝试与失败方法来查找解决方案之后,我尝试首先直接从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的必要性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM