运行 COM DLL 时引发异常

Posted

技术标签:

【中文标题】运行 COM DLL 时引发异常【英文标题】:Exceptions raised running COM DLL 【发布时间】:2017-05-22 05:31:05 【问题描述】:

我会再试一次.... :)

如果我有这个代码:

void CTestDlg::OnBnClickedButtonTest()

    MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
    HRESULT hr;
    hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
    if (FAILED(hr))
    
        __int64 i;
        p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
        p->ReadPublisherData(&i);
    

然后我运行它,我得到了这个静默异常:

Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000099D88FBDC0).

但是,如果我使用包装器(标题:

#pragma once

#import "D:\\My Programs\\2017\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\Release\\MSAToolsLibrary.tlb" raw_interfaces_only named_guids

class CMSATools

public:
    CMSATools();
    ~CMSATools();
    void SetPathXML(CString strPath);
    void OpenPublisherDatabase();

private:
    MSAToolsLibrary::IMSAToolsLibraryInterfacePtr m_pInterface;

类:

#include "stdafx.h"
#include "MSATools.h"


CMSATools::CMSATools()

    m_pInterface = NULL;

    HRESULT hr;
    hr = m_pInterface.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
    if (FAILED(hr))
    
        // TODO: Throw exception ?
    



CMSATools::~CMSATools()



void CMSATools::SetPathXML(CString strPath)

    if (m_pInterface != NULL)
    
        CComBSTR    bstrText = strPath.AllocSysString();
        __int64     iResult;

        m_pInterface->SetPathXML(bstrText, &iResult);
    


void CMSATools::OpenPublisherDatabase()

    __int64 iResult;

    if (m_pInterface != NULL)
        m_pInterface->ReadPublisherData(&iResult);

并在 MFC 中使用它:

void CTestDlg::OnBnClickedButtonGetNames()

    CMSATools toolsMSA;

    UpdateData(TRUE);

    toolsMSA.SetPathXML(m_strPublisherDatabaseXML);
    toolsMSA.OpenPublisherDatabase();

它正在做同样的事情,但我得到了这些静默异常:

Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000090F277C040).
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0xE0434352 (parameters: 0xFFFFFFFF80070002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00007FFCBF6C0000).

为什么一种方法会起作用而另一种方法会导致异常(我似乎无法检测到)?

更新

请稍等——我现在看到了我的愚蠢错误!一会....

更新 2

void CTestDlg::OnBnClickedButtonTest()

    MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
    HRESULT hr;
    hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
    if (SUCCEEDED(hr))
    
        __int64 i;
        p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
        p->ReadPublisherData(&i);
    

我现在更正了测试用例,它们都引发了相同的异常。这是似乎导致 DLL 出现问题的方法:

public void ReadPublisherData(out Int64 iResult)

    iResult = MakeResult(true);

    try
    
        _PublisherData.Publishers.Clear(); // Reset

        XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
        using (StreamReader reader = new StreamReader(_strPathXML))
        
            _PublisherData = (PublisherData)x.Deserialize(reader);
            _PublisherData.BuildPublisherDictionaryFromList();
            iResult = _PublisherData.PublisherDictionary.Count;
        
    
    catch
    
        iResult = MakeResult(false);
    
 

据我所知,它不会导致任何异常。看来……

【问题讨论】:

【参考方案1】:

你唯一明显的问题是你没有问题。您使用的 COM 服务器是用托管语言编写的。很常见,很简单,只需要一个属性。可能是 C#,因为您已经提出了有关它的问题。关键是这些异常是静默的,它们在托管代码中被抛出和捕获。

跨 COM 边界传递异常是非法的,CLR 为您提供了绝对不会发生的绝对保证。如果未捕获托管异常,则它将变成指示失败的 HRESULT 错误代码。由于您使用的是#import 生成的包装器,因此您永远不会真正看到这些错误代码,包装器通过抛出_com_error 将它们转回C++ 异常。您不会尝试捕捉它们,因此如果发生这种情况,那么您的程序将在 terminate() 上崩溃并死掉,不可能不注意到这一点。

Fwiw, 0x04242420 是非致命异常代码,是调试器的实现细节。 Documented here.

EEFileLoadException 是 CLR 内部使用的非托管异常,当要求 Fusion 加载程序集但它找不到它时触发。变成托管的 FileLoadException。考虑到托管 COM 服务器在查找依赖程序集时经常遇到问题,您可能会稍微担心它。但这通常发生在托管代码使用 XML 序列化时,我们知道you are using it。使用异常进行流控制不是很好,但性能也是一个特性。更多相关信息in this post。

所以最好不要担心。如果您不相信您的 COM 服务器能够正确实现,那么只需调试两者即可。项目 > 属性 > 调试并将调试器类型设置从自动更改为混合。并使用 Debug > Windows > Exception Settings 并勾选 CLR Exceptions 复选框以强制调试器在抛出托管异常时中断。

【讨论】:

感谢您的解释。 我在这里有另一个问题:social.msdn.microsoft.com/Forums/vstudio/en-US/… 但我不想在 SO 中重复我的问题或让我的帐户超载。

以上是关于运行 COM DLL 时引发异常的主要内容,如果未能解决你的问题,请参考以下文章

0x0F19B7EC (ucrtbased.dll)处(位于 ex6.exe 中)引发的异常: 0xC0000005: 写入位置 0x00740000 时发生访问冲突。

Emgu.CV.CvInvoke”的类型初始值设定项引发异常

检测 DLL 何时引发异常

dll Matlab实例在c#中运行release时抛出异常

SQL2008:“Microsoft.SqlServer.Management.Dmf.PolicyStore”的类型初始值设定项引发异常

C#调用matlab时,类型初始值设定项引发异常