一、IDispatch接口与Variant类型

1.IDispatch的简介与作用

a) 自动化技术让解释下语音能够调用到自定义的接口,

b) 具有自动化功能的组件是支持IDispatch接口的COM组件

c) IDispatch能够接收一个函数的字符串名称,并执行这个函数.

d) 解释性语言要调用COM组件的自定义接口都是通过自动化控制

程序把自定义接口中的函数的字符串和参数传递给IDispatch

而IDispatch间接的执行自定义接口中的函数.

e) 重要的函数 GetIDsOfNames和Invoke

GetIDsOfNames函数将读取一个函数名称,并返回其调用ID,

Invoke函数接收一个调度ID,跟函数参数,执行调用ID所对应函数功能.

f) 所以解释下语音跟宏语音不必直接认识我们的自定义接口,

只要我们的COM组件支持了IDispatch接口,他们就能通过自动化控制

程序调用我们的IDispatch接口,通过传入函数名字的字符串

和函数参数来执行调用我们的自定义接口.



2.常用的COM数据类型

a)基本类型

CHAR typedef char CHAR  CHAR* char指针

BYTE 无符号的char  BYTE*

SHORT typedef short SHORT  SHORT*

USHORT 无符号short  USHORT*

INT typedef int INT*

UINT 无符号int UINT*

LONG typedef long LONG*

ULONG 无符号long ULONG*

FLOAT FLOAT*

DOUBLE DOUBLE*

VARIANT_BOOL COM中的布尔类型 typedef short VARIANT_BOOL

注意: 0== FALSE  -1== TRUE 

VARIANT_BOOL*

b) 字符串

BSTR COM中的字符串类型

BSTR* BSTR指针

BSTR是指向的是宽字符串的指针,是一个带有

字符计数值的字符串,且这个计数值是保存在字符数组的开头

COM技术入门(2)_第1张图片


3.BSTR基本操作

a) 错误赋值 BSTR str = L"ABCD";

这样是错误的,因为字符串前面没有计数值

b)BSTR SysAllocString(const OLECHAR*)

是COM申请BSTR字符串的方法,把CHAR* 传进去,返回BSTR类型

c)BSTR SysAllocStringLen(const OLECHAR* ,UINT)

根据字符串指针与字符个数构造BSTR字符串

d)UINT SysStringLen(BSTR)获取字符串计数值

e)void SysFreeString(BSTR)释放字符串,当COM中的

字符串(BSTR)不再使用后,调用该函数.

BSTR strA = SysAllocString(L"Hello"); //申请一个字符串

//申请指定个数字符串,从参数1中取

BSTR strB = SysAllocStringLen(strA,SysStringLen(strA));  

SysFreeString(strA);

SysFreeString(strB);



4.COM常用数据类型

IUnknown* COM的最基本的接口指针

IUnknown** 指针的指针

IDispatch*  支持组件自动化的接口

IDispatch** IDispatch*的指针

如果写的组件不想被 解释性的语言 脚本语言

查找接口的话, 可以直接使用IUnknown接口



5.万能数据类型 VARIANT

a) 具备跨语言的特性,同时能存储任何的数据类型

为了实现这个类型的功能,C++中这个类型是一个结构体,

这个结构体,里面又有联合体,联合多种基本数据类型

又有变量类型标志VARTYPE vt.标志他的类型


b) 初始化和清楚

	VARIANT var;
	VariantInit(&var);
	//此时var.vt == VT_EMPTY控件
	//..其他操作
	//清除操作
	VariantClear(&var);


c) VARIANT的使用

用VARIANT保存LONG类型

	VARIANT var;
	VariantInit(&var);
	//此时var.vt == VT_EMPTY控件
	//..其他操作
	//清除操作
	//VT_I4  ×××就是VT_I2
	var.vt = VT_I4;
	//赋值
	var.lVal = 100;
	VariantClear(&var);

FLOAT类型 VT_R4  DOUBLE VT_R8

var.fltVal flaot值 


VARIANT使用BSTR类型

var.vt = VT_BSTR;

var.bstrVal = SysAllocString(L"HEllo");


VT_BOOL 布尔类型


d) 读取值

//先判断类型 在根据类型读取

if(var.vt == VT_l4)
{

  LONG lValue = var.lVar;

}





6.COM数据类型的转换

LONG转换成FLOAT

VARIANT var; 初始化

var.vt = VT_I4;

var.lVar = 100;

VariantChangeType(&var,&var,0,VT_R4);

if(var.vt = VT_R4)

{

 LONG fValue = var.fltValue;

}

清空var




7.VARIANT类型的派生类

a) 在派生类扩展VARIANT类使得他的使用更加方便

#include ATL库里面就带有一个派生类CComVariant

他简化了初始化和清楚, 构造函数可以直接传递基本类型或者VARIANT类型

可以用C++的类型,也可以用COM基本类型来构造一个对象

	INT a = 10;
	CComVariant b(a);
	
	double c = 100.0100;
	CComVariant d(c);

b) 赋值 重载了运算符 operator= 根据不同类型分配不同值

也就是说如果你是INT型  直接对象=值  d = 100;







(二)、测试简单对象


一、ATL制作简单对象(Simple Object)

COM技术入门(2)_第2张图片

blob.png

完成即可

blob.png

1.项目创建完成,添加简单对象(Simple Object)

COM技术入门(2)_第3张图片

选择简单对象

COM技术入门(2)_第4张图片


输入简称

COM技术入门(2)_第5张图片


ProgId

ATLProject.HelloSimpleObject

ProgID是程序员给某个CLSID指定一个程序员易记的名称,

某些计算机语言通过PropID来标记组件 命名规则

..

程序.组件.版本



COM技术入门(2)_第6张图片

双重是支持IDispatch接口的,这样这个接口就会支持一些脚本语言等等。




2.给简单对象添加一个方法,

在类视图选中刚添加的这个(选中接口不是添加的类)然后添加方法

blob.png

blob.png

接口方法是固定的HRESULT,所以只能用输入的参数作为返回值.

COM技术入门(2)_第7张图片in代表输入


加一个指针就可以显示out,表示是输出的可作为返回值

retval表示用他做返回值

blob.png



这个ID表示这个方法 在接口里的ID,直接点击完成即可

COM技术入门(2)_第8张图片



3.来到解决方案管理器查看项目ild文件

blob.png


ATLProjectLib的uuid

COM技术入门(2)_第9张图片


组件的UUID他被ATLProjectLib包含,组件又包含了这个 我们自定义的接口

COM技术入门(2)_第10张图片

会发现我们的组件(简单对象就是组件)支持我们自定义接口(IHelloSimpleObject)


接口定义上面会看到接口IID,

COM技术入门(2)_第11张图片

而且接口里就有一个我们刚创建的方法, 他的ID是1




4.方法的声明和实现 

在.h文件里声明了

blob.png

在.c文件里实现了

COM技术入门(2)_第12张图片



5.添加属性

他会自动给这个属性添加 SET和GET方法,

ProPutRef表示为引用参数

COM技术入门(2)_第13张图片

blob.png

添加属性方法ID自增



6.编译生成

除了dll文件还生成了两个代码文件(ATLProject_i.h和 _i.c)

这两个文件里面描述的是组件的相关信息,如接口方法接口iid,组件CLSID


7.组件的CLSID

组件的CLSID和IID一样,都是GUID,

组件的CLSID用于标识组件,每一个组件都有一个与之对应的CLSID

红色就是组件名,上面就是他的CLSID

COM技术入门(2)_第14张图片


这个就是你输入的组件名

COM技术入门(2)_第15张图片




二、在MFC中测试简单对象

直接创建一个对话框程序

stdafx.h添加 _i.h文件  stdafx.cpp 添加_h.c文件

blob.png

COM技术入门(2)_第16张图片

测试代码

组件这些都被宏定义了,使用更方便

COM技术入门(2)_第17张图片


	HRESULT hr = E_FAIL;
	//使用COM组件必须初始化
	hr = CoInitialize(NULL);
	if(SUCCEEDED(hr))
	{
		//接口指针对象
		IHelloSimpleObject* pHello = NULL;
		//创建接口指针实例  组件对象
		//第一个参数是组件标识
		//第二个参数NULL
		//第三个参数一般用这个CLSCTX_INPROC_SERVER 
		//第四个参数接口标识符
		//第五个参数 接口指针 返回
		hr = CoCreateInstance(CLSID_HelloSimpleObject,NULL,CLSCTX_INPROC_SERVER,
			IID_IHelloSimpleObject,(LPVOID*)&pHello);

		if(SUCCEEDED(hr))
		{
			LONG sum = 0;
			hr = pHello->SumLong(100,100,&sum);

			//读取描述
			BSTR bstrs = SysAllocString(L"");
			hr = pHello->get_m_desc(&bstrs);
			SysAllocString(bstrs);
			bstrs = NULL;

			//写入
			BSTR strb = SysAllocString(L"MFC中测试");
			hr = pHello->put_m_desc(strb);
			SysAllocString(strb);
			bstrs = NULL;

			bstrs = SysAllocString(L"");
			hr = pHello->get_m_desc(&bstrs);
			SysAllocString(bstrs);
			bstrs = NULL;
		}

		//接口不再使用
		pHello->Release();
	}

	//不再使用com组件对象时 一般放在程序结束
	CoUninitialize();