root/applications/robust/DDEClient.cpp @ 1423

Revision 1423, 29.3 kB (checked in by sindj, 12 years ago)

Nevim jake zmeny. JS

Line 
1// This file defines a DLL, which exports procedures for DDE client connections
2// to server applications.
3// The base of the procedures are several articles from Mircosoft about DDE and
4// different examples of code found via internet search. The code examples did
5// not work in Visual Studio .NET 2003 and had to be revised substantially.
6//
7// Author:  Robert Matovinovic
8// Version: 0.03
9// Date:    14.10.2006
10//
11// 0.01
12// DLL supports only a single connection. For multiple connections the variables
13// must be localized to procedures. Synchronous and asynchronous transactions are
14// possible. To access data of asynchronous transactions call
15// DCAsynchTransactionCompleted
16//
17// 0.02
18// multiple connections realized by use of individual conversation handle and
19// separated variables
20//
21// 0.03
22// bug fixed which caused an infinite loop in DCAsynchTransactionCompleted
23
24// DDEClient.cpp : Entry point for DLL application.
25//
26
27#pragma once
28
29#define WIN32_LEAN_AND_MEAN             // don't bind to seldom used parts of Windows-Header
30#include <windows.h>
31#include <ddeml.h>
32//#include <atlstr.h>           // only for string handling of error messages
33#include "DCErrors.h"   // Error messages for dll
34
35//
36// global data
37//
38char szVersion[]="DDEClient.dll, version 0.03, copyright Robert Matovinovic, robert.matovinovic@web.de";
39// variable of DDE instance
40DWORD dwDDEInst = 0;
41// data handle for execute transaction
42HDDEDATA hExecData;
43// string for messages
44CString csMsg; 
45// Flag for successful return of callback function
46bool bCbSuccess = true;
47
48// DDEClientTransaction data, variables for transactions via DDEML
49typedef struct {
50        // Pointer to the beginning of the data the client must pass to the server.
51        // can also be a data handle, for execute and poke.
52        LPBYTE pData; 
53        // Specifies the length, in bytes, of the data pointed to by the pData parameter
54        DWORD cbData;           
55        // Handle to the conversation in which the transaction is to take place.
56        HCONV hConv;             
57        // Handle to the data item for which data is being
58        // exchanged during the transaction.
59        HSZ hszItem;           
60        // Specifies the standard clipboard format
61        // in which the data item is being submitted or requested.
62        UINT wFmt; 
63        // Specifies the transaction type.
64        UINT wType;
65        // Specifies the maximum length of time, in milliseconds, that the client will
66        // wait for a response from the server application in a synchronous transaction.
67        // This parameter should be TIMEOUT_ASYNC for asynchronous transactions.
68        DWORD dwTimeout;
69        // Pointer to a variable that receives the result of the transaction.
70        //LPDWORD pdwResult;
71        // Variable that receives the result of the transaction.
72        DWORD dwResult;
73        // Data handle for transactions
74        HDDEDATA hData;
75} DDEVARS;
76
77// DDE data structure for access data received by DDE transaction
78typedef struct {
79        // pointer to begin of dde data returned by DdeAccessData
80        BYTE* pData;
81        // length of dde data returned by DdeAccessData
82        DWORD dwLen;
83        // string pointer to dde data, if the data should accessed as string
84        char* pszData;
85        // ID of transaction, used to determine completion of asynchronous transaction
86        DWORD dwTransID;
87        // ID of transaction, returned by callback function with asynch. transaction
88        DWORD dwCbTransID;
89        // string for access type of data
90        char szAccType[6];
91} DCDATAACCESS;
92
93// maximal number of dde conversations
94const WORD wCONVMAX = 20;
95// pointer array to dde conversation variables
96DDEVARS* DdeV[wCONVMAX];
97// pointer array to dde data access variables
98DCDATAACCESS* DDA[wCONVMAX];
99
100#define DllExport extern "C" _declspec( dllexport )
101
102//
103// exported variables
104//
105// boolean used by DCLastError for appearance of error messages.
106// false: Messages are shown in a system message box.
107// true: Messages are passed to the calling program.
108DllExport bool bDCErrorExport = false;
109// pointer to an pointer array to dde data access variables
110DllExport DCDATAACCESS* *DCDA = DDA;
111
112
113//
114// exported functions
115//
116DllExport bool DCRequestString  (WORD wC,
117                                                                 char szItem[], 
118                                                                 DWORD dwTimeout);
119
120DllExport bool DCRequest(WORD wC,
121                                                 char szItem[], 
122                                                 char szFormat[], 
123                                                 DWORD dwTimeout );
124DllExport bool DCTransaction    (WORD wC,
125                                                                 char szType[], 
126                                                                 char szItem[], 
127                                                                 char szData[], 
128                                                                 char szFormat[], 
129                                                                 DWORD dwTimeout,
130                                                                 char szAccess[]);
131DllExport bool DCInit();
132DllExport bool DCConnect(WORD* pConvNo, char* szService, char* szTopic);
133DllExport bool DCDisconnect(WORD wC);
134DllExport bool DCUninit();
135DllExport bool DCFreeDdeMem(WORD wC);
136DllExport char* DCLastError();
137DllExport void DCFinalize();
138DllExport bool DCAsynchTransactionCompleted(WORD wC, DWORD dwTransID, bool bWait);
139DllExport bool DCAbandonTransaction(WORD wC, DWORD dwTransID);
140DllExport char* DCVersion();
141
142
143
144//
145// forward declarations
146//
147bool DdeDataHandling(WORD wC, HDDEDATA hData, char szAccess[]);
148void FreeData(WORD wC);
149bool InitDdeVars(HCONV hConv);
150bool InitDCDataAccess(WORD wC);
151WORD FindConvNo(HCONV hConv);
152bool GetConvNo(WORD* pConvNo);
153void FreeDdeV(WORD wC);
154void FreeDDA(WORD wC);
155
156//
157// Entry point for application
158//
159BOOL APIENTRY DllMain( HANDLE hModule, 
160                       DWORD  ul_reason_for_call, 
161                       LPVOID lpReserved
162                                         )
163{
164    //hMod = hModule;        // save our module handle
165        //InitDdeVars(0L);
166        //InitDCDataAccess();
167
168    return true;
169}
170
171//
172// local functions
173//
174
175void FAR PASCAL WEP(WORD wGarbage)
176{
177    //
178    // Do absolutely nothing at all here, since   
179    // that's all that is safe to do.
180    //
181}
182
183// procedure which retrives the last DDE error and adds it to a CString
184UINT DCGetLastError(DWORD dwDdeInst, CString csMsgHead)
185{
186        UINT ui;
187
188        csMsg=csMsgHead;
189
190        ui = DdeGetLastError(dwDdeInst);
191
192    if (ui != DMLERR_NO_ERROR) 
193        {
194                switch (ui)
195                {
196                case DMLERR_ADVACKTIMEOUT: 
197                        csMsg = csMsg + (CString)ccDMLERR01;
198                        break; 
199                case DMLERR_BUSY: 
200                        csMsg = csMsg + (CString)ccDMLERR02;
201                        break; 
202                case DMLERR_DATAACKTIMEOUT: 
203                        csMsg = csMsg + (CString)ccDMLERR03;
204                        break; 
205                case DMLERR_DLL_NOT_INITIALIZED: 
206                        csMsg = csMsg + (CString)ccDMLERR04;
207                        break; 
208                case DMLERR_DLL_USAGE: 
209                        csMsg = csMsg + (CString)ccDMLERR05;
210                        break; 
211                case DMLERR_EXECACKTIMEOUT: 
212                        csMsg = csMsg + (CString)ccDMLERR06;
213                        break; 
214                case DMLERR_INVALIDPARAMETER: 
215                        csMsg = csMsg + (CString)ccDMLERR07;
216                        break;
217                case DMLERR_LOW_MEMORY: 
218                        csMsg = csMsg + (CString)ccDMLERR08;
219                        break; 
220                case DMLERR_MEMORY_ERROR: 
221                        csMsg = csMsg + (CString)ccDMLERR09;
222                        break; 
223                case DMLERR_NO_CONV_ESTABLISHED: 
224                        csMsg = csMsg + (CString)ccDMLERR10;
225                        break; 
226                case DMLERR_NOTPROCESSED: 
227                        csMsg = csMsg + (CString)ccDMLERR11;
228                        break; 
229                case DMLERR_POKEACKTIMEOUT: 
230                        csMsg = csMsg + (CString)ccDMLERR12;
231                        break; 
232                case DMLERR_POSTMSG_FAILED: 
233                        csMsg = csMsg + (CString)ccDMLERR13;
234                        break; 
235                case DMLERR_REENTRANCY: 
236                        csMsg = csMsg + (CString)ccDMLERR14;
237                        break;
238                case DMLERR_SERVER_DIED: 
239                        csMsg = csMsg + (CString)ccDMLERR15;
240                        break;
241                case DMLERR_SYS_ERROR: 
242                        csMsg = csMsg + (CString)ccDMLERR16;
243                        break; 
244                case DMLERR_UNADVACKTIMEOUT: 
245                        csMsg = csMsg + (CString)ccDMLERR17;
246                        break; 
247                case DMLERR_UNFOUND_QUEUE_ID: 
248                        csMsg = csMsg + (CString)ccDMLERR18;
249                        break; 
250                }
251    }
252        return ui;
253}
254//
255// Callback function for DDE messages
256//
257
258HDDEDATA CALLBACK DdeCallback(UINT wType, 
259                              UINT wFmt, 
260                              HCONV hConv,
261                              HSZ hsz1, 
262                              HSZ hsz2, 
263                              HDDEDATA hDDEData, 
264                              DWORD dwData1, 
265                              DWORD dwData2)
266{
267        bool bErrorExport;
268        WORD wC;
269       
270        bCbSuccess = true;
271        wC = FindConvNo(hConv);
272
273        switch ( wType )
274        {
275        case XTYP_XACT_COMPLETE:
276                // store transaction ID
277                DDA[wC]->dwCbTransID = dwData1;
278
279                // Return doing nothing, if the transaction IDs are not equal
280                if ( dwData1 != DdeV[wC]->dwResult ) 
281                {
282                        csMsg = ccMsgCbWrongID;
283                        bCbSuccess = false;
284                        return 0;
285                }
286               
287                // Check for successful transaction
288                if ( !hDDEData )
289                {
290                        csMsg = ccMsgCbTransactionFailed;
291                        bCbSuccess = false;
292                }
293                // access DDE data for request transactions
294                else if ( DdeV[wC]->wType == XTYP_REQUEST )
295                {
296                        if(!DdeDataHandling(wC, hDDEData, DDA[wC]->szAccType))
297                        {
298                                FreeData(wC);
299                                csMsg = ccMsgCbAsynchRequestFailed;
300                                bCbSuccess = false;
301                        }
302                }
303                else bCbSuccess = true;
304
305                // do nothing for execute and poke transactions
306
307                DdeV[wC]->dwResult = 0;
308
309                //char szTemp[100];
310                //sprintf(szTemp,"bCbSuccess = %i  CbTransID = %i", bCbSuccess,DDA[wC]->dwCbTransID);
311                //MessageBox((HWND)GetActiveWindow(), szTemp, ccMsgCaptionCb, MB_OK);
312               
313                return 0;
314        case XTYP_DISCONNECT:
315                DdeV[wC]->dwResult = 0;
316                MessageBox((HWND)GetActiveWindow(), ccMsgAppTerminatedConv, ccMsgCaptionCb, MB_OK | MB_ICONERROR);
317                return 0;
318        case XTYP_ERROR:
319                // only valid for one error (low memory)
320                // bDCErrorExport has to be set to false, otherwise the error is not shown.
321                // After that its previous state is restored
322                bErrorExport = bDCErrorExport;
323                bDCErrorExport = false;
324                DCGetLastError(dwDDEInst, csMsg);
325                bDCErrorExport = bErrorExport;
326                return 0;
327        default:
328                return 0;
329        }
330}
331
332//
333// Extract constant for format of DDE command
334//
335UINT DDEFormat(char* szFormat)
336{
337        // Null-terminated, plain ANSI text in a global memory block.
338        if (0 == strnicmp (szFormat,"CF_TEXT",7)) 
339                return CF_TEXT;
340        // A bitmap compatible with Windows 2.x.
341        if (0 == strnicmp (szFormat,"CF_BITMAP",7)) 
342                return CF_BITMAP;
343        // A Windows metafile with some additional information about how the
344        // metafile should be displayed.
345        if (0 == strnicmp (szFormat,"CF_METAFILEPICT",7)) 
346                return CF_METAFILEPICT;
347        // An ASCII text format used by some older Microsoft products.
348        if (0 == strnicmp (szFormat,"CF_SYLK",7)) 
349                return CF_SYLK;
350        // Software Art's data interchange format (DIF). Also an ASCII text format.
351        if (0 == strnicmp (szFormat,"CF_DIF",7)) 
352                return CF_DIF;
353        // Tag image file format (TIFF) data in a global memory block.
354        if (0 == strnicmp (szFormat,"CF_TIFF",7)) 
355                return CF_TIFF;
356        // Similar to CF_TEXT but using the OEM character set.
357        if (0 == strnicmp (szFormat,"CF_OEMTEXT",7)) 
358                return CF_OEMTEXT;
359        // A global memory block containing a Windows device-independent bitmap (DIB)
360        // as a BITMAPINFO structure followed by the bitmap bits.
361        if (0 == strnicmp (szFormat,"CF_DIB",7)) 
362                return CF_DIB;
363        // A color-palette handle. (Used in conjunction with CF_DIB.)
364        if (0 == strnicmp (szFormat,"CF_PALETTE",7)) 
365                return CF_PALETTE;
366        // Data is for the pen extensions to Windows.
367        if (0 == strnicmp (szFormat,"CF_PENDATA",7)) 
368                return CF_PENDATA;
369        // Resource interchange file format (RIFF) data as a global memory block.
370        if (0 == strnicmp (szFormat,"CF_RIFF",7)) 
371                return CF_RIFF;
372        // A specific case of RIFF in which the contained data is a waveform (sampled sound).
373        if (0 == strnicmp (szFormat,"CF_WAVE",7)) 
374                return CF_WAVE;
375
376        return 0;
377}
378//
379// Extract constant or time for timeout of DDE command
380//
381DWORD DDETimeout(DWORD* pdwTimeout)
382{
383        if (*pdwTimeout > 0) 
384        {
385                return *pdwTimeout;
386        }
387        return TIMEOUT_ASYNC;
388}
389//
390// Set Parameters for DDEClientTransaction considering the type of command
391//
392void SetDDEParams(WORD wC, char* szType, char* szItem, 
393                                  char* szData, char* szFormat, DWORD* pdwTimeout)
394{
395        UINT wCmdLen = lstrlen(szItem)+1;
396
397        if (0 == strnicmp (szType,"execute",7)) 
398        {
399                DdeV[wC]->wType = XTYP_EXECUTE;
400                DdeV[wC]->wFmt = 0;
401                // Create a data handle for the exec string
402                hExecData = DdeCreateDataHandle(dwDDEInst,
403                                                                                (LPBYTE)szItem,
404                                                                                wCmdLen,
405                                                                                0,
406                                                                                NULL,
407                                                                                DdeV[wC]->wFmt,
408                                                                                0);
409                DdeV[wC]->pData = (LPBYTE)hExecData;
410                DdeV[wC]->cbData = -1;
411                DdeV[wC]->hszItem = NULL;
412                DdeV[wC]->dwTimeout = DDETimeout(pdwTimeout);
413                //DdeV[wC]->pdwResult = NULL;
414                DdeV[wC]->dwResult = 0;
415                return;
416        }
417        if (0 == strnicmp (szType,"poke",4)) 
418        {
419                DdeV[wC]->wType = XTYP_POKE;
420                DdeV[wC]->wFmt = DDEFormat(szFormat);
421                DdeV[wC]->pData = (LPBYTE)szData;
422                DdeV[wC]->cbData = lstrlen(szData)+1;
423                DdeV[wC]->hszItem = DdeCreateStringHandle(dwDDEInst, szItem, CP_WINANSI );
424                DdeV[wC]->dwTimeout = DDETimeout(pdwTimeout);
425                //DdeV[wC]->pdwResult = NULL;
426                DdeV[wC]->dwResult = 0;
427                return;
428        }
429        if (0 == strnicmp (szType,"request",7)) 
430        {
431                DdeV[wC]->wType = XTYP_REQUEST;
432                DdeV[wC]->pData = NULL;
433                DdeV[wC]->cbData = 0;
434                DdeV[wC]->hszItem = DdeCreateStringHandle(dwDDEInst, szItem, CP_WINANSI );
435                DdeV[wC]->wFmt = DDEFormat(szFormat);
436                DdeV[wC]->dwTimeout = DDETimeout(pdwTimeout);
437                DdeV[wC]->dwResult = 0;
438                return ;
439        }
440        /*
441        if (0 == strnicmp (szType,"advise_start",12))
442        {
443                return XTYP_ADVSTART;
444        }
445        if (0 == strnicmp (szType,"advise_stop",11))
446        {
447                return XTYP_ADVSTOP;
448        }
449        */
450}
451
452// procedure retriving DDE Data as string.
453bool DdeDataString(WORD wC, HDDEDATA hData)
454{
455        if (!hData) return false;
456        else
457        {
458                // get the data as string               
459                char* pszDdeData = (char *) DdeAccessData(hData, &DDA[wC]->dwLen);
460                if(pszDdeData)
461                {
462                        // store data in a new array, otherwise it is lost with
463                        // asynchronous transactions
464                        DDA[wC]->pszData = (char *)malloc(DDA[wC]->dwLen);
465                        char* pszData = DDA[wC]->pszData;
466                        for (DWORD i = 0; i < DDA[wC]->dwLen; i++) 
467                                pszData[i] = *pszDdeData++; 
468                        DdeUnaccessData( hData );
469                        return true;
470                }
471                else
472                        return false;
473        }
474}
475
476// short form of DCTransaction for string request transaction
477bool DCRequestString(WORD wC, char szItem[], DWORD dwTimeout)
478{
479        csMsg = "";
480        DdeV[wC]->wType = XTYP_REQUEST;
481        DdeV[wC]->dwTimeout = DDETimeout(&dwTimeout);
482
483    // Send the request
484        DdeV[wC]->hData = DdeClientTransaction(NULL, 0, DdeV[wC]->hConv, 
485                                                DdeCreateStringHandle(dwDDEInst, szItem, CP_WINANSI ), 
486                                                CF_TEXT, 
487                                                DdeV[wC]->wType, 
488                                                DdeV[wC]->dwTimeout, 
489                                                &(DdeV[wC]->dwResult));
490
491        // store transaction ID
492        DDA[wC]->dwTransID = DdeV[wC]->dwResult;
493        // Check for DDE data
494        if (DdeV[wC]->hData==NULL)
495        {
496                csMsg = (CString)ccMsgRequestFailed + szItem;
497                return 0;
498        }
499        else
500        {
501                if (DdeV[wC]->dwTimeout != TIMEOUT_ASYNC)
502                {
503                        // data access for synchronous transactions
504                        if(!DdeDataString(wC,DdeV[wC]->hData))
505                        {
506                                FreeData(wC);
507                                csMsg = (CString)ccMsgRequestFailed + szItem;
508                                return false;
509                        }
510                        else return true;
511                }
512                else
513                {
514                        strncpy(DDA[wC]->szAccType,"string",sizeof(DDA[wC]->szAccType));
515                }
516        }
517        return true;
518}
519
520// procedure retrieving DDE data as byte array
521bool DdeDataBytes(WORD wC, HDDEDATA hData)
522{
523        // Check for DDE data
524        if (hData==NULL)
525                {
526                        DDA[wC]->pData = NULL;
527                        DDA[wC]->dwLen = NULL;
528                        return false;
529                }
530                else
531                {
532                        // Get data             
533                        BYTE* pDdeData = DdeAccessData(hData, &DDA[wC]->dwLen);
534                        if(pDdeData)
535                        {
536                                // store data in a new array, otherwise it is lost with
537                                // asynchronous transactions
538                                DDA[wC]->pData = (BYTE *)malloc(DDA[wC]->dwLen);
539                                BYTE* pData = DDA[wC]->pData;
540                                for (DWORD i = 0; i < DDA[wC]->dwLen; i++) 
541                                        pData[i] = *pDdeData++; 
542                                DdeUnaccessData( hData );
543                                return true;
544                        }
545                        else
546                                return false;
547                }       
548}
549
550
551// procedure for DDE request giving back a pointer to the data
552bool DCRequest(WORD wC, char szItem[], char szFormat[], DWORD dwTimeout )
553{
554        csMsg = "";
555        // Set parameters for a single DDE conversation
556        SetDDEParams(wC, "request", szItem, NULL, szFormat, &dwTimeout);
557
558    // Send the request
559        DdeV[wC]->hData = DdeClientTransaction(DdeV[wC]->pData, 
560                                                                                        DdeV[wC]->cbData, 
561                                                                                        DdeV[wC]->hConv, 
562                                                                                        DdeV[wC]->hszItem, 
563                                                                                        DdeV[wC]->wFmt, 
564                                                                                        DdeV[wC]->wType, 
565                                                                                        DdeV[wC]->dwTimeout, 
566                                                                                        &(DdeV[wC]->dwResult));
567
568        // store transaction ID
569        DDA[wC]->dwTransID = DdeV[wC]->dwResult;
570
571        if (DdeV[wC]->dwTimeout != TIMEOUT_ASYNC)
572        {
573                // data access for synchronous transaction
574                if(!DdeDataBytes(wC, DdeV[wC]->hData))
575                {
576                        FreeData(wC);
577                        csMsg = (CString)ccMsgRequestFailed + szItem;
578                        return false;
579                }
580                else return true;
581        }
582        else
583        {
584                strncpy(DDA[wC]->szAccType,"byte",sizeof(DDA[wC]->szAccType));
585        }
586        return true;
587}
588
589// Initialize data structure for dde variables
590bool InitDdeVars(HCONV hConv, WORD wC)
591{
592        // assign memory for conversation variables
593        DdeV[wC] = (DDEVARS *)malloc(sizeof(DDEVARS));
594
595        if (DdeV[wC] == NULL)
596        {
597                csMsg = (CString)ccMsgNotEnoughMemory01;
598                return false;
599        }
600        memset(DdeV[wC], 0, sizeof(DdeV[wC]));
601        DdeV[wC]->hConv = hConv;
602        return true;
603}
604
605// Initialize data structure for dde data access
606bool InitDCDataAccess(WORD wC)
607{
608        // assign memory for data access variables
609        DDA[wC] = (DCDATAACCESS *)malloc(sizeof(DCDATAACCESS));
610        if (DDA[wC] == NULL)
611        {
612                csMsg = (CString)ccMsgNotEnoughMemory02;
613                return false;
614        }
615
616        DDA[wC]->pData = NULL;
617        DDA[wC]->dwLen = 0;
618        DDA[wC]->pszData = NULL;
619        strncpy(DDA[wC]->szAccType,"string",sizeof(DDA[wC]->szAccType));
620        DDA[wC]->dwTransID = 0;
621        DDA[wC]->dwCbTransID = 0;
622        return true;
623}
624
625
626// Initiate a conversation with the server application on a topic
627// If server is not found, ask to launch it. If either server could
628// not be launched or topic is not found give an error message.
629bool DCConnect (WORD* pConvNo, char* szService, char* szTopic)
630{
631    HSZ hszDDEServer;
632        HSZ hszTopic;
633        HCONV hConv;
634
635        csMsg = "";
636
637        // Get server application handle
638        hszDDEServer = DdeCreateStringHandle(dwDDEInst, szService, CP_WINANSI );
639        // Get topic handle
640        hszTopic = DdeCreateStringHandle(dwDDEInst, szTopic, CP_WINANSI);
641        // Get conversation handle
642        hConv = DdeConnect(dwDDEInst, hszDDEServer, hszTopic, NULL);
643
644    DdeFreeStringHandle(dwDDEInst, hszDDEServer);
645    DdeFreeStringHandle(dwDDEInst, hszTopic);
646
647        if(hConv == 0L)
648        {
649                csMsg = (CString)ccMsgConnectFailed01 + szService +
650                                (CString)ccMsgConnectFailed02 + szTopic +
651                                (CString)ccMsgConnectFailed03;
652                return 0;
653        }
654
655        // determine conversation number
656        if(!GetConvNo(pConvNo))
657                return false;
658        // init variables neccessary for conversation
659        if(!InitDdeVars(hConv, *pConvNo)) 
660        {
661                FreeDdeV(*pConvNo);
662                return false;
663        }
664        else
665        {
666                if(!InitDCDataAccess(*pConvNo)) 
667                {
668                        FreeDDA(*pConvNo);
669                        return false;
670                }
671                return true;
672        }
673}
674
675
676// procedure for initializing DDEML.DLL
677bool DCInit()
678{
679    UINT ui;
680
681    // Set message string
682        csMsg = (CString)ccDMLERRInitialize;
683       
684        // Initialize DDEML
685    ui = DdeInitialize(&dwDDEInst,
686                       (PFNCALLBACK) DdeCallback,
687                       APPCMD_CLIENTONLY, 
688                       0L);
689
690        // Initialize pointer arrays
691        for(int i = 0; i < wCONVMAX; i++)
692        {
693                DdeV[i] = NULL;
694                DDA[i] = NULL;
695        }
696    if (ui != DMLERR_NO_ERROR)
697        {
698                DCGetLastError(dwDDEInst, (CString)ccDMLERRInitialize);
699                return false;
700    }
701        else
702        {
703                return true;
704        }
705}
706
707// procedure which frees handles of the DDE conversation and memory associated
708// with the last transaction. Has has to be called after each transaction
709// especially after transactions which give back data.
710// Important: After data handle is freed no pointer can access the data.
711// Therefore it has to be processed or copied to another buffer before.
712bool DCFreeDdeMem(WORD wC)
713{
714        bool bSuccess = true;
715        CString csMsgLocal = "";
716
717        csMsg = "";
718
719        // Free string handle now.
720        if (DdeV[wC]->hszItem != NULL) 
721        {
722                if(!DdeFreeStringHandle( dwDDEInst, DdeV[wC]->hszItem ))
723                {
724                        csMsgLocal = (CString)ccMsgHandleErr01;
725                        bSuccess = false;
726                }
727                DdeV[wC]->hszItem = NULL;
728        }
729        // Free data handle now
730        if(DdeV[wC]->hData)
731        {
732                if(!DdeFreeDataHandle(DdeV[wC]->hData))
733                {
734                        csMsgLocal = csMsgLocal + (CString)" " + (CString)ccMsgHandleErr02;
735                        bSuccess = false;
736                }
737                DdeV[wC]->hData = 0L;
738        }
739        // Free memory of dde data buffers
740        FreeData(wC);
741
742        if (!bSuccess) csMsg = csMsgLocal;
743
744        return bSuccess;
745}
746
747// procedure which disconnects a DDE connection
748bool DCDisconnect(WORD wC)
749{
750        int nSuccess = 1;
751        CString csMsgLocal = "";
752
753        csMsg = "";
754
755        // Free handles and memory associated with the  last transaction
756        if(!DCFreeDdeMem(wC)) csMsgLocal = csMsg;
757
758    // Done with the conversation now.
759
760        nSuccess = DdeDisconnect(DdeV[wC]->hConv);
761
762        // Free memory for DDE variables
763        FreeDdeV(wC);
764        // Free memory for DDE data access variables
765        FreeDDA(wC);
766
767        if (nSuccess == 0)
768        {
769                DCGetLastError(dwDDEInst, csMsgLocal + (CString) " " + 
770                                                                  (CString)szMsgDMLERRDisconnect);
771                return false;
772        }
773        return true;
774}
775
776// procedure which uninitializes DDEML.DLL
777bool DCUninit()
778{
779        if(DdeUninitialize(dwDDEInst))// && AfxFreeLibrary(dwDDEInst))
780        {
781                // Reset instance handle
782                dwDDEInst = 0;
783                return true;
784        }
785    else
786        {
787                DCGetLastError(dwDDEInst, (CString)szMsgDMLERRUninitialize);
788                return false;
789        }
790}
791
792
793// handle DDE data
794bool DdeDataHandling(WORD wC, HDDEDATA hData, char szAccess[])
795{
796        bool bSuccess = false;
797        if (0 == strnicmp (szAccess,"string",6))
798        {
799                // get pointer to the data as string //in pszDCDataString
800                bSuccess = DdeDataString(wC, hData);
801        }
802        else if (0 == strnicmp (szAccess,"byte",4))
803                // fill c-structure with data for dde data access
804                bSuccess = DdeDataBytes(wC, hData);
805
806        return bSuccess;
807}
808
809// Do a DDE Transaction
810bool DCTransaction(WORD wC, char szType[], char szItem[], char szData[], 
811                                   char szFormat[], DWORD dwTimeout, char szAccess[])
812{
813        bool bSuccess = true;
814        csMsg = "";
815
816        // Set parameters for dde transaction
817        SetDDEParams(wC, szType, szItem, szData, szFormat, &dwTimeout);
818
819    // execute dde transaction
820        DdeV[wC]->hData = DdeClientTransaction(DdeV[wC]->pData, 
821                                                                                        DdeV[wC]->cbData, 
822                                                                                        DdeV[wC]->hConv, 
823                                                                                        DdeV[wC]->hszItem, 
824                                                                                        DdeV[wC]->wFmt,
825                                                                                        DdeV[wC]->wType, 
826                                                                                        DdeV[wC]->dwTimeout, 
827                                                                                        &(DdeV[wC]->dwResult));
828        // store transaction ID
829        DDA[wC]->dwTransID = DdeV[wC]->dwResult;
830        // Error handling
831        if (DdeV[wC]->hData == 0)
832        {
833                // Transaction failed
834                csMsg = (CString)"'" + szType + (CString)" " + szItem + (CString)"' " + 
835                                (CString)ccMsgTransactionFailed;
836                bSuccess = false;
837        }
838        // data handling for synchronous transactions
839        else if ((DdeV[wC]->wType == XTYP_REQUEST) && 
840                (DdeV[wC]->dwTimeout != TIMEOUT_ASYNC))
841        {
842                bSuccess = DdeDataHandling(wC, DdeV[wC]->hData, szAccess);
843                if (!bSuccess) 
844                {
845                        FreeData(wC);
846                        csMsg = (CString)ccMsgRequestFailed + szItem;
847                }
848        }
849        // store variable for data access format for asynchronous transaction
850        else if (DdeV[wC]->dwTimeout == TIMEOUT_ASYNC)
851                strncpy(DDA[wC]->szAccType,szAccess,sizeof(DDA[wC]->szAccType));
852
853        return bSuccess;
854}
855
856
857// procedure which gives back the message of last error.
858// By bDCErrorExport is decided whether the message is the return value of
859// the function or displayed in a message box.
860// The length of the message is is determined by the size of szErrorMsg.
861// If the message is longer than sizeof(szErrorMsg) it will be cut off,
862// and a comment is given.
863char* DCLastError()
864{
865        if(bDCErrorExport)
866        {
867                return csMsg.GetBuffer(0);
868        }
869        else
870        {
871                MessageBox((HWND)GetActiveWindow(), csMsg, ccMsgCaption, MB_OK | MB_ICONERROR);
872                return 0;
873        }
874}
875
876// procedure which frees memory of DDE data
877void FreeData(WORD wC)
878{
879        // Free memory of dde data
880        if(DDA[wC] != NULL)
881        {
882                if(DDA[wC]->pszData != NULL)
883                {
884                        free(DDA[wC]->pszData);
885                        DDA[wC]->pszData = NULL;
886                }
887                if(DDA[wC]->pData != NULL)
888                {
889                        free(DDA[wC]->pData);
890                        DDA[wC]->pData = NULL;
891                }
892        }
893}
894
895// procedure which frees memory, to be called before ending dll access.
896void DCFinalize()
897{
898        for (WORD i = 0; i < wCONVMAX; i++)
899        {
900                FreeData(i);
901                FreeDdeV(i);
902                FreeDDA(i);
903        }
904        _heapmin();
905}
906
907
908// helper procedure for DCAsynchTransactionCompleted which determines
909// if a certain asynchronous transaction  has completed.
910bool AsynchTransactionCompleted(WORD wC, DWORD dwTransID)
911{
912        MSG msg;
913        bool bSuccess = true;
914
915        csMsg = "";
916
917        if(dwTransID == DDA[wC]->dwCbTransID)
918        {
919                // Transaction IDs are equal, the desired transaction
920                // was already handled by the callback function
921                DDA[wC]->dwCbTransID = 0;
922                bSuccess = bCbSuccess;
923                //char szTemp[100];
924                //sprintf(szTemp,"Entry TransID = CbTransID bSuccess: %i",bSuccess);
925                //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
926        }
927        else
928        {
929                // look for message in message queue
930                if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == 0)
931                {
932                        // no message in queue
933                        csMsg = (CString)ccMsgNoWindowsMessage;
934                        bSuccess = false;
935                }
936                else
937                {
938                       
939                        //char szTemp[100];
940                        //sprintf(szTemp,"Before dispatch Message: %i  TransID = %i  CbTransID = %i",msg.message,dwTransID,DDA[wC]->dwCbTransID);
941                        //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
942                       
943                        TranslateMessage(&msg); 
944                        DispatchMessage(&msg); 
945                        // a message was in the queue, is dispatched
946                        // and may have invoked the callback function
947                       
948                        //sprintf(szTemp,"After dispatch TransID = %i  CbTransID = %i",dwTransID,DDA[wC]->dwCbTransID);
949                        //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
950
951                        if(dwTransID == DDA[wC]->dwCbTransID)
952                        {
953                                // Transaction IDs are equal, the desired transaction was handled
954                                // by the callback function
955
956                                //sprintf(szTemp,"TransID = CbTransID Message: %i",msg.message);
957                                //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
958
959                                DDA[wC]->dwCbTransID = 0;
960                                switch (msg.message) 
961                                {
962                                        case 996: // = WM_DDE_ACK
963                                                if((DdeV[wC]->wType == XTYP_EXECUTE) |
964                                                (DdeV[wC]->wType == XTYP_POKE))
965                                                        // execute and poke return only an ACK                                 
966                                                        bSuccess = bCbSuccess;
967                                                if(DdeV[wC]->wType == XTYP_REQUEST)
968                                                {
969                                                        // when command cannot be processes (applies not to all servers)
970                                                        csMsg = (CString)ccMsgAsynchRequestNotCompleted;
971                                                        bSuccess = false;
972                                                }
973                                                break;
974
975                                        case 997: // = WM_DDE_DATA
976                                                if(DdeV[wC]->wType == XTYP_REQUEST)
977                                                {
978                                                        // request return data when finished
979                                                        bSuccess = bCbSuccess;
980
981                                                        //sprintf(szTemp,"inside WM_DDE_DATA bSuccess: %i",bSuccess);
982                                                        //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
983                                                }
984                                                break;
985
986                                        default:
987                                                //char szTemp[100];
988                                                //sprintf(szTemp,"inside default branch");
989                                                //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
990                                                csMsg = (CString)ccMsgAsynchTransNotCompleted;
991                                                bSuccess = false;
992                                        }
993                        }
994                        else
995                        {
996                                csMsg = (CString)ccMsgAsynchTransNotCompleted;
997                                bSuccess = false;
998                        }
999
1000                }
1001        }
1002
1003        //char szTemp[100];
1004        //sprintf(szTemp,"Before exit bSuccess: %i",bSuccess);
1005        //MessageBox((HWND)GetActiveWindow(), szTemp, "AsynchTransactionCompleted", MB_OK);
1006        return bSuccess;
1007}
1008
1009// procedure which determines if a certain asynchronous transaction
1010// has completed. Only to use for one transaction at a time, because
1011// messages from other transactions will be ignored. Procedure enables
1012// quasi synchronous behavior for asynchronous request, if called
1013// after transaction call. To use if in between a transaction is processed
1014// by a server some other calculations shall be done in the program without
1015// waiting for the server to finish the transaction. After the calculations
1016// this procedure can be called. If the server has finished it returns true,
1017// if not false.
1018// bWait:       controls, if the procedure shall wait until the transaction is
1019//                      finished (true) or only check once for completion (false).
1020bool DCAsynchTransactionCompleted(WORD wC, DWORD dwTransID, bool bWait)
1021{
1022        bool bSuccess;
1023        do
1024        {
1025                bSuccess = AsynchTransactionCompleted(wC, dwTransID);
1026                // transaction completed with error
1027                if(!bCbSuccess) return false;
1028                // transaction completed successful
1029                else if(bSuccess && bCbSuccess) return true;
1030                //
1031        }while(bWait && !bSuccess && bCbSuccess);
1032        // no message available
1033        return false;
1034}
1035               
1036
1037// procedure which retrives the conversation number from a given
1038// conversation handle
1039WORD FindConvNo(HCONV hConv)
1040{
1041        for(WORD i = 0; i < wCONVMAX; i++)
1042                if(DdeV[i]->hConv == hConv)
1043                        return i;
1044        return wCONVMAX + 1;
1045}
1046// procedure which determines the next conversation number
1047bool GetConvNo(WORD* pConvNo)
1048{
1049        WORD i = 0;
1050        while((i < wCONVMAX) && (DdeV[i] != NULL)) i++;
1051        if (i >= wCONVMAX)
1052        {
1053                // too many conversations
1054                csMsg = (CString)ccMsgConvMaxError;
1055                return false;
1056        }
1057        else
1058        {
1059                *pConvNo = i;
1060                return true;
1061        }
1062}
1063
1064// Free memory for DDE variables
1065void FreeDdeV(WORD wC)
1066{
1067        if(DdeV[wC] != NULL)
1068        {
1069                free(DdeV[wC]);
1070                DdeV[wC] = NULL;
1071        }
1072        return;
1073}
1074// Free memory for DDE data access variables
1075void FreeDDA(WORD wC)
1076{
1077        if(DDA[wC] != NULL)
1078        {
1079                free(DDA[wC]);
1080                DDA[wC] = NULL;
1081        }
1082        return;
1083}
1084
1085// procedure to abandon an asynchronous transaction
1086// takes the conversation number and the transaction id
1087bool DCAbandonTransaction(WORD wC, DWORD dwTransID)
1088{
1089        bool bSuccess;
1090
1091        bSuccess = DdeAbandonTransaction(dwDDEInst, DdeV[wC]->hConv, dwTransID);
1092        FreeData(wC);
1093
1094        if(!bSuccess)
1095        {
1096                DCGetLastError(dwDDEInst, (CString)ccMsgAbandonTransaction);
1097                bSuccess = false;
1098    }
1099        else
1100        {
1101                bSuccess = true;
1102        }
1103        return bSuccess;
1104}
1105
1106// procedure which gives back the version of this dll
1107char* DCVersion()
1108{
1109        return szVersion;
1110}
1111
1112
Note: See TracBrowser for help on using the browser.