当前位置 博文首页 > KOOKNUT的博客:WindowsIPC机制--动态数据交换

    KOOKNUT的博客:WindowsIPC机制--动态数据交换

    作者:[db:作者] 时间:2021-07-02 21:26

    动态数据交换(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