Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

How To Write a DDEML Server for Excel and Use it with NetDDE


View products that this article applies to.

This article was previously published under Q238133

↑ Back to the top


Summary

This article walks you through building a DDE Management Library (DDEML) server application for Microsoft Excel using Visual C++, and illustrates how you can use the server remotely.

↑ Back to the top


More information

A common use of DDE (Dynamic Data Exchange) is to create an application that serves data to DDE clients such as Microsoft Excel. For instance, you might have an application that continuously gets real-time stock market quotes. Using DDE, you could expose this data from your application, and Excel users with access to it could reference it right in their calculations using DDE links.

The first part of this article walks you through building a very basic DDE server application using the DDEML. It updates a counter variable continuously, and advises any DDE clients listening as it changes:
  1. Create a new Visual C++ 6.0 project. Select "Win32 Application" as the project type, and name it "DdemlSvr." When it asks you what kind of project you want, select "An empty project."
  2. Add a new .cpp file to your project called "main.cpp."
  3. Paste the following code into main.cpp:
    #include <windows.h>
    #include <stdio.h>
    #include <ddeml.h>
    
    
    // Globals...
    HSZ g_hszAppName;
    HSZ g_hszTopicName;
    HSZ g_hszItemName;
    int g_count = 0;
    DWORD g_idInst = 0;
    
    // Declarations:
    HDDEDATA EXPENTRY DdeCallback(UINT type, UINT fmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
    
    // WinMain()..
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
       
       // Initialize DDEML...
       if(DdeInitialize(&g_idInst, DdeCallback, APPCLASS_STANDARD, 0)) {
          MessageBox(NULL, "DdeInitialize() failed", "Error", MB_SETFOREGROUND);
          return -1;
       }
       
       // Create string handles...
       g_hszAppName = DdeCreateStringHandle(g_idInst, "DdemlSvr", NULL);
       g_hszTopicName = DdeCreateStringHandle(g_idInst, "MyTopic", NULL);
       g_hszItemName = DdeCreateStringHandle(g_idInst, "MyItem", NULL);
       
       if( (g_hszAppName == 0) || (g_hszTopicName == 0) || (g_hszItemName == 0) ) {
          MessageBox(NULL, "DdeCreateStringHandle() failed", "Error", MB_SETFOREGROUND);
          return -2;
       }
       
       // Register DDE server
       if(!DdeNameService(g_idInst, g_hszAppName, NULL, DNS_REGISTER)) {
          MessageBox(NULL, "DdeNameService() failed!", "Error", MB_SETFOREGROUND);
          return -3;
       }
       
       // Create a timer to simulate changing data...
       SetTimer(0,0,1,0);
       
       // Message loop:
       MSG msg;
    
       while (GetMessage(&msg, NULL, 0, 0))  {
          // On WM_TIMER, change our counter, and update clients...
          if(msg.message == WM_TIMER) {
             g_count++;
             DdePostAdvise(g_idInst, g_hszTopicName, g_hszItemName);
          }
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
       
       return msg.wParam;
    }
    
    
    // Our DDE Callback function...
    HDDEDATA EXPENTRY DdeCallback(UINT wType, UINT fmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2) {
    
       switch (wType) {
          
       // ----------------------------------------------------------------
       case XTYP_CONNECT:
          // Client is trying to connect. Respond TRUE if we have what they want...
          if ((!DdeCmpStringHandles(hsz1, g_hszTopicName)) &&
             (!DdeCmpStringHandles(hsz2, g_hszAppName)))
             return (HDDEDATA)TRUE;   // SERVER supports Topic|Service
          else
             return FALSE;  // SERVER does not support Topic|Service
          
          // ----------------------------------------------------------------
       case XTYP_ADVSTART:
          // Client starting advisory loop.
          // Say "ok" if we have what they are asking for...   
    
          if((!DdeCmpStringHandles(hsz1, g_hszTopicName)) &&
             (!DdeCmpStringHandles(hsz2, g_hszItemName)))
             return (HDDEDATA)TRUE;   // SERVER supports Topic|Service
          else
             return FALSE;  // SERVER does not support Topic|Service
          // ----------------------------------------------------------------
                
    
       case XTYP_ADVREQ:
          
          // Client wants our data. Since this is specific to Excel, we'll
          // go ahead and assume they want XlTable-formatted data. For a
          // generic DDE server, you might want to handle various formats
          // specified by the passed in fmt parameter.
    
          if(!DdeCmpStringHandles(hsz1, g_hszTopicName) &&
             !DdeCmpStringHandles(hsz2, g_hszItemName)) {
    
             short xltableData[100];
             
             // tdtTable record...
             xltableData[0] = 0x0010; // tdtTable
             xltableData[1] = 4; // 2 short ints following
             xltableData[2] = 1; // # rows
             xltableData[3] = 1; // # cols
             
             // tdtInt record...
             xltableData[4] = 0x0006;
             xltableData[5] = 2;
             xltableData[6] = (short)g_count;
    
             return DdeCreateDataHandle(g_idInst, (UCHAR*)xltableData, 2*7, 0, g_hszItemName, fmt, 0);
          }    
          // ----------------------------------------------------------------
       default:
          return (HDDEDATA)NULL;
       }
    }
    					
  4. Compile and run the project.
The application first calls DdeInitialize() to initialize the DDEML library, passing the address of your DdeCallback function that acts in a manner similar to a window procedure. Then, it registers your application, topic, and item strings to get string handles. And finally, it registers your DDE server so clients can see it.

Once a client references you in a DDE link, your DdeCallback function will get called a few times with various parameters starting a DDE conversation. For this simple example, you just check to make sure they are asking for the right topic and name, and under the assumption the client is going to be Excel, just return your data in Excel's XlTable format.

Walk through the following steps to test your DDE server locally before continuing:
  1. Make sure your DdemlSvr.exe application is running. You can do this by examining the process list of the Windows Task Manager.
  2. Start Excel, and type the following in a cell: =DdemlSvr|MyTopic!MyItem
The cell should obtain the value of g_count from the DDE server application, and increment rapidly as it receives updates.

Now, you are ready to experiment using the server remotely using NetDDE. Follow these steps to set up the server:
  1. Start the DdemlSvr.exe application in a networked Windows NT 4.0 machine that will be your DDE Server: (Install it if it is not already running.)
  2. On that same machine, run "DdeShare" from the command-line.
  3. Choose Shares from the menu, and select DDE Shares.
  4. Click on Add a Share. Fill in the values under Application Name as follows:
    Share Name: MyShare$
    Old Style: DdemlSvr.DDE
    New Style: DdemlSvr.OLE
    Static: DdemlSvr
  5. Fill in MyTopic in the three boxes below Topic Name.
  6. Click OK, then select MyShare$, and click Trust Share.
  7. Check Initiate to Application Enable.
  8. Click OK on all the dialog boxes, and exit the DdeShare utility.
Follow these steps to set up the client and test the server:
  1. Start Excel on another Windows NT 4.0 machine on the same network; this will be your Client.
  2. Type the following in a cell, and substitute the name of your server machine on the network for SERVERNAME:='\\SERVERNAME\NDDE$'|'MyShare$'!MyItem

    You should see results similar to those you saw when you tested on the client, a number incrementing continuously.

↑ Back to the top


References

For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base:
181946� How To Create a NetDDE Client and Server in Visual Basic
128491� Creating a NetDDE Link in Excel on Windows NT
Additional information about DDE can be found in the MSDN articles entitled "Quick and Easy DDE Server" and "Client Sample: Client Use of DDEml Library."

↑ Back to the top


Keywords: KB238133, kbhowto, kbdde

↑ Back to the top

Article Info
Article ID : 238133
Revision : 8
Created on : 1/24/2007
Published on : 1/24/2007
Exists online : False
Views : 616