可视化 为什么我的 C# 和 C++ dll 表现出不同的行为

visual Why do my C# and C++ dlls exhibit different behavior?

本文关键字:我的 为什么 dll C++ 可视化      更新时间:2023-10-16

我正在做一个项目,该项目涉及创建一个支持某个接口的dll,以便插入某些软件以向其添加功能。 这是由调用我的 dll 的 dll 完成的(我没有调用的 dll 的源代码)。 最初,我得到了一个接口和一个 C# 实现,用于创建一个 COM 可见的 dll。 但是,在使用一段时间后,我发现我想使用一些大型C++库,并且由于创建包装器需要很长时间,因此我想创建一个C++ ATL COM dll。 我这样做了,我的类的方法似乎被正确调用(我注册了我的dll,运行程序,方法似乎以正确的顺序调用),但是我发现一些行为是不同的。

我不确定如何解释这一点,因为我的代码与闭源 API 相关,但也许如果我描述一个示例,有人可能会对我可能想要查看的地方有一些想法。

例如,在 C# dll 中,我尝试通过执行以下操作来打开文件:

FMANFileControl fileControl = new FMANFileControl();
FMANFile wFile = null;
const string filePath = @"C:DataApril 4Data_IDA.wiff";
wFile = fileControl.GetFileObject(filePath, 1);
long numSamples = wFile.GetNumberOfSamples();

我得到了正确数量的样本。

在我的C++dll中,我有这个(删除了一些HRESULT检查以保持代码更短):

std::string filePath = "C:\Data\April 4\Data_IDA.wiff";
_bstr_t fileName(filePath.c_str());
IFMANFilePtr ipFMANFile;
IFMANFileControlPtr ipFMANFileControl;
hr = ipFMANFileControl.CreateInstance(__uuidof(FMANFileControl));
hr = ipFMANFile.CreateInstance(__uuidof(FMANFile));
ipFMANFile = ipFMANFileControl->GetFileObject(fileName, 1);
long numSamples = ipFMANFile->GetNumberOfSamples(); 

但是文件无法正确打开,导致零个样本。

使用 oleview,我查看了 typelib,它为函数说:

[id(0x00000001), helpstring("method GetWiffFileObject")] 
IFMANWiffFile* GetWiffFileObject( [in] BSTR WiffFileName, [in] long sample); 

从中获取信息的文件是在实验期间写入的文件,就在它获得更多数据之前,它调用我的方法,我应该能够获得最新的文件。 在 C# dll 中,这是可能的,但在C++ dll 中则不是。 虽然我意识到这一点的细节是隐藏的,但我想知道是否有人知道为什么使用相同接口的 C++ COM dll 和 C#、comvisible dll 在被同一个 dll 调用时会表现出不同的行为。

我现在很困惑,所以任何想法都会受到赞赏,即使它们被证明是偏离基础的。 如果有人认为他们可能能够提供帮助,我可以分享我的源代码。

编辑:我尝试了答案 1 的解决方案,但我无法编译我的代码。 在阅读这篇文章时,我发现了这篇文章:COM IDL 定义中 [输入、输出] 和 [输出、恢复] 之间的差异这似乎表明,由于 FMANFile 指针被标记为 [out, retval],该方法变为:

IFMANFilePtr ExploreData::IFMANFileControl(BSTR filename, long sample);

还是我误解了那篇文章?

编辑2:让它工作,虽然我不太确定为什么。最初,我将标头中的变量声明为类的私有成员变量,如下所示:

class ATL_NO_VTABLE CUserIDA :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CUserIDA, &CLSID_UserIDAObject>,
public IUserIDA
{
.
.
.
public:
STDMETHOD(GetSwitchCriteria)(DOUBLE* intensity, DOUBLE* minMass, DOUBLE* maxMass, VARIANT_BOOL *selectIntensity, LONG* numOfDepCycles);
    .
    .
    .
private:
    ExploreDataObjects::IFMANWiffFilePtr ipFMANWiffFile;
ExploreDataObjects::IFMANWiffFile2Ptr ipFMANWiffFile2;
};

只是为了尝试一下,我把它们移到了班级的顶部,就像这样:

class ATL_NO_VTABLE CUserIDA :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CUserIDA, &CLSID_UserIDAObject>,
public IUserIDA
{
ExploreDataObjects::IFMANWiffFilePtr ipFMANWiffFile;
ExploreDataObjects::IFMANWiffFile2Ptr ipFMANWiffFile2;

我认为默认情况下这些也是私人成员,并且与以前相同,所以我无法解释为什么这似乎有效。 有人可以解释一下吗?

您的C++代码是正确的,但以下行除外:

hr = ipFMANFile.CreateInstance(__uuidof(FMANFile));

这没有任何意义,因为ipFMANFile在下一条语句中再次初始化。

不幸的是,这个 IDL 声明:

IFMANWiffFile* GetWiffFileObject([in] BSTR WiffFileName, [in] long sample); 

仅限于调试目的,因为它不支持通过 HRESULT 报告异常的本机 COM 机制。符合 COM 的声明将是:

HRESULT GetWiffFileObject([in] BSTR WiffFileName, [in] long sample, [out, retval] IFMANWiffFile** fileInstance); 

我相信您无法更改库的代码,因此我建议您尝试一些外部调试工具,如"procmon.exe"和"dbgview.exe",以便在运行 CPP 测试用例时检查应用程序事件。查找所有失败的操作。

我希望这会以某种方式帮助您