MFC dll 中的访问冲突(用 C++/CLI 包装)从 C# 程序开始

Posted

技术标签:

【中文标题】MFC dll 中的访问冲突(用 C++/CLI 包装)从 C# 程序开始【英文标题】:Access violation in MFC dll (wrapped in C++/CLI) started from C# program 【发布时间】:2011-07-14 13:32:54 【问题描述】:

我为 mfc dll (C++) 编写了一个托管 C++/CLI 包装器,并且在第二次调用 dll 后出现了一些访问冲突!

包装器

// in .h
typedef CKeyManagerServerApp* (*KeyManagerInstance)(CCommonUtils *);

ManagedKeyInterface::ManagedKeyInterface()

    HINSTANCE m_keyManagerLib = LoadLibrary("pathToDll");

    KeyManagerInstance _createInstance = (KeyManagerInstance)GetProcAddress(m_keyManagerLib, "GetInstance");

    // get native reader interface from managed reader interface
    CCommonUtils *nativeReaderInterface = static_cast<CCommonUtils*>(readerInterface->nativeReaderInterface.ToPointer());

    CKeyManagerServerApp *m_keyManagerApp = (_createInstance)(nativeReaderInterface );


ManagedKeyInterface::~ManagedKeyInterface()

    try

    DestroyKeyManagerInstance _destroyInstance = (DestroyKeyManagerInstance)GetProcAddress(m_keyManagerLib, "DestroyInstance");
    (_destroyInstance)(m_keyManagerApp);

    FreeLibrary(m_keyManagerLib);           

    catch(System::Exception ^e)
    
        FreeLibrary(m_keyManagerLib);
    

本地 MFC 类

extern "C" _declspec(dllexport) CKeyManagerServerApp* GetInstance(CCommonUtils *readerInterface)

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    return new CKeyManagerServerApp(readerInterface);


extern "C" _declspec(dllexport) void DestroyInstance(CKeyManagerServerApp *ptr)

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    delete ptr;


// constructor
CKeyManagerServerApp::CKeyManagerServerApp(CCommonUtils *readerInterface)   

    m_log = new Logging(loggingFilePath); // <--- ERROR at second call


    // reader interface object for communication 
    m_readerComm = new ReaderCommunication(readerInterface, m_log); 

    m_smartmaskcmds = new CSmartMaskCmds(m_readerComm, m_log);

    readerInterface = NULL;


// destructor
CKeyManagerServerApp::~CKeyManagerServerApp()

    // destruct objects     
    delete m_smartmaskcmds; 
    delete m_readerComm;    
    delete m_log;   

在 ReaderCommunication 和 CSmartMaskCmds 中。该对象只会被分配!

在 C# 程序的第一次运行时(加载带有添加引用的包装器)一切正常,但是当我再次启动它时,我得到:

TestKeyManagerApp.exe 中 0x76f85b57 处的第一次机会异常:0xC0000005:访问冲突读取位置 0xdddddddd。 TestKeyManagerApp.exe 中 0x75169617 处的第一次机会异常:Microsoft C++ 异常:内存位置 0x0024e820 处的 CMemoryException..

当我调用 m_log = new Logging(loggingFilePath)

看来析构函数不能正常工作!?

有什么想法!!??

谢谢!

【问题讨论】:

MFC 有一些关于管理全局状态和 DllMain() 的非常难以理解的规则。在我看来,第二次加载 DLL 时没有发生一些初始化。很难理解为什么要这样做,只需链接到 DLL 的导入库,这样您就可以直接调用方法并完成它。 谢谢!但是当 dll 发生变化时,不应该每次都重新编译包装器!提示:我还在 destr 中收到错误消息。第一次运行时的 CKeyManagerServerApp (目标不干净??? -> 所以一些内存伪影或分配仍然存在) 崩溃的调用栈是什么? 嗨!我发现从 CWinApp 派生我的基本 MFC 类并为每个导出的方法使用 AFX_MANAGE_STATE(AfxGetStaticModuleState()) 是必不可少的!我还使用指向另一个对象的指针作为constr。参数(当我理解正确时,这在常规 mfc dll 中是不可能的-> 但我也不能使用扩展 dll(从 C++/CLI 包装器加载 lib))什么是最好的解决方案?链接:msdn.microsoft.com/en-us/library/30c674tx(v=vs.80).aspx 和 msdn.microsoft.com/en-us/library/h5f7ck28(v=vs.80).aspx 【参考方案1】:

当您看到值0xdddddddd 时,表示some pointer was deleted(VC 将在调试版本中设置该值以帮助您识别这些情况)。你没有告诉我们loggingFilePath 是什么以及Logging 是如何实现的,但我的猜测是loggingFilePath 在某个时候被删除了,Logging 试图在构造函数中访问它的值或虚函数(或初始化列表)。

这也可以解释析构函数中的崩溃 - 您正在删除 m_log,它可能包含从 loggingFilePath 获得的非法指针。当您尝试再次使用它时,您会遇到同样的崩溃。

【讨论】:

【参考方案2】:

当我调用 m_log = new Logging(loggingFilePath)

幕后发生了什么?找出它到底在哪里崩溃。如果您使用 C#,请启用非托管调试。我猜问题出在Logging构造函数下。

【讨论】:

嗨!非托管调试已启用!应用程序在其中一些析构函数调用(删除 m_smartmaskcmds;删除 m_readerComm;删除 m_log;)中存在错误,但并不总是在 m_log 中!所以我的猜测是调用对象销毁后内存不干净!但我明天也会发布日志类!

以上是关于MFC dll 中的访问冲突(用 C++/CLI 包装)从 C# 程序开始的主要内容,如果未能解决你的问题,请参考以下文章

运行使用 /clr 构建的 DLL 的本机 C++ 应用程序时访问冲突

C++/CLI 包装器尝试使用 MFC CObject 继承

本机 C++ 程序在使用 C++/CLI 和 C# 互操作 DLL 启动时崩溃

0x5746723c (msvcr100d.dll) 处最可能的异常: 0xC0000005: 读取位置 0xccccccc8 时发生访问冲突

用 C# 重写 MFC DLL?

将非托管 C++ dll 添加到托管 C++ dll