引发异常 运行 COM DLL
Exceptions raised running COM DLL
我会再试一次....:)
如果我有这个代码:
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).
但是,如果我使用包装器 (header:
#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;
}
Class:
#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);
}
}
据我所知,它不会导致任何异常。好像...
你唯一明显的问题是你没有问题。您使用的 COM 服务器是用托管语言编写的。很常见,只需一个属性就可以简单地完成。可能是 C#,因为您已经问过有关它的问题。关键是这些异常是静默的,它们被抛出并被托管代码捕获。
跨 COM 边界传递异常是非法的,CLR 为您提供了绝对不会发生这种情况的保证。如果未捕获托管异常,则它会变成指示失败的 HRESULT 错误代码。由于您正在使用由#import 生成的包装器,因此您永远不会真正看到这些错误代码,包装器通过抛出 _com_error
将它们变回 C++ 异常。您不会尝试捕获它们,因此如果发生这种情况,您的程序将在 terminate() 上崩溃并死掉,不可能不注意到这一点。
Fwiw,0x04242420 是非致命异常代码,是调试器的实现细节。 Documented here.
EEFileLoadException 是 CLR 内部使用的非托管异常,当 Fusion 被要求加载程序集但找不到它时触发。变成托管的 FileLoadException。考虑到托管 COM 服务器通常在查找相关程序集时遇到问题,您可能会稍微关心它。但这通常发生在托管代码使用 XML 序列化时,我们知道 you are using it. Using exceptions for flow-control isn't very nice but performance is a feature as well. More about it in this post.
所以最好不要为此烦恼。如果您不相信您的 COM 服务器能够正确实现,那么只需调试两者即可。 Project > Properties > Debugging 并将 Debugger Type 设置从 Auto 更改为 Mixed。并使用 Debug > Windows > Exception Settings 并勾选 CLR Exceptions 的复选框以强制调试器在抛出托管异常时中断。
我会再试一次....:)
如果我有这个代码:
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).
但是,如果我使用包装器 (header:
#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;
}
Class:
#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);
}
}
据我所知,它不会导致任何异常。好像...
你唯一明显的问题是你没有问题。您使用的 COM 服务器是用托管语言编写的。很常见,只需一个属性就可以简单地完成。可能是 C#,因为您已经问过有关它的问题。关键是这些异常是静默的,它们被抛出并被托管代码捕获。
跨 COM 边界传递异常是非法的,CLR 为您提供了绝对不会发生这种情况的保证。如果未捕获托管异常,则它会变成指示失败的 HRESULT 错误代码。由于您正在使用由#import 生成的包装器,因此您永远不会真正看到这些错误代码,包装器通过抛出 _com_error
将它们变回 C++ 异常。您不会尝试捕获它们,因此如果发生这种情况,您的程序将在 terminate() 上崩溃并死掉,不可能不注意到这一点。
Fwiw,0x04242420 是非致命异常代码,是调试器的实现细节。 Documented here.
EEFileLoadException 是 CLR 内部使用的非托管异常,当 Fusion 被要求加载程序集但找不到它时触发。变成托管的 FileLoadException。考虑到托管 COM 服务器通常在查找相关程序集时遇到问题,您可能会稍微关心它。但这通常发生在托管代码使用 XML 序列化时,我们知道 you are using it. Using exceptions for flow-control isn't very nice but performance is a feature as well. More about it in this post.
所以最好不要为此烦恼。如果您不相信您的 COM 服务器能够正确实现,那么只需调试两者即可。 Project > Properties > Debugging 并将 Debugger Type 设置从 Auto 更改为 Mixed。并使用 Debug > Windows > Exception Settings 并勾选 CLR Exceptions 的复选框以强制调试器在抛出托管异常时中断。