在博客园注册了半年,也潜水了半年。今天第一次写随笔,希望大家包涵。
相信很多朋友都有过平台调用方面的经验,但是从网上搜索的资料来看,好像不是很乐观。
根据我自己在使用C++, C#混合调用过程中的心得,小结成本文,希望可以给感兴趣或需要的朋友一些启示。
因为我只对C#语言稍微熟悉一点,所以本文提到的.Net平台都以C#为例。
1. 在C#语言环境中使用C++ dll文件中的函数: 使用DllImport。
这个在msdn中有很详细的介绍,包括数据封送处理,以及C++/C#的基本类型对照等等。
2.在C++语言环境中使用托管C#组件。
2.1 包装类。
C#中的Regex提供了强大的功能,我们想在C++代码中使用它,为此我们需要给Regex进行包装,定义了如下RegExp类。
RegExp.cs
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
namespace DotNetLib
{
[Guid("0F0D2A66-0262-47b5-A7F9-8BFFB8A13F90"),ComVisible(true)]
public interface iRegExp
{
string Replace(string input, string pattern, string replacement);
string[] Split(string input, string pattern);
}
/// <summary>
/// Wrapper of Regex class to provide
/// it's powerful function of dealing with text.
/// This will generate a COM class which can be
/// used by various platforms or languages.
/// </summary>
[Guid("2634BEA5-17FF-40ba-A837-12D30BAD38D5"),ClassInterface(ClassInterfaceType.None),ComSourceInterfaces(typeof(iRegExp)),ComVisible(true)]
public class RegExp: iRegExp
{
public RegExp()
{
}
#region iRegExp Members
//[return: MarshalAs(UnmanagedType.LPWStr)]
public string Replace(string input, string pattern, string replacement)
{
return Regex.Replace(input,pattern,replacement);
}
public string[] Split(string input, string pattern)
{
return Regex.Split(input,pattern);
}
#endregion
}
}
将该文件编译成Dll文件,然后使用Regasm进行注册,会产生相应的类型库文件,我们假定为DotNetLib.tlb. 至此我们的包装工作完成。
2.2 映射类。
因为我们是通过Com调用的,所以要进行很多数据转换工作,为了避免这些细节,我们定义一个映射类,使得用户使用该类就像使用真正的Regex类一样。
ComInterface.h
#include <comutil.h>
class ComInterface
{
public:
ComInterface(REFCLSID rCLSID);
ComInterface(IUnknown* piUnknown);
~ComInterface(void);
protected:
IUnknown* m_piUnknown;
private:
IDispatch* m_piDispatch;
static bool m_bCoInitialize;
};
ComInterface.cpp
#include "ComInterface.h"
#include <comutil.h>
bool ComInterface::m_bCoInitialize = false;
ComInterface::ComInterface(REFCLSID rCLSID)
{
m_piUnknown = NULL;
m_piDispatch = NULL;
if (!m_bCoInitialize)
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(rCLSID,NULL,CLSCTX_INPROC_SERVER,
IID_IUnknown,(void**)&m_piUnknown);
ATLASSERT(SUCCEEDED(hr));
hr = m_piUnknown->QueryInterface(IID_IDispatch,(void**)&m_piDispatch);
ATLASSERT(SUCCEEDED(hr));
}
ComInterface::ComInterface(IUnknown* piUnknown)
{
m_piUnknown = piUnknown;
m_piDispatch = NULL;
HRESULT hr = m_piUnknown->QueryInterface(IID_IDispatch,(void**)&m_piDispatch);
ATLASSERT(SUCCEEDED(hr));
}
ComInterface::~ComInterface(void)
{
if (m_piDispatch)
m_piDispatch->Release();
if (m_piUnknown)
m_piUnknown->Release();
if (m_bCoInitialize)
{
m_bCoInitialize = false;
CoUninitialize();
}
}
RegExp.h
#include "atlsafe.h"
#include "ComInterface.h"
#import "E:\\MyDocument\\MyProjects\\ComInteropTest\\DotNetLib\\lib\\DotNetLib.tlb" named_guids
using namespace DotNetLib;
class CRegExp : public ComInterface
{
public:
CRegExp();
virtual ~CRegExp();
CString Replace(const CString& strInput, const CString& strParttern,
const CString& strReplacement);
bool Split(const CString& strInput, const CString& strParttern,
SAFEARRAY** ppSafeArray);
private:
iRegExp* m_piRegExp;
};
RegExp.cpp
#include ".\RegExp.h"
CRegExp::CRegExp()
: ComInterface(CLSID_RegExp)
{
HRESULT hr = m_piUnknown->QueryInterface(IID_iRegExp,(LPVOID*)&m_piRegExp);
ATLASSERT(SUCCEEDED(hr));
}
CRegExp::~CRegExp()
{
if (m_piRegExp)
m_piRegExp->Release();
}
CString CRegExp::Replace(const CString& strInput, const CString& strParttern,
const CString& strReplacement)
{
CString strResult;
if (m_piRegExp)
{
strResult = m_piRegExp->Replace(_bstr_t(strInput),_bstr_t(strParttern),
_bstr_t(strReplacement)).GetBSTR();
}
else
strResult = _T("");
return strResult;
}
bool CRegExp::Split(const CString& strInput, const CString& strParttern,
SAFEARRAY** ppSafeArray)
{
if (m_piRegExp)
{
*ppSafeArray = m_piRegExp->Split(_bstr_t(strInput),_bstr_t(strParttern));
return true;
}
else
return false;
}
至此,映射类也定义完成了。我们可以做个简单的测试:
CRegExp exp;
CString strTest = _T("he is a good boy, he is very like his father");
strTest = exp.Replace(strTest, _T("he"), _T("she"));
strTest = exp.Replace(strTest, _T("boy", _T("girl"));
strTest = exp.Replace(strTest, _T("his"), _T("her"));
strTest = exp.Replace(strTest, _T("father"), _T("mother"));
// ok, now strTest should be "she is a good girl, she is very like her mother".
包装的方案比较笨拙,代码的执行效率也不高,但是目前我还没有找到更好的办法。 如果有这方面的达人,希望补充一下。