COM技术入门

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了COM技术入门相关的知识,希望对你有一定的参考价值。

一、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是指向的是宽字符串的指针,是一个带有

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

技术分享图片


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 <atlbase.h>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)

技术分享图片

技术分享图片

完成即可

技术分享图片

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

技术分享图片

选择简单对象

技术分享图片


输入简称

技术分享图片


ProgId

ATLProject.HelloSimpleObject

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

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

<Program>.<Component>.<Version>

程序.组件.版本



技术分享图片

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




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

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

技术分享图片

技术分享图片

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

技术分享图片in代表输入


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

retval表示用他做返回值

技术分享图片



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

技术分享图片



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

技术分享图片


ATLProjectLib的uuid

技术分享图片


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

技术分享图片

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


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

技术分享图片

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




4.方法的声明和实现 

在.h文件里声明了

技术分享图片

在.c文件里实现了

技术分享图片



5.添加属性

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

ProPutRef表示为引用参数

技术分享图片

技术分享图片

添加属性方法ID自增



6.编译生成

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

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


7.组件的CLSID

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

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

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

技术分享图片


这个就是你输入的组件名

技术分享图片




二、在MFC中测试简单对象

直接创建一个对话框程序

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

技术分享图片

技术分享图片

测试代码

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

技术分享图片


	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();













以上是关于COM技术入门的主要内容,如果未能解决你的问题,请参考以下文章

Cg入门20:Fragment shader - 片段级模型动态变色(实现汽车动态换漆)

Cg入门19:Fragment shader - 片段级模型动态变色

COM技术入门

Cg入门16:Fragment shader - 片段级光照

Atom编辑器入门到精通 Atom使用进阶

Atom编辑器入门到精通 Atom使用进阶