//==============================================================================================
//
// DDEapi.cpp
//
// This software was developed by U.S. Government employees as part of
// their official duties and is not subject to copyright. No warranty implied
// or intended.Any questions or comments mailto:John.Michaloski@nist.gov
/*
It uses the DDE execute facility for dealing with Word. Each call to
an API here causes a DDE conversation to be set up, the execute
request made and the conversation terminated.
Example:
SendExecCmd("WinWord", "[FileOpen(\"c:\\michaloski\\worddoc.doc\")][FilePrint 0][DocClose 2]");
DE is a means for one application (the client) to communicate with another (the server) via messages. The client can send commands and data to the server which will run the commands and process the data. This exchange of messages is called a conversation.
Conversations are about a topic. Think of a topic as the fundamental data grouping used in an application. A workbook in Excel or a form in VB for instance. Topics can be about a specific item, say a particular Excel spreadsheet cell.
Lets look at an example of sending data to a cell in Excel. With this app and Excel running, the first step is to register this application with the DDEML. This is accomplished with a call to the DdeInitialize API when you click the Initialize button. Conversly, the DdeUninitialize function is used to free all DDEML resources when our conversation is complete.
Next we need to describe our conversation. The service or process that we will converse with is "Excel" and the topic is the "book1" workbook. For the item we can specify a cell such as "R1C1" and we can use a value of "test".
After these values are entered into the corresponding textboxes the Poke button can be pressed. This uses the DdeCreateStringHandle function to convert our conversation parameters into memory handles. A call to DdeConnect establishes a conversation with a server application that supports the specified service name and topic and returns a handle to the conversation.
Once a conversation is established, the DdeClientTransaction API transfers the actual data to the server (Excel) application. DdeClientTransaction call uses a Poke transaction type which means "send unsolicited data" to the server application.
The Execute and Request buttons perfom similar functions but use "Execute" and "Request" type transactions. Execute is used to send a command string to the server while Request asks the server for data.
*/
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <atltime.h>
#include <time.h>
#include "DDEapi.h"
#include "StdStringFcn.h"
/****************************************************************************
* Callback function for DDE messages.
* @parameter wType
* @parameter wFmt
* @parameter hConv
* @parameter hsz1
* @parameter hsz2
* @parameter hDDEData
* @parameter dwData1
* @parameter dwData2
* @return HDDEDATA handle to the DDE data
*****************************************************************************/
HDDEDATA CALLBACK DDEAdapter::DDEMyCallback(UINT wType,
UINT wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hDDEData,
DWORD dwData1,
DWORD dwData2)
{
std::cerr << StdStringFormat( "Got DDE Callback %x\n", wType);
HDDEDATA ret=(HDDEDATA)true;
switch (wType)
{
case XTYP_CONNECT:
ret = (HDDEDATA)true;
break;
case XTYP_REQUEST:
// We use the DdeCmpStringHandles instead of the strcmp for two reasons: 1st we already have the strings in HSZ
// format, 2nd this way it's case insensitive as the DDE protocol is supposed to be.
std::cerr<< StdStringFormat("XTYP_REQUEST\n");
//if (DdeCmpStringHandles(hszTopic, ddeAdapter.DDETopicEvaluate) == 0)
break;
case XTYP_ERROR:
std::cerr<< StdStringFormat("Error=%x\n", XTYP_ERROR);
break;
case XTYP_ADVDATA :
{
//std::cerr << StdStringFormat("XTYP_ADVDATA callback %s=%s\n", szItem,szResult );
}
break;
case XTYP_ADVREQ :
std::cerr<< StdStringFormat("XTYP_ADVREQ\n");
break;
case XTYP_ADVSTART :
std::cerr<< StdStringFormat("XTYP_ADVSTART\n");
break;
case XTYP_ADVSTOP :
std::cerr<< StdStringFormat("XTYP_ADVSTOP\n");
break;
case XTYP_EXECUTE :
std::cerr<< StdStringFormat("XTYP_ADVDATA\n");
break;
case XTYP_CONNECT_CONFIRM :
std::cerr<< StdStringFormat("XTYP_CONNECT_CONFIRM\n");
break;
case XTYP_XACT_COMPLETE :
std::cerr<< StdStringFormat("XTYP_XACT_COMPLETE\n");
break;
case XTYP_REGISTER :
std::cerr<< StdStringFormat("XTYP_REGISTER\n");
break;
case XTYP_DISCONNECT :
std::cerr<< StdStringFormat("XTYP_DISCONNECT\n");
break;
case XTYP_UNREGISTER :
std::cerr<< StdStringFormat("XTYP_UNREGISTER\n");
break;
case XTYP_WILDCONNECT :
std::cerr<< StdStringFormat("XTYP_WILDCONNECT\n");
break;
case XTYP_POKE:
// ret = DDE_FACK; // Ritorna FACK se il messaggio ?stato processato
ret = DDE_FNOTPROCESSED;
break;
}
return ret;
}
//HDDEDATA CALLBACK DDEAdapter::DDECallback(UINT uType, UINT uFmt, HCONV hconv, HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, DWORD dwData1, DWORD dwData2)
//{
// HDDEDATA ret = 0;
// OutputDebugString("Got DDE Callback\n");
// std::cerr << "Got DDE Callback\n";
//
// switch (uType)
// {
// //
// // Accetta connessioni DDE
// //
// case XTYP_CONNECT:
// ret = (HDDEDATA)true;
// break;
// case XTYP_REQUEST:
// // We use the DdeCmpStringHandles instead of the strcmp for two reasons: 1st we already have the strings in HSZ
// // format, 2nd this way it's case insensitive as the DDE protocol is supposed to be.
// if (DdeCmpStringHandles(hszTopic, ddeAdapter.DDETopicEvaluate) == 0)
// {
// ret = DdeCreateDataHandle(ddeAdapter.dwDDEInst, (BYTE*)&ddeAdapter.Message[0], strlen(ddeAdapter.Message)+1, 0, hszItem, CF_TEXT, 0);
// // if (ret == 0)
// // ret = DdeCreateDataHandle(idInst, (BYTE*)"\1Unknown Error...", 18, 0, hszItem, CF_TEXT, 0);
// }
// break;
// case XTYP_ERROR:
// std::cerr<< StdStringFormat("Error=%s\n", hszTopic);
// break;
// case XTYP_ADVDATA :
// {
// if(uFmt==CF_TEXT)
// {
// char szResult[255];
// char szItem[255];
//
// DdeGetData(hdata, (unsigned char *)szResult, 255, 0);
// DdeQueryString(ddeAdapter.dwDDEInst,hszItem,szItem,256,CP_WINANSI );
// ddeAdapter.values[szItem]=szResult;
// std::cerr <<StdStringFormat("XTYP_ADVDATA callback %s=%s\n", szItem,szResult );
// }
// }
// break;
// case XTYP_ADVREQ :
// std::cerr<< StdStringFormat("XTYP_ADVREQ\n");
// break;
// case XTYP_ADVSTART :
// std::cerr<< StdStringFormat("XTYP_ADVSTART\n");
// break;
// case XTYP_ADVSTOP :
// std::cerr<< StdStringFormat("XTYP_ADVSTOP\n");
// break;
// case XTYP_EXECUTE :
// std::cerr<< StdStringFormat("XTYP_ADVDATA\n");
// break;
// case XTYP_CONNECT_CONFIRM :
// std::cerr<< StdStringFormat("XTYP_CONNECT_CONFIRM\n");
// break;
// case XTYP_XACT_COMPLETE :
// std::cerr<< StdStringFormat("XTYP_XACT_COMPLETE\n");
// break;
// case XTYP_REGISTER :
// std::cerr<< StdStringFormat("XTYP_REGISTER\n");
// break;
// case XTYP_DISCONNECT :
// std::cerr<< StdStringFormat("XTYP_DISCONNECT\n");
// break;
// case XTYP_UNREGISTER :
// std::cerr<< StdStringFormat("XTYP_UNREGISTER\n");
// break;
// case XTYP_WILDCONNECT :
// std::cerr<< StdStringFormat("XTYP_WILDCONNECT\n");
//