一个商品化的软件都提供安装程序,用户只需要运行程序SETUP.EXE或INSTALL.EXE,确认版权信息、输入产品序列号及选择不同的安装方式,即可按提示完成软件的安装。
一、DDE接口
为了方便用户使用,还必须创建程序文件夹和快捷键。Windows是利用 Program Manager的动态数据交换DDE接口来创建程序文件夹和快捷键的。为了帮助读者理解DDE的机制,我们首先要简单的介绍一下DDE的概念。
动态数据交换是Windows应用程序在运行时数据交换的一种技术,它是由一组DDE协议构成,并由DDEML动态库所支持。在一次DDE动态交互过程中,进行交互的一方称为客户方,另一方称为服务器方,而且一次DDE交互总是从客户端发起,由服务器提供各种数据服务。每个服务器有唯一的一个名字,称之为服务名,由一个字符串表示,客户端通过此服务名字符串与服务器建立连接。服务器提供的数据由主题名划分成不同的数据集,并由项名唯一的指定某个数据集中的某个数据(主题名和项名都由字符串表示)。客户程序使用服务器名和主题名与服务器建立会话连接,在连接建立之后使用项名请求服务器提供数据。在DDE中一次数据或服务请求被称为事务,其主要包括以下事务:XTYP_CONNECT 、XTYP_DISCONNECT 、XTYP_ERROR、XTYP_EXECUTE。DDE接口主要包含以下接口函数:
1、 初始化:
DDE程序在进行DDE交互之前,必须调用函数DdeInitialize进行初始化。在初始化函数中指定DDE回调函数,以便使DDEML能够将DDE事务传递给程序。函数调用成功之后返回DMLERR_NO_ERROR。在DDE程序结束运行之前,必须调用函数DdeUninitialize释放与应用程序有关的所有DDEML库资源。
2、 字符串管理:
为建立会话和执行事务,DDE程序之间需要交换字符串。函数DdeCreateStringHandle就是进行字符串管理的函数。这个函数创建一个句柄,在程序中使用这个句柄代表字符串。DDE客户和服务器应用程序可以把字符串句柄做为参数传递给其它DDEML函数。使用完字符串句柄后,应调用函数DdeFreeStringHandle来释放字符串句柄。
3、 数据管理:
在程序之间交换的数据必须存储在DDEML库提供的函数分配和管理的内存对象中。函数 DdeCreateDataHandle创建一个全局内存对象。使用完此对象应调用DdeFreeDatahandle函数删除此全局内存对象。
4、 会话管理:
客户和服务器之间的会话由客户发起。当一个会话被成功的发起之后,客户和参与服务器都会得到一个会话句柄,双方都使用此句柄发送事务和管理这个会话。客户通过调用DdeConnect函数与一个由调用参数指定的服务器建立会话。在任何时候,客户或服务器都可以调用DdeDisconnect函数终止会话。
5、 事务管理:
在客户和服务器建立会话连接之后,客户应用程序可以调用函数DdeClientTransaction在客户和服务器程序之间启动数据事务处理,通过发送一个事务来从服务器中获取数据或服务
6、 DDE回调函数:
参与DDE会话的应用程序必须定义一个回调函数,以便使DDEML能够将DDE事务传递给该函数。
7、 错误处理:
当DDEML函数失败时,程序可以调用函数DdeGetLastError来确定产生错误的原因。
二、SHELL动态数据接口
Program Manager有一个DDE命令字符串接口。此接口允许应用程序创立、删除和重新安装程序组,给程序组添加或删除、替换项目。为了完成上述目的,Program Manager提供了以下命令:CreateGroup、DeleteGroup、ShowGroup、AddItem、DeleteItem、ReplacItem、 Reload、ExitProgram。每条命令必须用方括号括起来,参数放在圆括号里,并用逗号分开,并且多个命令可以连续使用。
为了执行这些命令应用程序必须先和Program Manager建立DDE会话。Program Manager作为DDE服务器,应用程序作为DDE客户端。服务器的服务名和主题名都是PROGRAM。应用程序和Program Manager建立会话之后就可以向其发送命令字符串。
以下先对经常要使用的部分Program Manager DDE命令字符串做一些解释:
1、 CreareGroup
创建一个新程序组或激活一个现存的程序组。其格式为:
CreareGroup(组名[,组标识])
2、 ShowGroup
使现有的组的窗口最大化、最小化或复原。其格式为:
ShowGroup(组名,窗口特征标识[,组标识])
3、 DeleteGroup
删除现有的组。其格式为:
DeleteGroup(组名[,组标识])
4、 AddItem
在已经存在的组中创建一个程序项。其格式为:
AddItem(命令[,标题[,图标文件名[,图标在图标文件的索引[,组窗口中的X坐标[,组窗口中的Y坐标[,默认目录名[,热键[,应用程序第一次显示时是否最小化标志]]]]]]]
)
三、应用实例
我们用下面的例子说明利用SHELL动态数据接口创建程序组和程序项的步骤和技巧。在此例中我们将创建一个程序项。
1、 利用AppWizard 创建基于对话框得工程NewDde,生成如下类和实现文件:
类名 |
基类 |
头文件 |
实现文件 |
CNewDdeApp |
CWinApp |
NewDde.h |
NewDde.cpp |
CNewDdeDlg |
CDialog |
NewDdeDlg.h |
NewDdeDlg.cpp |
CAboutDlg |
CDialog |
NewDdeDlg.h |
NewDdeDlg.cpp |
2、 修改IDD_NEWDDE_DIALOG对话框,加入如下控件:
控件名 |
标题 |
IDC_CREATE |
建立图标 |
IDC_DELETE |
删除图标 |
IDC_STATIC |
测试类型 |
IDOK |
确定 |
IDCANCEL |
取消 |
3、 利用ClassWizard向类CnewDdeDlg中添加处理函数和变量。
为IDOK按钮添加单击事件得处理函数OnOk。
为IDC_CREATE单选按钮添加单击事件得处理函数OnCreate。
为IDC_DELETE单选按钮添加单击事件得处理函数OnDelete。
添加变量m_Create,类型为Cbutton。
另外,在CnewDdeDlg中添加私有变量m_Index ,类型为BYTE。全局函数DdeCallback。
4、 实现以上命令处理函数和全局处理函数。
HDDEDATA CALLBACK DdeCallback
( UINT uType, // transaction type
UINT uFmt, // clipboard data format
HCONV hconv, // handle to the conversation
HSZ hsz1, // handle to a string
HSZ hsz2, // handle to a string
HDDEDATA hdata, // handle to a global memory object
DWORD dwData1, // transaction-specific data
DWORD dwData2 )
{
return 0;
}
void CNewDdeDlg::OnCreate()
{
// TODO: Add your control notification handler code here
m_Index = 1;//修改变量的值以指示是添加还是删除程序项
}
void CNewDdeDlg::OnDelete()
{
// TODO: Add your control notification handler code here
m_Index = 2; //修改变量的值以指示是添加还是删除程序项
}
void CNewDdeDlg::OnOk()
{
// TODO: Add your control notification handler code here
DWORD idInst=0;
HCONV hConv=0;
HDDEDATA hData;
HSZ hszService=0,hszTopic=0;
FARPROC lpCallBack;
if(m_Index==1)//创建程序组和程序项
{
lpCallBack=MakeProcInstance((FARPROC)DdeCallback,
AfxGetInstanceHandle());//取得指向回调函数的指针
if(lpCallBack==NULL)
return;
if(DdeInitialize(&idInst,(PFNCALLBACK)lpCallBack,APPCMD_CLIENTONLY,0L)!=
DMLERR_NO_ERROR)//DDE程序初始化,指定回调函数
return;
hszService=DdeCreateStringHandle(idInst,"PROGMAN",CP_WINANSI);
hszTopic=DdeCreateStringHandle(idInst,"PROGMAN",CP_WINANSI);
if(hszService==NULL||hszTopic==NULL)
return;
hConv=DdeConnect(idInst,hszService,hszTopic,NULL);//与服务器建立连接
if(hConv==NULL)
return;
CString cmmd;
LPTSTR temp = new char[50];
GetCurrentDirectory(50,temp);
cmmd=temp;
cmmd+="\\NewDde.exe";
char cmd[100]="[CreateGroup(\"DDE演示程序\")][AddItem(\"";
strcat (cmd,cmmd);
strcat (cmd,"\",\"DDE演示\")]");//生成Program Manager DDE命令串
hData=DdeCreateDataHandle(idInst,(LPBYTE)cmd,sizeof(cmd),0,0,CF_TEXT,0);
if(DdeClientTransaction((LPBYTE)hData,-1,hConv,0,0,//发送DDE命令
XTYP_EXECUTE,TIMEOUT_ASYNC,NULL)==0)
AfxMessageBox("Error");
}
if(m_Index==2)
{
lpCallBack=MakeProcInstance((FARPROC)DdeCallback,
AfxGetInstanceHandle());//取得指向回调函数的指针
if(lpCallBack==NULL)
return;
if(DdeInitialize(&idInst,(PFNCALLBACK)lpCallBack,APPCMD_CLIENTONLY,0L)!=
DMLERR_NO_ERROR)//DDE程序初始化,指定回调函数
return;
hszService=DdeCreateStringHandle(idInst,"PROGMAN",CP_WINANSI);
hszTopic=DdeCreateStringHandle(idInst,"PROGMAN",CP_WINANSI);
if(hszService==NULL||hszTopic==NULL)
return;
hConv=DdeConnect(idInst,hszService,hszTopic,NULL);//与服务器建立连接
if(hConv==NULL)
return;
char cmd[100]="[DeleteGroup(\"DDE演示程序\")][DeleteItem(\"DDE演示\")]";
hData=DdeCreateDataHandle(idInst,(LPBYTE)cmd,sizeof(cmd),0,0,CF_TEXT,0);
if(DdeClientTransaction((LPBYTE)hData,-1,hConv,0,0,
XTYP_EXECUTE,TIMEOUT_ASYNC,NULL)==0)
AfxMessageBox("Error");
}
}
参考文献
1.陈坚 陈涛 《利用Visual C++ 2.0/4.0编制Windows95应用程序》 西安电子科技大学出版社 1997
|