CDDEServer类

//
// DDEServer.h
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#if !defined(AFX_DDESERVER_H__3C8F46D7_D308_414A_BCC4_5F68389331C5__INCLUDED_)
#define AFX_DDESERVER_H__3C8F46D7_D308_414A_BCC4_5F68389331C5__INCLUDED_

#pragma once

/*

MFC进程间通信Server端对象,在SHAREAZA主application中调用Create和CLOSE()

函数,负责处理来自客户端的请求并响应,这里是根据客户端传来的topic是URL,

TORRENT还是COLLECTION,来解析客户端传来的字符串,并向主窗口发送对应的消息

*/

class CDDEServer
{

// Construction

public:

 CDDEServer(LPCTSTR pszService);

 virtual ~CDDEServer();

// Attributes

protected:

 //有自己类型的一个变量

 static CDDEServer* m_pServer;

protected:

 DWORD m_hInstance;

 HSZ  m_hszService;

 CString m_sService;

// Operations

public:

 BOOL Create();

 void Close();

protected:

 CString StringFromHsz(HSZ hsz);

 static CString ReadArgument(LPCTSTR& pszMessage);

 static HDDEDATA CALLBACK DDECallback(UINT wType,
  UINT wFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
  HDDEDATA hData, DWORD dwData1, DWORD dwData2);

protected:

 virtual BOOL CheckAccept(LPCTSTR pszTopic);

 virtual BOOL Execute(LPCTSTR pszTopic,
  HDDEDATA hData, HDDEDATA* phResult);

 virtual BOOL Execute(LPCTSTR pszTopic,
  LPCVOID pData, DWORD nLength);

 virtual BOOL Execute(LPCTSTR pszTopic,
  LPCTSTR pszMessage);

};

extern CDDEServer DDEServer;

#endif // !defined(AFX_DDESERVER_H__3C8F46D7_D308_414A_BCC4_5F68389331C5__INCLUDED_)

//
// DDEServer.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "DDEServer.h"

#include "ShareazaURL.h"
#include "BTInfo.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CDDEServer DDEServer( _T("Shareaza") );

/*

在Windows系统中,各个应用程序(进程)之间常常需要交换、传递数据,

这就要解决进程间的数据通信问题。在最初的16位Windows3.x系统中,

所有Windows应用程序共享单一地址,任何进程都能够对这一共享地址空间

的数据进行读写操作。随着Windwos98、WindowsNT、Windows2000等32位

的操作系统的出现,规定每个进程都有自己的地址空间,一个Windows进程

不能存取另一个进程的私有数据,也就是说,虽然两个进程可以用具有

相同值的指针寻址,但所读写的只是它们各自的数据,这样就减少了进程

之间的相互干扰。那么上述技术的采用是否意味着各个应用程序之间不能

进行数据交换了呢?答案当然是否定的,强大的Windows系统早已为我们

设计了很多方案来解决进行间的通信问题,这里我们只探讨如何通过动态

数据交换(DDE)方法实现进程间的数据通信。

http://dev.yesky.com/481/2279481.shtml

自从微软推出Windows操作系统以来,动态数据交换(DDE)就已经成为Windows的部分,

并且很多Windwos应用程序都使用了DDE技术来实现进程之间的数据交换。DDE是建立

在Windows内部消息系统、全局和共享全局内存基础上的一种协议,用来协调Windows

应用程序之间的数据交换和命令调用,它已经成为应用程序之间通信的一种常用方法。

DDE应用程序可以分为四种类型:客户类型、服务器类型、客户/服务器类型和监视器。

DDE会话发生在客户应用程序和服务器应用程序之间。客户应用程序从服务器应用程序

请求数据或服务,服务器应用程序响应客户应用程序的数据或服务请求。客户/服务器

应用程序是既可以发出请求,又可以提供信息,监视器应用程序则是用语调试的目的。

DDE协议使用三级树型命名:服务(SERVICE)、主题(TOPIC)和数据项(ITEM)

来标识DDE所要传送的数据单元。服务使应用程序具有了提供给其他程序的数据

交换能力;主题类似于目录,是建立会话连接的参数:ITEM才是DDE具体通信时要

传送的数据内容,比如一个数据或一个字符串。

动态交换管理库(DDEML)提供了DDE和应用程序级协议。使用DDEML开发的应用

程序无论是在运行一致性方面还是在应用程序相互通信方面性能均优于没有使用

DDEML的应用程序。而且DDEML的应用使得开发支持DDE的应用程序容易了许多。

建立DDE会话后,客户程序和服务器程序可以通过三种链接方式进行数据交换,

分别是:1、冷链接:客户程序申请数据,服务器程序立即给客户程序发送数据;

2、温链接:服务器程序通知客户程序数据数据项发生了改变,但是并没有将已发

生的值发送给客户程序。3、热链接:当数据项发生变化时,服务器程序立即把变

化后的值发送给客户程序,这是最常用、最方便的方法,

下面的例子就使用的这种方法。

DDE会话初始化

使用API函数DdeInitialize(),在DDEML中注册应用。

会话建立

服务器:注册服务DdeNameService.

客户:连接DdeConnect.

会话过程

类似于Windows的消息循环,会话的过程就是事务处理的过程。

客户通过DdeClientTransaction()来发出事务请求,通过DDE回调函数,

服务器处理客户事务请求,返回DdeCreateDataHandle来发送数据,

同时客户可以调用DdeGetData()获取数据。

会话结束

可由服务方或客户方来终止会话,推出程序时要注消服务,

释放资源,调用DdeUninitialize()。

http://qooi.cn/?action-viewnews-itemid-2456

*/


//
// CDDEServer construction

CDDEServer* CDDEServer::m_pServer = NULL;


CDDEServer::CDDEServer(LPCTSTR pszService)
{
 m_pServer  = this;

 m_hInstance  = NULL;

 m_hszService = NULL;

 m_sService  = pszService;//设置服务字符串
}

CDDEServer::~CDDEServer()
{
 Close();

 m_pServer = NULL;
}

//
// CDDEServer create

BOOL CDDEServer::Create()
{
 USES_CONVERSION;

 DWORD dwFilterFlags = 0;

 UINT uiResult;

 //在初始化的时候设置回调函数为DDECallback

 uiResult = DdeInitialize( &m_hInstance,
  DDECallback, dwFilterFlags, 0 );

 if ( uiResult != DMLERR_NO_ERROR )
 {
  return FALSE;
 }

 /*

The DdeCreateStringHandle function creates a handle that

identifies the specified string. A dynamic data exchange

(DDE) client or server application can pass the string

handle as a parameter to other Dynamic Data Exchange

Management Library (DDEML) functions.

注意这里的m_hszService是根据m_sService来创建的

 */

 m_hszService = DdeCreateStringHandle( m_hInstance,
  (LPCTSTR)m_sService, CP_WINUNICODE );


    DdeNameService( m_hInstance, m_hszService,
  NULL, DNS_REGISTER );

 return TRUE;
}

//
// CDDEServer close

void CDDEServer::Close()
{
 if ( m_hInstance == NULL )
 {
  return;
 }

 DdeNameService( m_hInstance, m_hszService,
  NULL, DNS_UNREGISTER );

 DdeFreeStringHandle( m_hInstance, m_hszService );

 DdeUninitialize( m_hInstance );

 m_hInstance = NULL;
}

//
// CDDEServer static callback

HDDEDATA CALLBACK CDDEServer::DDECallback(UINT wType, UINT wFmt,
            HCONV hConv, HSZ hsz1, HSZ hsz2,
            HDDEDATA hData, DWORD dwData1,
            DWORD dwData2)
{
 HDDEDATA hResult = NULL;

 if ( ! m_pServer )
 {
  return hResult;
 }

 switch ( wType )
 {

 case XTYP_CONNECT:

  hResult = m_pServer->CheckAccept( m_pServer->StringFromHsz( hsz1 ) ) ?
   (HDDEDATA)TRUE : (HDDEDATA)FALSE;

  break;

 case XTYP_CONNECT_CONFIRM:

  // m_pServer->AddConversation( hConv, hsz1 );

  break;

 case XTYP_DISCONNECT:

  // m_pServer->RemoveConversation( hConv );

  break;

 case XTYP_EXECUTE:

  m_pServer->Execute( m_pServer->StringFromHsz( hsz1 ),
   hData, &hResult );

  break;

 }

 return hResult;
}

//
// CDDEServer HSZ to string helper

//调用DDEQueryString拷贝hsz对应的text到一个CString中

CString CDDEServer::StringFromHsz(HSZ hsz)
{
 //获得hsz对应的text的长度

 CString str;

 //The DdeQueryString function copies text associated with a string handle into a buffer.

 DWORD nLen = DdeQueryString( m_hInstance, hsz,
  NULL, 0, CP_WINUNICODE );

 if ( nLen == 0 )
 {
  return str;
 }

 //创建nLen个缓冲区,最后多一个null,因为QueryString不拷贝null

 LPTSTR pBuf = new TCHAR[ nLen + 1 ];

 DdeQueryString( m_hInstance, hsz, pBuf,
  nLen + 1, CP_WINUNICODE );

 pBuf[nLen] = 0;

 str = pBuf;

 delete [] pBuf;

 return str;
}

//
// CDDEServer argument helper

CString CDDEServer::ReadArgument(LPCTSTR& pszMessage)
{
 BOOL bEscape = FALSE;

 CString strPath;

 for ( pszMessage += 7 ; *pszMessage ; pszMessage++ )
 {
  if ( bEscape )
  {
   strPath += *pszMessage;

   bEscape = FALSE;
  }
  else if ( *pszMessage == '/"' )
  {
   if ( pszMessage[1] == '/"' )
   {
    strPath += '/"';

    pszMessage++;
   }
   else
   {
    break;
   }
  }
  else if ( *pszMessage == '//' )
  {
   bEscape = TRUE;
  }
  else
  {
   strPath += *pszMessage;
  }
 }

 return strPath;
}

//
// CDDEServer check accept

//如果参数是URL,TORRENT或者COLLECTION中的一种,则返回真

BOOL CDDEServer::CheckAccept(LPCTSTR pszTopic)
{
 return _tcsicmp( pszTopic, _T("URL") ) == 0 ||
   _tcsicmp( pszTopic, _T("TORRENT") ) == 0 ||
   _tcsicmp( pszTopic, _T("COLLECTION") ) == 0;
}

//
// CDDEServer execute HDDEDATA mode

//执行下面的Execute,封装了返回结果

BOOL CDDEServer::Execute( LPCTSTR pszTopic,
       HDDEDATA hData, HDDEDATA* phResult)
{
 DWORD nLength = 0;

 /*

The DdeAccessData function provides access to the data in

the specified dynamic data exchange (DDE) object.

An application must call the DdeUnaccessData function when

it has finished accessing the data in the object.

hData

[in] Handle to the DDE object to access.

pcbDataSize

[out] Pointer to a variable that receives the size, in bytes,

of the DDE object identified by the hData parameter. If this

parameter is NULL, no size information is returned.

调用DdeAccessData将hDDEDATA hData中的数据读取出来

在下面转化为CString

 */

 LPVOID pData = DdeAccessData( hData, &nLength );

 BOOL bResult = Execute( pszTopic, pData, nLength );

 DdeUnaccessData( hData );

 *phResult = (HDDEDATA)( bResult ? DDE_FACK : DDE_FNOTPROCESSED );

 return bResult;
}

//
// CDDEServer execute LPCVOID mode

//解析字符串,根据pszTopic的类型(URL,TORRENT,COLLECTION)向主窗口发送对应的消息

BOOL CDDEServer::Execute(LPCTSTR pszTopic, LPCVOID pData, DWORD nLength)
{
 //首先将pData转化为unicode型的CString,然后调用下面的Execute方法

 CString str;

 if ( theApp.m_bNT ) // 是NT及其以上系统,返回的是unicode
 {
  // Copy data info a buffer直接将pData拷贝,创建对应的CString

  LPWSTR pszData = new WCHAR[ nLength + 1 ];

  CopyMemory( pszData, pData, nLength );

  // Ensure it has a null terminator

  pszData[ nLength ] = 0;

  // Assign it to the Cstring and remove buffer

  str = pszData;

  delete [] pszData;
 }
 else // windows 9x返回的是ascii,需要转化为unicode
 {
  // Windows 9x will return the data as an ASCII string. (even though UNICODE was specified)

  int nWide = MultiByteToWideChar( CP_ACP, 0,
   (LPCSTR)pData, (int)nLength, NULL, 0 );

  MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pData,
   (int)nLength, str.GetBuffer( nWide ), nWide );

  str.ReleaseBuffer( nWide );
 }

 return Execute( pszTopic, str );
}

//
// CDDEServer execute string mode

BOOL CDDEServer::Execute(LPCTSTR pszTopic, LPCTSTR pszMessage)
{
 CWnd* pWnd = AfxGetMainWnd();

 //根据pszTopic的类型进行不同的处理,pszTopic为URL,TORRENT,COLLECTION中的一种

 if ( _tcscmp( pszTopic, _T("URL") ) == 0 )
 {
  //创建一个CShareazaURL,调用Parse方法完成解析

  //最后向主窗口发送WM_URL消息

  theApp.Message( MSG_SYSTEM,
   IDS_URL_RECEIVED, pszMessage );

  CShareazaURL* pURL = new CShareazaURL();

  if ( pURL->Parse( pszMessage ) )
  {
   if ( ! pWnd->PostMessage( WM_URL, (WPARAM)pURL ) )
   {
    delete pURL;
   }

   return TRUE;
  }

  delete pURL;

  theApp.Message( MSG_ERROR, IDS_URL_PARSE_ERROR );
 }
 else if ( _tcscmp( pszTopic, _T("TORRENT") ) == 0 )
 {
  //是torrent,则创建一个CBTInfo对象,从pszMessage中读取数据
  
  //根据BTInfo对象创建一个CShareazaURL对象完成解析

  //最后向主窗口发送WM_URL消息

  theApp.Message( MSG_SYSTEM,
   IDS_BT_PREFETCH_FILE, pszMessage );

  CBTInfo* pTorrent = new CBTInfo();

  if ( pTorrent->LoadTorrentFile( pszMessage ) )
  {
   if ( pTorrent->HasEncodingError() )
   {
    theApp.Message( MSG_SYSTEM,
     _T("Possible encoding error detected while parsing torrent") );
   }

   CShareazaURL* pURL = new CShareazaURL( pTorrent );

   if ( ! pWnd->PostMessage( WM_URL, (WPARAM)pURL ) )
   {
    delete pURL;
   }

   return TRUE;
  }

  delete pTorrent;

  theApp.Message( MSG_ERROR, IDS_BT_PREFETCH_ERROR, pszMessage );
 }
 else if ( _tcscmp( pszTopic, _T("COLLECTION") ) == 0 )
 {
  //是collection,将pszMessage拷贝到pszPath中,向主窗口发送WM_COLLECTION

  //消息,返回

  LPTSTR pszPath = new TCHAR[ _tcslen(pszMessage) + 1 ];

  CopyMemory( pszPath, pszMessage,
   sizeof(TCHAR) * ( _tcslen(pszMessage) + 1 ) );

  if ( pWnd->PostMessage( WM_COLLECTION,
   (WPARAM)pszPath ) )
  {
   return TRUE;
  }
  else
  {
   delete [] pszPath;
  }
 }

 return FALSE;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值