引发运行COM DLL的异常

时间:2017-01-07 15:09:09

标签: c# mfc com

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

如果我有这段代码:

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 个答案:

答案 0 :(得分:2)

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

在COM边界传递异常是非法的,CLR为您提供了一个坚如磐石的保证,即永远不会发生这种情况。如果未捕获托管异常,则会将其转换为表示失败的HRESULT错误代码。由于您正在使用#import生成的包装器,因此您永远不会真正看到这些错误代码,包装器通过抛出_com_error将它们重新转换为C ++异常。你没有尝试抓住它们,所以如果它发生了,那么你的程序将会终止并终止于终止(),不可能不会注意到它。

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

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

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