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

时间:2012-04-09 20:25:58

标签: c++ visual-c++ dll com atl

我正在开发一个项目,该项目涉及创建一个尊重某个界面的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:\Data\April 4\Data_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我查看了类型库,并为函数说明了这一点:

[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,但是我无法编译我的代码。阅读本文时,我发现这篇文章: Differences between [in, out] and [out, retval] in COM IDL definitions 这似乎表明,由于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;
};

只是尝试一下,我将它们移到了类delcration的顶部,如下所示:

class ATL_NO_VTABLE CUserIDA :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CUserIDA, &CLSID_UserIDAObject>,
public IUserIDA
{

ExploreDataObjects::IFMANWiffFilePtr ipFMANWiffFile;
ExploreDataObjects::IFMANWiffFile2Ptr ipFMANWiffFile2;

我认为默认情况下这些也是私人会员和以前一样,所以我无法解释为什么这似乎有效。有人可以解释一下吗?

1 个答案:

答案 0 :(得分:0)

您的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); 

我相信您无法更改库的代码,因此我建议您在运行CPP测试用例时尝试使用“procmon.exe”和“dbgview.exe”等外部调试工具来检查应用程序事件。寻找所有失败的行动。

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