tags:

views:

48

answers:

2

Hello,

I was following the example from How to use Dynamic Data Exchange (DDE) with Word and Excel from Visual C++ and I somehow managed to able able to retrieve the value from the Excel.

Now the question is, with this example, I have to run the application over again to get the necessary update. How do I make it in such a way that if there is an update in Excel, my application will be notified? DdeAdvise?

Thanks in advance! Excel is just an example! And no, I need DDE not COM even if its old.

// DDEExample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h> 
#include "ddeml.h"

#define PAUSE system("pause")

HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv,
         HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
         ULONG_PTR dwData1, ULONG_PTR dwData2)
{
 printf("uType: %d", uType);
 switch(uType)
 {
  case XTYP_REQUEST:
   printf("XTYP_REQUEST\n");
  break;

 }
 return 0;
}

void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
    HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
    HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT, 
                                 XTYP_REQUEST,5000 , NULL);
    if (hData==NULL)
    {
        printf("Request failed: %s\n", szItem);
    }
    else
    {
        char szResult[255];
        DdeGetData(hData, (unsigned char *)szResult, 255, 0);
        printf("%s%s\n", sDesc, szResult);
    }
}


int _tmain(int argc, _TCHAR* argv[])
{
 char szApp[] = "EXCEL";
 char szTopic[] = "C:\\Test.xlsx";
 char szCmd1[] = "[APP.MINIMIZE()]";
 char szItem1[] = "R1C1";  char szDesc1[] = "A1 Contains: ";


 UINT uiResult;
 DWORD m_dwDDEInstance = 0;
 uiResult = DdeInitialize(&m_dwDDEInstance, (PFNCALLBACK) &DdeCallback, APPCLASS_STANDARD|APPCMD_CLIENTONLY, 0);
 if(uiResult != DMLERR_NO_ERROR)
 {
  printf("DDE Initialization Failed: 0x%04x\n", uiResult);
  return FALSE;
 }
 printf("m_dwDDEInstance: %u\n", m_dwDDEInstance);
 //PAUSE;
 HSZ hszApp, hszTopic;
 HCONV hConv;
 hszApp = DdeCreateStringHandle(m_dwDDEInstance, szApp, 0);
 hszTopic = DdeCreateStringHandle(m_dwDDEInstance, szTopic, 0);
 hConv = DdeConnect(m_dwDDEInstance, hszApp, hszTopic, NULL);
 DdeFreeStringHandle(m_dwDDEInstance, hszApp);
 DdeFreeStringHandle(m_dwDDEInstance, hszTopic);
 if(hConv == NULL)
 {
  printf("DDE Connection Failed.\n");
 }

 DDERequest(m_dwDDEInstance, hConv, szItem1, szDesc1);
 DdeDisconnect(hConv);
 DdeUninitialize(m_dwDDEInstance);

 PAUSE;
}
A: 

This is not much of an answer so I am sorry about that. Anyway, is there any chance you could use C# or even C++/CLI? Because if you can then you could use NDde. All of the low level plumbing is in place to do advise loops and there are examples included in the download for doing so.

Brian Gideon
A: 

From MS Platform SDK: "A client can request a hot advise loop with a server by specifying the XTYP_ADVSTART transaction type in a call to DdeClientTransaction".

//#include "stdafx.h"
#include "windows.h"
#include "ddeml.h"
#include "stdio.h"

char szApp[] = "EXCEL";
char szTopic[] = "C:\\Test.xls";
char szCmd1[] = "[APP.MINIMIZE()]";
char szItem1[] = "R1C1";  char szDesc1[] = "A1 Contains: ";
char szItem2[] = "R2C1";  char szDesc2[] = "A2 Contains: ";
char szItem3[] = "R3C1";  char szData3[] = "Data from DDE Client";

HSZ hszApp, hszTopic;
DWORD idInst=0;

HDDEDATA CALLBACK DdeCallback(
    UINT uType,     // Transaction type.
    UINT uFmt,      // Clipboard data format.
    HCONV hconv,    // Handle to the conversation.
    HSZ hsz1,       // Handle to a string.
    HSZ hsz2,       // Handle to a string.
    HDDEDATA hdata, // Handle to a global memory object.
    DWORD dwData1,  // Transaction-specific data.
    DWORD dwData2)  // Transaction-specific data.
{
    if(uType==XTYP_ADVDATA && uFmt==CF_TEXT)
    {
        HSZ hszItem1 = DdeCreateStringHandle(idInst, szItem1, 0);
        HSZ hszItem2 = DdeCreateStringHandle(idInst, szItem2, 0);
        char szResult[255];
        if((!DdeCmpStringHandles(hsz1, hszTopic)) && (!DdeCmpStringHandles(hsz2, hszItem1)))
        {
            DdeGetData(hdata, (unsigned char *)szResult, 255, 0);
            printf("%s - %s\n", szItem1,szResult);
        }
        else if((!DdeCmpStringHandles(hsz1, hszTopic)) && (!DdeCmpStringHandles(hsz2, hszItem2)))
        {
            DdeGetData(hdata, (unsigned char *)szResult, 255, 0);
            printf("%s - %s\n", szItem2,szResult);
        }
    }
    return 0;
}

void DDEExecute(DWORD idInst, HCONV hConv, char* szCommand)
{
    HDDEDATA hData = DdeCreateDataHandle(idInst, (LPBYTE)szCommand,
                               lstrlen(szCommand)+1, 0, NULL, CF_TEXT, 0);
    if (hData==NULL)   {
        printf("Command failed: %s\n", szCommand);
    }
    else    {
        DdeClientTransaction((LPBYTE)hData, 0xFFFFFFFF, hConv, 0L, 0,
                             XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
    }
}

void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
    HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
    HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
                                 XTYP_REQUEST,5000 , NULL);
    if (hData==NULL)
    {
        printf("Request failed: %s\n", szItem);
    }
    else
    {
        char szResult[255];
        DdeGetData(hData, (unsigned char *)szResult, 255, 0);
        printf("%s%s\n", sDesc, szResult);
    }
}

void DDEPoke(DWORD idInst, HCONV hConv, char* szItem, char* szData)
{
    HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
    DdeClientTransaction((LPBYTE)szData, (DWORD)(lstrlen(szData)+1),
                          hConv, hszItem, CF_TEXT,
                          XTYP_POKE, 3000, NULL);
    DdeFreeStringHandle(idInst, hszItem);
}



int main(int argc, char* argv[])
{

    char szCmd2[] = "[SELECT(\"R3C1\")][FONT.PROPERTIES(,\"Bold\")]";//[SAVE()][QUIT()]";

    //DDE Initialization
    UINT iReturn;
    iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
                            APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
    if (iReturn!=DMLERR_NO_ERROR)
    {
        printf("DDE Initialization Failed: 0x%04x\n", iReturn);
        Sleep(1500);
        return 0;
    }

    //Start DDE Server and wait for it to become idle.
    HINSTANCE hRet = ShellExecute(0, "open", szTopic, 0, 0, SW_SHOWNORMAL);
    if ((int)hRet < 33)
    {
        printf("Unable to Start DDE Server: 0x%04x\n", (UINT)hRet);
        Sleep(1500); DdeUninitialize(idInst);
        return 0;
    }
    Sleep(1000);

    //DDE Connect to Server using given AppName and topic.
    HCONV hConv;
    hszApp = DdeCreateStringHandle(idInst, szApp, 0);
    hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
    hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
    DdeFreeStringHandle(idInst, hszApp);
    DdeFreeStringHandle(idInst, hszTopic);
    if (hConv == NULL)
    {
        printf("DDE Connection Failed.\n");
        Sleep(1500); DdeUninitialize(idInst);
        return 0;
    }

    //Execute commands/requests specific to the DDE Server.
    DDEExecute(idInst, hConv, szCmd1);
    DDERequest(idInst, hConv, szItem1, szDesc1);
    DDERequest(idInst, hConv, szItem2, szDesc2);
    DDEPoke(idInst, hConv, szItem3, szData3);
    DDEExecute(idInst, hConv, szCmd2);

    HSZ hszItem = DdeCreateStringHandle(idInst, szItem1, 0);
    DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
                                 XTYP_ADVSTART,5000 , NULL);


BOOL bRet;
MSG msg;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

    //DDE Disconnect and Uninitialize.
    DdeDisconnect(hConv);
    DdeUninitialize(idInst);

    Sleep(3000);
    return 1;
}

Hope this help

steven