|
|
/***************************************************************************/ /** 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; }
|