mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
12 KiB
424 lines
12 KiB
/***************************************************************************/
|
|
/** Microsoft Windows **/
|
|
/** Copyright(c) Microsoft Corp., 1991, 1992 **/
|
|
/***************************************************************************/
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
dde.cpp
|
|
|
|
Aug 92, JimH
|
|
May 93, JimH chico port
|
|
|
|
Member functions for DDE, DDEServer, and DDEClient are here.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "hearts.h"
|
|
|
|
#include "dde.h"
|
|
#include "debug.h"
|
|
|
|
// declare DDE objects
|
|
|
|
DDEClient *ddeClient;
|
|
DDEServer *ddeServer;
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE:DDE
|
|
performs basic DDEML initialization.
|
|
m_bResult is TRUE if everything works.
|
|
|
|
****************************************************************************/
|
|
|
|
DDE::DDE(const TCHAR *server, const TCHAR *topic, DDECALLBACK CallBack,
|
|
DWORD filters) : m_idInst(0), m_CallBack(NULL)
|
|
{
|
|
// Check for basic compatibility, ie protect mode
|
|
|
|
// m_bResult = ( (LOBYTE(GetVersion()) > 2) && (GetWinFlags() & WF_PMODE) )
|
|
// ? TRUE : FALSE;
|
|
m_bResult = TRUE;
|
|
if (!m_bResult)
|
|
return;
|
|
|
|
m_data.Empty(); // clear CString object
|
|
|
|
// Set callback function and filters from passed-in parameters
|
|
|
|
if (!SetCallBack(CallBack))
|
|
return;
|
|
|
|
SetFilters(filters);
|
|
if (!Initialize())
|
|
{
|
|
m_idInst = 0;
|
|
return;
|
|
}
|
|
|
|
// create CString objects and HSZ handles for server and topic
|
|
|
|
m_server = server;
|
|
m_topic = topic;
|
|
m_hServer = CreateStrHandle(m_server);
|
|
m_hTopic = CreateStrHandle(m_topic);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE::~DDE
|
|
cleans up string handles and DDEML-uninitializes
|
|
|
|
****************************************************************************/
|
|
|
|
DDE::~DDE()
|
|
{
|
|
if (!m_idInst)
|
|
return;
|
|
|
|
DestroyStrHandle(m_hServer);
|
|
DestroyStrHandle(m_hTopic);
|
|
|
|
::DdeUninitialize(m_idInst);
|
|
FreeProcInstance((FARPROC)m_CallBack);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE:CreateDataHandle
|
|
converts data to a HDDEDATA handle.
|
|
|
|
****************************************************************************/
|
|
|
|
HDDEDATA DDE::CreateDataHandle(void FAR *pdata, DWORD size, HSZ hItem)
|
|
{
|
|
return ::DdeCreateDataHandle(m_idInst, // instance ID
|
|
(LPBYTE)pdata, // data to convert
|
|
size, // size of data
|
|
0, // offset of data
|
|
hItem, // corresponding string handle
|
|
CF_OWNERDISPLAY,// clipboard format
|
|
0); // creation flags, system owns
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE:CreateStrHandle
|
|
converts a string into a HSZ. The codepage defaults to CP_WINANSI.
|
|
|
|
****************************************************************************/
|
|
|
|
HSZ DDE::CreateStrHandle(LPCTSTR str, int codepage)
|
|
{
|
|
HSZ hsz = NULL;
|
|
|
|
if (m_idInst)
|
|
hsz = ::DdeCreateStringHandle(m_idInst, str, codepage);
|
|
|
|
if (hsz == NULL)
|
|
m_bResult = FALSE;
|
|
|
|
return hsz;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE::DestroyStrHandle
|
|
frees HSZ created by CreateStrHandle
|
|
|
|
****************************************************************************/
|
|
|
|
void DDE::DestroyStrHandle(HSZ hsz)
|
|
{
|
|
if (m_idInst && hsz)
|
|
::DdeFreeStringHandle(m_idInst, hsz);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE:GetData
|
|
Like GetDataString, this function retrieves data represented by
|
|
hData provided in callback function. However, the buffer must be
|
|
provided by the caller. The len parameter defaults to 0 meaning
|
|
the caller promises pdata points to a large enough buffer.
|
|
|
|
****************************************************************************/
|
|
|
|
PBYTE DDE::GetData(HDDEDATA hData, PBYTE pdata, DWORD len)
|
|
{
|
|
DWORD datalen = ::DdeGetData(hData, NULL, 0, 0);
|
|
if (len == 0)
|
|
len = datalen;
|
|
::DdeGetData(hData, pdata, min(len, datalen), 0);
|
|
return pdata;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE:GetDataString
|
|
The default value of hData is NULL meaning just return the current
|
|
m_data string. Otherwise get associated DDE data. The caller does
|
|
not have to provide a CString buffer.
|
|
|
|
****************************************************************************/
|
|
|
|
CString DDE::GetDataString(HDDEDATA hData)
|
|
{
|
|
if (hData == NULL) // default paramenter
|
|
return m_data;
|
|
|
|
DWORD len = ::DdeGetData(hData, NULL, 0, 0); // find length
|
|
TCHAR *pdata = m_data.GetBuffer((int)len);
|
|
::DdeGetData(hData, (LPBYTE)pdata, len, 0);
|
|
m_data.ReleaseBuffer();
|
|
return m_data;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE::Initialize
|
|
performs DDEML initialization
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDE::Initialize()
|
|
{
|
|
m_initerr = (WORD)::DdeInitialize(&m_idInst, (PFNCALLBACK)m_CallBack,
|
|
m_filters, 0);
|
|
m_bResult = (m_initerr == DMLERR_NO_ERROR);
|
|
return m_bResult;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDE::SetCallBack
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDE::SetCallBack(DDECALLBACK CallBack)
|
|
{
|
|
if (m_CallBack)
|
|
FreeProcInstance((FARPROC)m_CallBack);
|
|
|
|
m_CallBack = (DDECALLBACK)MakeProcInstance((FARPROC)CallBack,
|
|
AfxGetInstanceHandle());
|
|
|
|
m_bResult = (m_CallBack != NULL);
|
|
return m_bResult;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
DDEServer functions
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
|
|
DDEServer::DDEServer
|
|
registers server name
|
|
|
|
****************************************************************************/
|
|
|
|
DDEServer::DDEServer(const TCHAR *server, const TCHAR *topic,
|
|
DDECALLBACK ServerCallBack, DWORD filters) :
|
|
DDE(server, topic, ServerCallBack, filters)
|
|
{
|
|
if (!m_bResult)
|
|
return;
|
|
|
|
if (::DdeNameService(m_idInst, m_hServer, NULL, DNS_REGISTER) == 0)
|
|
m_bResult = FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEServer::~DDEServer
|
|
unregisters server name
|
|
|
|
****************************************************************************/
|
|
|
|
DDEServer::~DDEServer()
|
|
{
|
|
::DdeNameService(m_idInst, NULL, NULL, DNS_UNREGISTER);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEServer::PostAdvise
|
|
notify clients that data has changed
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDEServer::PostAdvise(HSZ hItem)
|
|
{
|
|
return ::DdePostAdvise(m_idInst, m_hTopic, hItem);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
DDEClient functions
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
|
|
DDEClient::DDEClient
|
|
after DDE construction, connect to specified server and topic.
|
|
m_bResult indicates success or failure.
|
|
|
|
****************************************************************************/
|
|
|
|
DDEClient::DDEClient(const TCHAR *server, const TCHAR *topic,
|
|
DDECALLBACK ClientCallBack, DWORD filters) :
|
|
DDE(server, topic, ClientCallBack, filters)
|
|
{
|
|
if (!m_bResult) // if DDE construction failed
|
|
return;
|
|
|
|
m_timeout = m_deftimeout = TIMEOUT_ASYNC; // default to asynch trans
|
|
|
|
m_hConv = ::DdeConnect(m_idInst, m_hServer, m_hTopic, NULL);
|
|
if (m_hConv == NULL)
|
|
m_bResult = FALSE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEClient::~DDEClient
|
|
disconnects from server
|
|
|
|
****************************************************************************/
|
|
|
|
DDEClient::~DDEClient()
|
|
{
|
|
::DdeDisconnect(m_hConv);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEClient:Poke
|
|
Use this function to send general unsolicited data to the server.
|
|
String data can be sent more conveniently using string Poke below.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDEClient::Poke(HSZ hItem, void FAR *pdata, DWORD len, DWORD uTimeout)
|
|
{
|
|
if (uTimeout == NULL) // default
|
|
m_timeout = m_deftimeout;
|
|
else
|
|
m_timeout = uTimeout;
|
|
|
|
ClientTransaction((LPBYTE)pdata, len, hItem, XTYP_POKE, CF_OWNERDISPLAY);
|
|
return m_bResult;
|
|
}
|
|
|
|
BOOL DDEClient::Poke(HSZ hItem, const TCHAR *string, DWORD uTimeout)
|
|
{
|
|
if (uTimeout == NULL) // default
|
|
m_timeout = m_deftimeout;
|
|
else
|
|
m_timeout = uTimeout;
|
|
|
|
ClientTransaction((void FAR *)string, lstrlen(string)+1, hItem, XTYP_POKE);
|
|
return m_bResult;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEClient::RequestString
|
|
DDEClient::RequestData
|
|
These request a synchronous update from server on specified item.
|
|
|
|
RequestString returns a BOOL which says if the request succeeded.
|
|
Get the result from GetDataString(void).
|
|
|
|
RequestData returns a HDDEDATA. If it is not NULL, pass it to
|
|
GetData() along with a buffer to copy the result in to.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDEClient::RequestString(HSZ hItem, DWORD uTimeout)
|
|
{
|
|
if (uTimeout == NULL) // default
|
|
m_timeout = m_deftimeout;
|
|
else
|
|
m_timeout = uTimeout;
|
|
|
|
HDDEDATA hData = ClientTransaction(NULL, 0, hItem, XTYP_REQUEST);
|
|
|
|
if (m_bResult)
|
|
GetDataString(hData);
|
|
else
|
|
m_data.Empty();
|
|
|
|
return m_bResult;
|
|
}
|
|
|
|
HDDEDATA DDEClient::RequestData(HSZ hItem, DWORD uTimeout)
|
|
{
|
|
if (uTimeout == NULL) // default
|
|
m_timeout = m_deftimeout;
|
|
else
|
|
m_timeout = uTimeout;
|
|
|
|
HDDEDATA hData = ClientTransaction(NULL, 0, hItem, XTYP_REQUEST,
|
|
CF_OWNERDISPLAY);
|
|
return hData;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEClient::StartAdviseLoop
|
|
This function sets up a hotlink with the server on the specified item.
|
|
It returns TRUE if the link was set up successfully.
|
|
|
|
Setting up a warm link would involve changing the XTYP.
|
|
|
|
****************************************************************************/
|
|
|
|
BOOL DDEClient::StartAdviseLoop(HSZ hItem)
|
|
{
|
|
ClientTransaction(NULL, 0, hItem, XTYP_ADVSTART);
|
|
return m_bResult;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
DDEClient::ClientTransaction
|
|
an internal wrapper for ::DdeClientTransaction()
|
|
|
|
****************************************************************************/
|
|
|
|
HDDEDATA DDEClient::ClientTransaction(void FAR *lpvData, DWORD cbData,
|
|
HSZ hItem, UINT uType, UINT uFmt)
|
|
{
|
|
HDDEDATA hData = ::DdeClientTransaction(
|
|
(LPBYTE)lpvData, // data to send to server
|
|
cbData, // size of data in bytes
|
|
m_hConv, // conversation handle
|
|
hItem, // handle of item name string
|
|
uFmt, // clipboard format
|
|
uType, // XTYP_* type
|
|
m_timeout, // timeout duration in milliseconds
|
|
NULL); // transaction result, not used
|
|
|
|
m_bResult = (hData != FALSE);
|
|
|
|
return hData;
|
|
}
|