接Interop(交互) Between C# and C++ 研究一
在使用ATL之前也先做一个小小的测试项目:
Project:AtlTest
Files:
(通过项目向导添加类:TestFIrst,并通过向导添加类TestFirst的方法Add,则以下文件将有相应的改变)
AtlTest.idl部分:
interface ITestFirst : IDispatch{
[id(1), helpstring("方法Add")] HRESULT Add([in] LONG a, [in] LONG b , [out] LONG* sum);
};
TestFirst.cpp部分:
STDMETHODIMP CTestFirst::Add(LONG a, LONG b , LONG* sum)
{
// TODO: 在此添加实现代码
*sum=a+b;
return S_OK;
}
生成AtlTest.dll.然后可以能过vs2005的工具tlbimp.exe为AtlTest.dll生成可以在.Net下调用的封装好的AtlTestLib.dll.把它与AtlTest.dll放于同一目录下,最后便可在.Net下调用如下:
Project:charptest1
Files:
Program.cs:
static void Main(string[] args)
{
AtlTestLib.TestFirstClass testFirstClass = new AtlTestLib.TestFirstClass();
int sum;
testFirstClass.Add(3, 6, out sum);
Console.WriteLine(sum);
Console.Read();
}
测试成功,心理还是很欣慰的.因为tlbimp.exe这一个工具实在是比较好用,只要一运行便可将COM封装成.Net可调用的DLL了.实在方便.但想到可不可以在COM中传出一个结构呢?因为在多媒体的播放中需要将网络访问的数据如播放列表以某种结构传到UI层,于是为这一个做了一个测试,也很简单:
(1)在项目AtlTest的AtlTest.idl文件中添加如下结构:
[
uuid("581B648D-1A8F-4a2e-81F3-1684799966E8"),
]
struct Program_List
{
BSTR aBstr;
long pid;
long file_type;
long file_size;
long check_size;
long check_offset2;
};
以上为手动添加,不知道如何用向导添加自定义的结构.GUID可以用VS生成一个.
(2)在AtlTest项目AtlTest.idl文件中添加方法如下所示:
interface ITestFirst : IDispatch{
[id(1), helpstring("方法Add")] HRESULT Add([in] LONG a, [in] LONG b , [out] LONG* sum);
[id(2), helpstring("方法GetVariantFunc")] HRESULT GetVariantFunc([out]struct Program_List* pList);
};
并相应的修改TestFirst.h与文件TestFirst.cpp的内容,在文件TestFirst.cpp添加如下部分代码:
STDMETHODIMP CTestFirst::GetVariantFunc(Program_List* pList)
{
// TODO: 在此添加实现代码
if ( NULL == pList)
return E_POINTER;
//pList=(Program_List*)CoTaskMemAlloc(sizeof(Program_List));
pList->aBstr=SysAllocString(TEXT("abcdef"));
pList->check_offset2=3;
pList->check_size=54;
pList->file_size=324;
pList->file_type=2;
pList->pid=1;
return S_OK;
}
因为本人不知道如何在托管环境中调试C++写的COM项目,所以就为这一个COM项目写了一个用于测试调试的C++项目:cpptest1
(1)在文件stdafx.h中添加如下代码:
#import ".."debug"AtlTest.dll" no_namespace
#include <atlbase.h>
#include <atlcom.h>
using namespace ATL;
(2)在文件cpptest1.cpp中添加如下代码:
#include "stdafx.h"
#include "file1.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
//cout<<add(4,2)<<endl;
CoInitialize(NULL);
{
CComPtr<ITestFirst> pTestFirst;
HRESULT hr= pTestFirst.CoCreateInstance(__uuidof(TestFirst),NULL,CLSCTX_SERVER);
if(FAILED(hr))
{
cout<<"create com instance error"<<endl;
getchar();
return 0;
}
Program_List pList;
pTestFirst->GetVariantFunc(&pList);
_bstr_t aStr(pList.aBstr);
cout<<aStr<<endl;
//CoTaskMemFree(&pList);
}
CoUninitialize();
getchar();
return 0;
}
其中file1.h与注释的没有任何意义,可以不用去管它们.最后运行输出"abcdef"代表运行成功.而后也可以通过工具tlbimp.exe生成托管环境下封装的AtlTestLib.dll.并且测试:
Project:charptest1
Files:
Program.cs的Main()函数中:
AtlTestLib.TestFirstClass testFirstClass = new AtlTestLib.TestFirstClass();
try
{
AtlTestLib.Program_List pList;
testFirstClass.GetVariantFunc(out pList);
Console.WriteLine(pList.aBstr);
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
同样运行成功,离成功很近了,现在只有最后一个想法,是如何回调UI上的方法,或都说如何在COM中实现事件.比如在客户端通过网络访问获取到了播放列表后如何通知UI层及时更新界面呢?或者当播放过程当中,网络访问过程当中突然出然意料之外的错误如何通知到用C#写的UI层呢?这一些都不是预知的,只能在发生后通知到UI层,所以一定得用事件来解决事情.
Interop(交互) Between C# and C++ 研究三