目录
com方式调用matlab(一)
com方式调用matlab(二)
com方式调用matlab(三)
com方式调用matlab(四)
com方式调用matlab(五)
com方式调用matlab(六)
com方式调用matlab(附:运行结果及代码)
在前面粗略描述了系统的设计思路和matlab生成com组件的相关知识后,从现在开始,将要讨论一下具体的实现方面的问题.在本部分,我们首先讨论一下配置文件的格式和内容,然后再探讨一下以com方式调用matlab进行绘图的相关技术.
前面曾经说到过我们将要把matlab所生成的组件的相关信息,包括组件GUID,接口RIID以及方法参数写到一个配置文件里面去,这样我们的vc程序就能够以可扩充的方式使用matlab组件了.下面是我所设计的配置信息的一个例子:
<?
xml version="1.0" encoding="utf-8"
?>
<
Components
>
<
Graph
physicalName
="c1_1_0.dll"
Name
="图1"
>
<
GUID
>
{8DE06792-8F2B-48CB-9908-080A572802CD}
</
GUID
>
<
RIID
>
{0A0A6D93-0CE5-4228-A5B2-999691D2DE55}
</
RIID
>
<
Method
>
<
MethodName
>
draw2d
</
MethodName
>
</
Method
>
</
Graph
>
<
Graph
physicalName
="c2_1_0.dll"
Name
="图2"
>
<
GUID
>
{13270AAA-5E35-4E91-A8F0-C275C0D5F664}
</
GUID
>
<
RIID
>
{56C22D9C-EC7E-4708-AF2C-98C8C5FC7F24}
</
RIID
>
<
Method
>
<
MethodName
>
drawline2d
</
MethodName
>
<
Param
Name
="x1"
>
5
</
Param
>
<
Param
Name
="x2"
>
-5
</
Param
>
<
Param
Name
="a"
>
-10
</
Param
>
<
Param
Name
="b"
>
10
</
Param
>
</
Method
>
</
Graph
>
<
Graph
physicalName
="c3_1_0.dll"
Name
="图3"
>
<
GUID
>
{9E2B0F53-6638-446D-A292-A0BF9F17656D}
</
GUID
>
<
RIID
>
{FC8A4C39-4B83-46AF-AC71-259CE1791037}
</
RIID
>
<
Method
>
<
MethodName
>
drawline3d
</
MethodName
>
<
Param
Name
="x1"
>
7
</
Param
>
<
Param
Name
="x2"
>
-7
</
Param
>
<
Param
Name
="y1"
>
8
</
Param
>
<
Param
Name
="y2"
>
-8
</
Param
>
<
Param
Name
="n"
>
20
</
Param
>
</
Method
>
</
Graph
>
<
Graph
physicalName
="darw123_1_0.dll"
Name
="图4"
>
<
GUID
>
{F2C933B5-E83D-40F0-9A6D-3EF822933172}
</
GUID
>
<
RIID
>
{4151A20D-6F6C-4EBB-8830-D7D66AD250B5}
</
RIID
>
<
Method
>
<
MethodName
>
draw123
</
MethodName
>
<
Param
Name
="x2"
>
7
</
Param
>
<
Param
Name
="x1"
>
-7
</
Param
>
<
Param
Name
="b"
>
8
</
Param
>
<
Param
Name
="a"
>
4
</
Param
>
</
Method
>
</
Graph
>
</
Components
>
上面的配置文件里面包含三个图像的配置,分别是图
1
,图
2
和图
3
。他们具有相同的结构。下面分别说一下配置文件各个部分的信息。
Component
作为配置文件的根存在。
Graph
子节点代表一个图。仔细看一下,
Graph
子节点又包含以下子节点:
GUID
:组件的全局
ID
。他用来唯一标示一个组件。
RIID
:接口相对于组件的
ID
。通过
GUID
、
RIID
你就可以唯一找到你想构建的那个接口。
Method
:接口方法。其中的
MethodName
为接口方法的名称;
Param
为接口方法的参数。
Param
的
Name
属性为借口方法参数的名称。
另外,
Graph
节点包含两个属性。其中:
PhysicalName
为组件文件的物理路径。
vc程序
根据这个物理路径来找到组件。其实对于组件来讲,在注册表中进行注册以后,就在相应系统中建立了组件的全局索引。任何程序只要根据
GUID
和
RIID
就可以找到组件,完全不需要知道物理路径。但是在开发程序的时候,本着这样一个宗旨,就是让软件绿色一些,尽量在不注册的前提下使用组件。当然基于
Matlab
组件对于一些核心模块的依赖,这种思路没有成功。但是这种调用方式对于其他程序而言是可以借鉴的。所以这里还是维持了这种思路。
Name
为组件显示名称。
vc程序
中根据这个名称创建下拉列表供用户进行选择。
下面依照一个例子来说明配置文件是如何进行编写的。
在这里创建的组件的名称为
c2
。在
c2
组件的工作目录中(具体见com方式调用matlab(二)),进入
src
目录,打开
c2_idl_i.c
文件。如下图所示的信息为我们需要填入
xml
的信息。
可以看到,上面的为
RIID
,下面的为
GUID
。那么如何进行区别呢?
GUID
一般是以
CLSID
为前缀的。而
RIID
是以
IID
为前缀的。值得注意的是,这里要将
GUID
和
RIID
修改成
8-4-4
-4-12
(
16
进制)的形式。否则在
CM
中无法识别。在得到这两个信息以后,我们再去找到接口方法的相关信息。打开
c2_com.cpp
文件,会看到如下信息:
这里就是接口方法了.把相关信息填入method节点,一个matlab图的配置就写完了.值得注意的是,matlab接口方法的参数顺序和我们调用的顺序刚好相反,比如对于上面的方法声明,我们在配置里面就得这么写:
具体原因可能和参数的压栈方法有关,这里我也没有深究,如果有人对于具体细节了解的比较详细,希望您能不吝赐教.
通过上面的步骤,我们就完成了配置文件的设计并完成了一个例子.下面来看一看使用matlab组件的具体方法.
其实通过com方式调用matlab进行图形绘制确实不难,对于稍有com组件知识的人来讲,尤为如此.简单的讲,首先使用DllGetClassObject函数创建类厂,然后用类厂获取IDispatch接口,然后用IDispatch接口通过方法的名称调用方法.下面是具体的实现:
bool
CMatlabGraph::DrawGraph(CString sGraphName)
//
绘图
{
if
(
!
this
->
m_pcfg)
{
this
->
m_sError
=
"
获取配置文件失败!
"
;
return
false
;
}
if
(
!
m_pcfg
->
FindGraphInfoByName(
this
,sGraphName))
{
this
->
m_sError
=
m_pcfg
->
m_sError;
return
false
;
}
::CoInitialize(NULL);
IDispatch
*
pIDisp
=
NULL;
//
指向读入的组件文件的句柄
HINSTANCE hinstLib;
//
指向类厂的实例化方法
MYPROC ProcAdd;
BOOL fRunTimeLinkSuccess
=
FALSE;
//
int rtn=0;
//
读取组件文件载入内存
hinstLib
=
LoadLibrary(
this
->
m_sComFileName.GetBuffer(m_sComFileName.GetLength()));
//
如果执行成功,则hinstLib非空
if
(hinstLib
!=
NULL)
{
//
读取指向获取类厂的函数的指针
ProcAdd
=
(MYPROC)GetProcAddress(hinstLib,
"
DllGetClassObject
"
);
//
如果获取成功,则创建类厂
if
(fRunTimeLinkSuccess
=
(ProcAdd
!=
NULL))
{
//
类厂接口
IClassFactory
*
pIf;
//
初始类厂接口为空
pIf
=
NULL;
if
(SUCCEEDED(ProcAdd(m_clsid,IID_IClassFactory,(
void
**
)
&
pIf))
&&
(pIf
!=
NULL))
{
if
(
!
SUCCEEDED(pIf
->
CreateInstance(NULL,m_riid,(
void
**
)
&
pIDisp))
||
(pIDisp
==
NULL))
{
pIf
->
Release();
pIf
=
NULL;
FreeLibrary(hinstLib);
::CoUninitialize();
return
false
;
}
m_hinstLib
=
hinstLib;
//
因为已经取得分发接口,故释放类厂接口
pIf
->
Release();
pIf
=
NULL;
//
根据名称查找接口方法
USES_CONVERSION;
OLECHAR FAR
*
szMember
=
T2OLE((LPCTSTR)(
this
->
m_sMethodName.GetBuffer(
this
->
m_sMethodName.GetLength())));
//
获取方法ID
DISPID MethodID;
if
(
!
SUCCEEDED(pIDisp
->
GetIDsOfNames(IID_NULL,
&
szMember,
1
,LOCALE_SYSTEM_DEFAULT,
&
MethodID)))
{
this
->
m_sError
=
"
取接口方法ID失败
"
;
return
false
;
}
//
填入参数
DISPPARAMS dispparams
=
{
this
->
m_pvars, NULL,
this
->
m_nparacount,
0
}
;
//
调用方法
HRESULT hr
=
pIDisp
->
Invoke(MethodID,IID_NULL,GetUserDefaultLCID(),DISPATCH_METHOD,
&
dispparams,NULL,NULL,NULL);
if
(
!
SUCCEEDED(hr))
{
this
->
m_sError.Format(
"
调用失败!错误码:%x
"
,hr);
//
="调用失败!";
FreeLibrary(hinstLib);
::CoUninitialize();
return
false
;
}
//
释放文件
//
FreeLibrary(hinstLib);
//
::CoUninitialize();
return
true
;
}
}
}
::CoUninitialize();
return
false
;
}
下面是CMatlabGraph的类定义:
class CMatlabGraph
{
public:
CMatlabGraph(CGraphConfiguration *cfg);
virtual ~CMatlabGraph();
bool DrawGraph(CString sGraphName);//绘图
CString m_sError;//错误信息
private:
CLSID m_clsid;//组件对象ID
IID m_riid;//接口ID
CString m_sMethodName;//接口方法名称
CString m_sComFileName;//组件文件名称
CComVariant *m_pvars;//接口方法参数
CGraphConfiguration *m_pcfg;//配置
int m_nparacount;//接口方法参数个数
friend class CGraphConfiguration;
HINSTANCE m_hinstLib;
}; 当然,看上去本部分介绍的两块内容似乎关系不大,那么在接下去的几篇随笔里面将会对配置文件和具体组件调用程序的衔接方法作比较详细的说明。
posted on 2006-08-11 19:50
littlegai 阅读(870)
评论(0) 编辑 收藏 引用 所属分类:
我的代码玩具