1、客户和服务的交互过程:
DDE总是发生在客户应用程序和服务应用程序之间。DDE客户应用程序通过建立和服务程序的会话来发送事务(transaction)来实现数据交换。一个事务是对数据或服务的请求。DDE服务应用程序通过提供数据或服务来响应客户程序的请求。一个服务程序同时可以和多个客户程序建立会话;一个客户程序也能同时从多个服务程序中获取数据。一个应用程序即可以是客户程序,也可以是服务程序。客户或者服务程序都可以在任意时刻结束已经建立的会话。
2、事务(transaction)和DDE回调函数:
DDEML通过发送事务给应用程序的DDE回调函数来通知应用程序相应的活动。一个DDE事务同一个消息很相似。事务是一个带有关于该事务附加信息参数的命名参数。DDEML会传递一个事务给一个由应用程序定义的DDE回调函数,该函数会执行相应的操作。例如:一个客户应用程序试图用DdeConnect函数来同一个服务应用程序建立一个会话。该函数会使DDEML发送一个XTYP_CONNECT事务给服务应用程序的DDE回调函数。该回调函数可以通过返回TRUE给DDEML来允许建立该会话;或者返回FALSE来拒绝。
3、服务名、主题名和事务名:
DDE服务器使用三层结构(服务名、主题名和数据项名)来唯一地标识一个在会话中被交换地数据单元。
服务名是一个在客户程序试图同服务器建立会话时服务应用程序用来响应的字符串。为了同服务器建立会话,客户程序必须指定服务名。虽然一个服务器可以响应多个服务名,但是大多数服务器一般只响应一个服务名。
主题名是一个用来标识逻辑数据上下文的字符串。对于那些操作基于文件处理的服务器,主题名通常是文件名;其它的则是由应用程序指定的字符串。除了服务名,一个客户程序如果试图建立一个会话,则必须指定主题名。
数据项名是一个用来标识服务器传递给客户程序的数据单元的字符串。
4、系统主题:
系统主题提供了一个让任何DDE客户程序得到感兴趣信息的上下文。建议服务应用程序总是支持系统主题。在DDEML.H头文件中,系统主题被定义为SZDDESYS_TOPIC。
为了确定存在哪个服务器以及服务器所提供的信息类型,客户程序可以在启动时,通过设置设备名为NULL来请求一个关于系统主题的会话。
一个服务器必须支持下面的系统主题:SZDDE_ITEM_ITEMLIST、SZDDESYS_ITEM_FORMATS、SZDDESYS_ITEM_HELP、SZDDESYS_ITEM_RTNMSG、SZDDESYS_ITEM_STATUS、SZDDESYS_ITEM_SYSITEMS和SZDDESYS_ITEM_TOPICS。这些数据项名定义在DDEML.H头文件中。为了获得这些字符串的字符串句柄,应用程序必须使用DDEML的字符串管理函数。
5、建立:
在调用其它DDEML函数前,应用程序必须调用DdeInitialize函数。DdeInitialize函数获取应用程序的实例标识符,注册应用程序的DDE回调函数,并为回调函数指定事务过滤。
每个应用程序实例或动态链接库必须将它的实例标识符作为IdInst参数传到那些相应的DDEML函数中。多DDEML实例的目的是为了支持那些DDEML和应用程序同时都需要使用的DLL文件。一个应用程序不能使用多于一个的DDEML的实例。
事务过滤通过阻止DDEML传递不需要的事务给应用程序的DDE回调函数来优化系统性能。应用程序通过在调用DdeInitialize函数时设置ufCmd参数来允许事务过滤。应用程序必须为不在回调函数中处理的每类事务指定一个事务过滤标志。应用程序可以通过调用DdeInitialize重新设置事务过滤。
当不再需要使用DDEML时,应用程序必须调用DdeUninitialize函数。该函数会结束任何打开的会话,并且释放系统分配给应用程序的DDEML资源。
6、回调函数:
每个使用DDEML的应用程序必须使用回调函数来处理DDE事件。DDEML通过将事务传递给应用程序的DDE回调函数来通知应用程序有关的事件。回调函数接收何种事务由所设置的过滤标志、应用程序是否时客户、服务或两者皆是来决定。
DDE回调函数的函数原形如下:
HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1,
hsz2, hdata, dwData1, dwData2)
UINT uType; // transaction type
UINT uFmt; // clipboard data format
HCONV hconv; // handle to conversation
HSZ hsz1; // handle to string
HSZ hsz2; // handle to string
HDDEDATA hdata; // handle to global memory object
DWORD dwData1; // transaction-specific data
DWORD dwData2; // transaction-specific data
{
switch (uType)
{
case XTYP_REGISTER:
case XTYP_UNREGISTER:
.
.
.
return (HDDEDATA) NULL;
case XTYP_ADVDATA:
.
.
.
return (HDDEDATA) DDE_FACK;
case XTYP_XACT_COMPLETE:
//
return (HDDEDATA) NULL;
case XTYP_DISCONNECT:
//
return (HDDEDATA) NULL;
default:
return (HDDEDATA) NULL;
}
}
7、字符串管理:
为了执行某个DDE任务,许多DDEML函数需要获得字符串的访问权。例如:一个客户程序在调用DdeConnect函数来请求同服务器建立会话时,必须指定服务名和主题名。在DDEML函数中,应用程序通过传递字符串句柄而不是指针来指定一个字符串。字符串句柄是一个DWORD值,由系统分配,用来标识一个字符串。
应用程序可以通过调用DdeCreateStringHandle函数来获取特定字符串的字符串句柄。该函数在系统中注册一个字符串,并且返回给应用程序一个字符串句柄。应用程序可以将该句柄传入那些必须访问字符串的DDEML函数中。下面示例解释了这点:
HSZ hszServName;
HSZ hszSysTopic;
hszServName = DdeCreateStringHandle(idInst,"MyServer",CP_WINANSI);
hszSysTopic = DdeCreateStringHandle(idInst,SZDDESYS_TOPIC,CP_WINANSI);
一个应用程序的DDE回调函数在大多DDE事务中接收多个字符串句柄。比如:在XTYP_REQUEST事务处理期间,一个服务器接收两个字符串句柄:一个标识主题名字符串,另一个标识数据项名字符串。应用程序可以通过调用DdeQueryString函数来获取相应于字符串句柄的字符串长度,并且复制字符串到应用程序定义的buffer中。如下所示:
DWORD idInst;
DWORD cb;
HSZ hszServ;
PSTR pszServName;
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0,
CP_WINANSI) + 1;
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb);
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);
一个特定于实例的字符串句柄不能在字符串和相应字符串之间相互映射。
用DdeCmpStringHandles函数来比较两个字符串句柄的值。
当一个字符串句柄被传进回调函数后,如果回调函数返回后该句柄将失效。应用程序可以通过DdeKeepStringHandle函数来保存字符串句柄以备在回调函数返回后使用该句柄。
当应用程序调用了DdeCreateStringHandle函数后,系统会将指定的字符串放入字符串表,同时产生一个用来访问字符串的句柄。系统会为字符串表中的每个字符串维护一个引用计数。
当一个应用程序调用DdeCreateStringHandle函数,并且指定已经存在于字符串表中的字符串,系统会增加引用计数,而不是增加相同的字符串。当应用程序调用了DdeFreeStringHandle函数后,系统会减少引用计数。
当字符串表中的字符串引用计数为0时就被删除。
DDEML字符串管理函数是基于atom管理,并且服从于相同的大小限制。
8、DDEML和线程:
DdeInitialize函数注册一个应用程序为DDEML使用者,并且创建一个DDEML实例。该实例是基于线程的,和调用DdeInitialize函数的线程有关。
所有调用属于一个DDEML实例的对象的DDEML函数必须都由那个调用DdeInitialize函数的线程来创建。
本文地址:http://com.8s8s.com/it/it23579.htm