📄 dde_stuf.cpp
字号:
//-------------------------------------------------------------------------------------
// Destructor: ~C_DDE_Server
// This destructor frees the memory used by the DDE server and any item objects
// which it might have created.
C_DDE_Server::~C_DDE_Server (void)
{
int Timeout; // Counts "time" for thread to finish
// Tell the DDE thread that it's time to exit now and close its window
DDE_ServerTimeToStop = true;
// Delete the server/topic pair array and service name
if (phszPair != NULL) delete [] phszPair;
delete [] ServiceName;
// We should wait until the DDE thread has exited before going any further
for (Timeout = 0L; Timeout < MAX_TIMEOUT; Timeout++)
{
Sleep (20);
if (DDE_ServerThreadDone == true) break;
}
// If the wait loop timed out, the wait for the DDE thread to exit was too long
if (Timeout >= MAX_TIMEOUT)
MessageBox (NULL, "DDE server thread not exiting on time", "DDE Warning",
MB_OK | MB_ICONEXCLAMATION);
}
//-------------------------------------------------------------------------------------
// Function: Initialize
// The DDE server's constructor starts up a thread, and the thread function calls
// this function to initialize the DDEML system from within the newly started
// thread.
void C_DDE_Server::Initialize (void)
{
// Try to initialize DDE and get an instance handle
idInstance = 0L;
DdeInitialize ((LPDWORD)&idInstance, (PFNCALLBACK)DdeServerCallback,
APPCMD_FILTERINITS, 0L);
// Check for DDE errors and complain if any are found
DDE_CheckForError (idInstance);
// Create string handle for service name; call user's function to create topic
// and item string handles
hszService = DdeCreateStringHandle (idInstance, ServiceName, CP_DDESERV);
if (hszService == 0L) DDE_CheckForError (idInstance);
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Registering service \"%s\", handle %08X\n",
ServiceName, (int)hszService);
#endif
// Register the service name. This allows DDEML messages to come to this server
DdeNameService (idInstance, hszService, NULL, DNS_REGISTER);
DDE_CheckForError (idInstance);
// Register each of the topic names; the topic's registration function calls
// the registration functions of each of the items too
C_DDE_Topic* pCurTopic = (C_DDE_Topic*) GetHead ();
while (pCurTopic != NULL)
{
pCurTopic->Register (idInstance);
pCurTopic = (C_DDE_Topic*) GetNext ();
}
}
//-------------------------------------------------------------------------------------
// Function: Uninitialize
// The DDE server's destructor tells the DDE thread to call this function. This
// function then uninitializes the DDEML system.
void C_DDE_Server::Uninitialize (void)
{
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Uninitializing DDEML system\n");
#endif
if (idInstance != 0L)
DdeUninitialize (idInstance); // Shut down the DDE server if it's up
The_DDE_Server = NULL; // Un-set the callback's pointer
}
//-------------------------------------------------------------------------------------
// Function: SendAdviseData
// This function tells all the topics owned by this server to tell all the items
// which they own to update their advise-linked data. If any of the items' data
// has changed, the items will inform the client of the change of data.
bool C_DDE_Server::SendAdviseData (void)
{
// Go through the topic list, asking every topic we find to do an update
C_DDE_Topic* pTopic = (C_DDE_Topic*) GetHead ();
while (pTopic != NULL)
{
pTopic->SendAdviseData ();
pTopic = (C_DDE_Topic*) GetNext ();
}
return true;
}
//-------------------------------------------------------------------------------------
// Function: SetServiceName
// This function allows the user to specify the service name.
void C_DDE_Server::SetServiceName (const char* aName)
{
// Un-register the previously registered service name
DdeNameService (idInstance, hszService, NULL, DNS_UNREGISTER);
// Create a new string handle for the service name and register it
hszService = DdeCreateStringHandle (idInstance, aName, CP_DDESERV);
if (hszService == 0L) DDE_CheckForError (idInstance);
DdeNameService (idInstance, hszService, NULL, DNS_REGISTER);
DDE_CheckForError (idInstance);
}
//-------------------------------------------------------------------------------------
// Function: ConnectClient
// A client somewhere has requested a connection with a server, and the client
// has specified a service name and a topic name in which it's interested. If
// the service and topic names match names supported by this server, hook on up.
HDDEDATA C_DDE_Server::ConnectClient (HSZ hsz1, HSZ hsz2)
{
// If the service name matches, look for a match in each of the topic names
if (hszService == hsz2)
{
C_DDE_Topic* pCurTopic = (C_DDE_Topic*)GetHead ();
while (pCurTopic != NULL)
{
if (hsz1 == pCurTopic->GetStringHandle ()) return (HDDEDATA)TRUE;
pCurTopic = (C_DDE_Topic*)GetNext ();
}
}
// Oh well, nothing matched
return (HDDEDATA)FALSE;
}
//-------------------------------------------------------------------------------------
// Function: WildConnect
// If a client object is sniffing around trying to find all the service and/or
// topic names supported by applications running on the system, the DDEML
// callback will call this function. It returns an array of service name/topic
// name pairs which are supported by this server and match any given names.
HDDEDATA C_DDE_Server::WildConnect (HSZ hsz1, HSZ hsz2)
{
// If the client's looking for this service name or any service name, fill the
// array of pairs of service and topic names and add a NULL/NULL pair at the end
if ((hsz2 == hszService) || (hsz2 == NULL))
{
int nTopic = 0; // Index for array of service/topic pairs
// Create or re-create array of handle pairs to hold service and topic names
if (phszPair != NULL) delete [] phszPair;
phszPair = new HSZPAIR[NumTopics + 1];
for (C_DDE_Topic* pCurTopic = (C_DDE_Topic*)GetHead (); pCurTopic != NULL;
pCurTopic = (C_DDE_Topic*)GetNext ())
{
// Only create a pair of names for the list if the topic name matches
if ((hsz1 == NULL) || (hsz1 == pCurTopic->GetStringHandle ()))
{
phszPair[nTopic].hszSvc = hszService;
phszPair[nTopic].hszTopic = pCurTopic->GetStringHandle ();
nTopic++;
}
}
// Add a pair of NULL service and topic names to mark the end of the list
phszPair[nTopic].hszSvc = (HSZ)NULL;
phszPair[nTopic].hszTopic = (HSZ)NULL;
return (HDDEDATA)DdeCreateDataHandle (idInstance, (LPBYTE)phszPair,
(NumTopics + 1) * sizeof (HSZPAIR), 0L, 0, CF_TEXT, 0);
}
// If the service name is wrong, don't send back any information about topics
return (HDDEDATA)FALSE;
}
//-------------------------------------------------------------------------------------
// Function: RequestData
// This function responds to a client application which has sent an XTYP_REQUEST
// message through DDE to the server. It looks for a data item whose topic and
// item names match those given. If it finds one, it formats the data in text
// clipboard format and returns a handle to it. If no topic and data names match
// then this function returns the not-processed code.
HDDEDATA C_DDE_Server::RequestData (WORD wFormat, HSZ hsz1, HSZ hsz2)
{
static char DataString[256]; // Place to store string sent to DDEML
// This server only supports the CF_TEXT format
if (wFormat != CF_TEXT) return (HDDEDATA)DDE_FNOTPROCESSED;
// Look for a topic whose name is the same as that the client's looking for
C_DDE_Topic* TheTopic;
if ((TheTopic = GetTopicWithHandle (hsz1)) != NULL)
{
// Look for an item belonging to that topic with the correct item name
C_DDE_Item* TheItem;
if ((TheItem = TheTopic->GetItemWithHandle (hsz2)) != NULL)
{
// We found the right item - convert its data to a string and send it
strcpy (DataString, TheItem->DataToString ());
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Sending data \"%s\"\n", DataString);
#endif
return (HDDEDATA)DdeCreateDataHandle (idInstance, (LPBYTE)DataString,
strlen (DataString) + 1, 0L, hsz2, CF_TEXT, 0);
}
}
// If the names don't match, return the code for "I can't do it"
return (HDDEDATA)DDE_FNOTPROCESSED;
}
//-------------------------------------------------------------------------------------
// Function: PokeData
// This function responds to a client application which has sent an XTYP_POKE
// message through DDE to the server. It looks for a data item whose topic and
// item names match those given. If it finds one, it gets the data which was
// sent, saves that data in the local data item, and returns an acknowledgement.
// If the topic and data names don't match, then this function returns the
// not-processed code and doesn't mess with the local copy of the data.
HDDEDATA C_DDE_Server::PokeData (WORD wFormat, HSZ hsz1, HSZ hsz2, HDDEDATA hData)
{
static char DataBuffer[256]; // Place to keep text strings with data
// This server only supports the CF_TEXT format
if (wFormat != CF_TEXT) return (HDDEDATA)DDE_FNOTPROCESSED;
// Look for a topic whose name is the same as that the client's looking for
C_DDE_Topic* TheTopic;
if ((TheTopic = GetTopicWithHandle (hsz1)) != NULL)
{
// Look for an item belonging to that topic with the correct item name
C_DDE_Item* TheItem;
if ((TheItem = TheTopic->GetItemWithHandle (hsz2)) != NULL)
{
// We found the right item; read the data which it gave us and save it
DdeGetData (hData, (LPBYTE)DataBuffer, 254L, 0L);
TheItem->StringToData (DataBuffer);
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Receiving poked data \"%s\"\n", DataBuffer);
#endif
return (HDDEDATA)DDE_FACK;
}
}
// If the names don't match, return the code for "I can't do it"
return (HDDEDATA)DDE_FNOTPROCESSED;
}
//-------------------------------------------------------------------------------------
// Function: AdviseStart
// This function responds to a client's XTYP_ADVSTART message. It looks for an
// item with the correct item and topic names which can be linked to the client
// and if it finds one, it sends back a message to indicate the link is working.
HDDEDATA C_DDE_Server::AdviseStart (WORD wFormat, HSZ hsz1, HSZ hsz2)
{
// This server only supports the CF_TEXT format
if (wFormat != CF_TEXT) return (HDDEDATA)FALSE;
// Look for a topic whose name is the same as that the client's looking for
C_DDE_Topic* TheTopic;
if ((TheTopic = GetTopicWithHandle (hsz1)) != NULL)
{
// Look for an item belonging to that topic with the correct item name
C_DDE_Item* TheItem;
if ((TheItem = TheTopic->GetItemWithHandle (hsz2)) != NULL)
{
// We found the right item; tell the client we can support it unless it
// has already been advise-linked
if (TheItem->IsAdviseLinked () == false)
{
TheItem->AdviseLink ();
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Setting up advise link on item \"%s\"\n",
TheItem->GetName ());
#endif
return (HDDEDATA)TRUE;
}
}
}
// If we get here, the item the client wants isn't supported
#ifdef MT_DEBUG_MODE
TakeDebugNote ("Cannot do advise link on item %08X\n", hsz2);
#endif
return (HDDEDATA)FALSE;
}
//-------------------------------------------------------------------------------------
// Function: AdviseRequest
// This function responds to a client's XTYP_ADVREQ message. The client is
// asking for some data; if the request is acceptable (format, topic and item)
// then send the data to the client. If not, send it a virtual raspberry.
HDDEDATA C_DDE_Server::AdviseRequest (WORD wFormat, HSZ hsz1, HSZ hsz2)
{
static char DataString[256]; // Place to store string sent to DDEML
// This server only supports the CF_TEXT format
if (wFormat != CF_TEXT) return (HDDEDATA)FALSE;
// Look for a topic whose name is the same as that the client's looking for
C_DDE_Topic* TheTopic;
if ((TheTopic = GetTopicWithHandle (hsz1)) != NULL)
{
// Look for an item belonging to that topic with the correct item name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -