当前位置 博文首页 > KOOKNUT的博客:WindowsIPC机制--动态数据交换
动态数据交换(Dynamic Data Exchange)也是一种进程间通信形式。
两个同时运行的程序间通过DDE方式交换数据时是客户/服务器关系,一旦客户和服务器建立起来连接关系,则当服务器中的数据发生变化后就会马上通知客户。通过DDE方式建立的数据连接通道是双向的,即客户不但能够读取服务器中的数据,而且可以对其进行修改。
DDE有三种数据交换方式:
(1)冷连接(Cool Link):数据交换是一次性数据传输,与剪切板相同。当服务器中的数据发生变化后不通知客户,但客户可以随时从服务器读写数据。
(2)温连接(Warm Link):当服务器中的数据发生变化后马上通知客户,客户得到通知后将数据取回。
(3)热连接(Hot Link):当服务器中的数据发生变化后马上通知客户,同时将变化的数据直接送给客户。
在调用其他DDEML函数前,客户端/服务器必须调用DdeInitialize()函数,以获取实例标识符,注册DDE CallBack函数。
冷连接代码示例:
主类
#include "stdafx.h"
#include "CDdeClass.h"
//静态数据成员初始化
CDdeClass* CDdeClass::m_DdeClass = NULL;
CDdeClass::CDdeClass()
{
//应用程序实例标识符
m_InstanceIdentify = 0;
//建立DDE连接需要有唯一的服务名;主题名和不同主题下的数据项名可以有多个
m_ServerName = _T("NicDDEService");
m_TopicName_1 = _T("Data");
m_ItemName_1 = _T("ServerReply");
m_TopicName_2 = _T("Query");
m_ItemName_2 = _T("ClientRequest");
}
CDdeClass::~CDdeClass()
{
if (m_DdeClass != NULL)
{
//服务器注销服务名
HSZ ServerNameHandle = DdeCreateStringHandle(m_InstanceIdentify, m_ServerName, NULL);
DdeNameService(m_InstanceIdentify, ServerNameHandle, NULL, DNS_UNREGISTER);
DdeFreeStringHandle(m_InstanceIdentify, ServerNameHandle);
}
}
void CDdeClass::DdeServer(CString ServerReply)
{
m_DdeClass = this;
m_ServerReply = ServerReply;
//注册服务器
DdeInitialize(
&m_InstanceIdentify, //服务器实例标识符
(PFNCALLBACK)DdeCallback, //服务器回调函数,处理系统发送的DDE事务
APPCLASS_STANDARD | //将应用程序注册为标准(非监视)DDEML应用程序
CBF_FAIL_ADVISES | //回调函数不接收XTYP_ADVSTART和XTYP_ADVSTOP事务、XTYP_POKE事务、XTYP_REGISTER通知、XTYP_UNREGISTER通知
CBF_FAIL_POKES |
CBF_SKIP_REGISTRATIONS |
CBF_SKIP_UNREGISTRATIONS,
0); //保留值 必须为0
//创建服务名句柄
HSZ ServerNameHandle = DdeCreateStringHandle(m_InstanceIdentify, m_ServerName, NULL);
//在操作系统中注册服务器名字
DdeNameService(m_InstanceIdentify, ServerNameHandle, NULL, DNS_REGISTER);
//释放服务名句柄
DdeFreeStringHandle(m_InstanceIdentify, ServerNameHandle);
}
HDDEDATA CALLBACK CDdeClass::DdeCallback(UINT Type,UINT Format,
HCONV ConversationHandle,
HSZ TopicNameHandle, //主题名
HSZ TempNameHandle, //服务名或者数据项名
HDDEDATA DdeDataHandle, DWORD Data1, DWORD Data2)
{
TCHAR BufferData[MAX_PATH] = { 0 };
switch (Type)
{
case XTYP_CONNECT:
{
//响应客户端使用的DdeConnect()函数 与服务器建立连接
//得到服务名
DdeQueryString(m_DdeClass->m_InstanceIdentify, TempNameHandle, BufferData, sizeof(BufferData), NULL);
//通过比较服务名是否相同 来判断服务器是否支持此服务
if (!_tcscmp(BufferData, m_DdeClass->m_ServerName.GetBuffer()))
{
//连接成功,返回1
return (HDDEDATA)1;
}
break;
}
case XTYP_REQUEST:
{
//响应客户端中使用DdeClientTransaction()函数的XTYP_REQUEST选项 服务器向客户端发送数据
//获得主题名并判断服务器是否支持此主题
DdeQueryString(m_DdeClass->m_InstanceIdentify, TopicNameHandle,BufferData, sizeof(BufferData), NULL);
if (_tcscmp(BufferData, m_DdeClass->m_TopicName_2.GetBuffer()) == 0)
{
//服务器支持此主题
//服务器返回数据
_tcscpy_s(BufferData, m_DdeClass->m_ServerReply.GetBuffer());
return DdeCreateDataHandle(m_DdeClass->m_InstanceIdentify,(LPBYTE)BufferData,
sizeof(BufferData), 0, TempNameHandle, CF_TEXT, NULL);
}
break;
}
case XTYP_EXECUTE:
{
//响应客户端中使用DdeClientTransaction()函数的XTYP_EXECUTE选项 服务器从客户端获取数据
//获得主题名并判断服务器是否支持主题
DdeQueryString(m_DdeClass->m_InstanceIdentify, TopicNameHandle,BufferData, sizeof(BufferData), 0);
if (_tcscmp(BufferData, m_DdeClass->m_TopicName_1.GetBuffer()) == 0)
{
//服务器支持此主题
//获得客户端请求数据
DdeGetData(DdeDataHandle, (LPBYTE)BufferData, sizeof(BufferData), 0);
m_DdeClass->m_ClientRequest = BufferData;
return (HDDEDATA)1;
}
break;
}
}
return NULL;
}
void CDdeClass::DdeClient(CString ClientRequest)
{
m_ClientRequest = ClientRequest;
//m_ClientRequest = "qwiuebgfiquege"
//注册客户端
DdeInitialize(&m_InstanceIdentify,
NULL, //此程序中客户端没有回调函数
APPCLASS_STANDARD |
CBF_FAIL_ADVISES |
CBF_FAIL_POKES |
CBF_SKIP_REGISTRATIONS |
CBF_SKIP_UNREGISTRATIONS,
0);
//与服务器建立不同类型的连接
DdeClientCall(XTYP_EXECUTE, m_ServerName.GetBuffer(), m_TopicName_1.GetBuffer(), m_ItemName_1.GetBuffer());
DdeClientCall(XTYP_REQUEST, m_ServerName.GetBuffer(), m_TopicName_2.GetBuffer(), m_ItemName_2.GetBuffer());
}
void CDdeClass::DdeClientCall(UINT Type, TCHAR* ServerName, TCHAR* TopicName, TCHAR* ItemName)
{
HDDEDATA DdeDataHandle = NULL;
DWORD Result = 0;
TCHAR BufferData[MAX_PATH] = { 0 };
DWORD ReturnLength = 0;
//创建字符串句柄
HSZ ServerNameHandle = DdeCreateStringHandle(m_InstanceIdentify, ServerName, NULL);
HSZ TopicNameHandle = DdeCreateStringHandle(m_InstanceIdentify, TopicName, NULL);
HSZ ItemNameHandle = DdeCreateStringHandle(m_InstanceIdentify, ItemName, NULL);
//客户端与服务器建立连接
HCONV ConversationHandle = DdeConnect(m_InstanceIdentify, ServerNameHandle, TopicNameHandle, NULL);
}
switch (Type)
{
case XTYP_REQUEST:
{
//客户端向服务器发送请求
//处理消息
DdeDataHandle = DdeClientTransaction(
NULL, //只有当type为XTYP_EXECUTE或XTYP_POKE时,才需要此参数。否则,此参数应为空。
NULL, //第一参数的长度此处为0
ConversationHandle, //会话句柄
ItemNameHandle, //数据项名
CF_TEXT, //指定要提交或请求数据项的标准剪贴板格式
Type, //指定事务类型
5000, //客户端等待服务器回应的最大时长
&Result //结果
);
//服务器返回请求数据
ReturnLength = DdeGetData(DdeDataHandle, (LPBYTE)BufferData, sizeof(BufferData), NULL);
if (ReturnLength > 0)
{
m_ServerReply = BufferData;
}
break;
}
case XTYP_EXECUTE:
{
//客户端向服务器发送数据
_tcscpy_s(BufferData, m_ClientRequest);
DdeDataHandle = DdeClientTransaction((LPBYTE)BufferData, sizeof(BufferData), ConversationHandle,
ItemNameHandle, CF_TEXT, Type, 5000, &Result);
break;
}
}
//客户端与服务器断开连接
DdeDisconnect(ConversationHandle);
//释放字符串句柄
DdeFreeStringHandle(m_InstanceIdentify, ServerNameHandle);
DdeFreeStringHandle(m_InstanceIdentify, TopicNameHandle);
DdeFreeStringHandle(m_InstanceIdentify, ItemNameHandle);
}
春招接近尾声,菜狗还没有拿到Offer,难顶啊,学学学
cs