可视化 为什么我的 C# 和 C++ dll 表现出不同的行为
visual Why do my C# and C++ dlls exhibit different behavior?
我正在做一个项目,该项目涉及创建一个支持某个接口的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 测试用例时检查应用程序事件。查找所有失败的操作。
我希望这会以某种方式帮助您
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么我的代码在输出中增加了93天
- 为什么我的for循环不能正确获取argv
- 为什么二进制搜索在我的测试中不起作用
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 为什么我的 std::ref 无法按预期工作?
- 为什么我的删除节点函数实际上没有删除节点?
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 为什么我的多线程作业队列崩溃
- 为什么我的排序算法会更改数组值
- 为什么我的变量没有更新,我的 LED 没有亮起?
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 为什么我的程序在for循环中k=0时返回垃圾值
- 为什么它只打印双链接列表的第一个值,而我的程序却崩溃了
- 为什么我的点没有在 OpenGL 中绘制鼠标所在的位置?
- 为什么我的共享库中存在展开符号
- 为什么我的C++代码中出现'Segmentation Fault: 11'行?
- 为什么我的递归函数按降序打印,然后按升序打印?