home *** CD-ROM | disk | FTP | other *** search
- /*
-
- DDE.C -- user code for DDE communication
- Copyright 1987-1991 Authorware Inc.
-
- Revsion History
-
- 7/25/91 - Initial version
-
- General Notes:
-
- 1) In this application it is assumed that this dll is the client and the
- application it is communicating with is the server.
-
- 2) This implementation is for cold link sessions only.
-
- 3) A DDE session consists of three parts
- a) Application - this is the name of the application which you are
- communicating with. This DOES NOT mean the name of the executable.
- It is an internal name for the application.
-
- b) Topic - this is the general name of the information you are requesting
- data on. This is internal to the application you are communicating
- with.
-
- c) Item - this is the specific information based on the topic which the
- DDE session is based on.
-
- See the notes which come with the application you are communicating
- with for the proper application name, topic and item. Other sources
- of information on DDE include:
-
- Microsoft (R) Windows SDK 3.0
- Reference Manual Volume 2
-
- Programming for Windows by Charles Petzold
- Microsoft Press (R)
- Second Edition.
-
-
- Lifecycle of a cold link DDE session:
-
- 1) Client sends a WM_DDE_INITIATE message (with the application and topic)
-
- 2) Server responds with a WM_DDE_ACK (this lets the client know the server
- window handle).
-
- 3) Client sends a WM_DDE_REQUEST (with the item requested and the format
- for the data to be returned).
-
- 4) Server responds with one of the following:
- a) Server sends a WM_DDE_DATA message with the data.
- - May request the client to respond with a WM_DDE_ACK.
-
- b) Server sends a WM_DDE_ACK (negative response) message to inform
- the client that the request cannot be filled.
-
- 5) Client sends a WM_DDE_TERMINATE message.
-
- 6) Server responds with a WM_DDE_TERMINATE message.
-
- Please note:
-
- a) steps 3 and 4 can be repeated many times.
- b) steps 5 and 6 can be reversed.
- */
-
- #include "windows.h"
- #include "dde.h"
-
- // Defines for cbWndExtra bytes on the window class.
- #define SERVERWND 0 // Handle to the server window
- #define SERVERDATA 2 // Returned server data
- #define CLIENTSTATUS 4 // Current status of communication
- #define REQUESTHAND 6 // Copy of the request
-
- // CLIENTSTATUS defines - defines current state of the DDE link
- #define IDLESTATUS 0 // Communication established - idle status
- #define INITSTATUS 1 // Initializing the link
- #define REQUESTING 2 // Requesting data
- #define NEWDATA 3 // New data has arrived from the server
- #define EXECUTING 4 // Executing request to the server
-
- // Size of a item request field
- #define ITEMLENGTH 256
-
- // Request data structure. All item requests use this structure.
- typedef struct
- {
- short type; // Type of data requested - ie CF_TEXT
- char item[ITEMLENGTH]; // Item name.
- } REQUEST, FAR *REQUEST_PTR;
-
- #define VALID_WINDOW(w) ((w) && IsWindow(w)) // Make NULL an invalid window
-
- // Class name - for Window registering
- static char szClassName[] = "APWDLLDDE";
- static WORD hInst;
- static DDEACK ack;
-
- /* Function Prototypes */
- short FAR PASCAL WEP( short bSystemExit );
- short FAR PASCAL LibMain( HANDLE hModule, WORD wDataSeg, WORD cbHeapSize,
- LPSTR lpszCmdLine );
- long FAR PASCAL DDEProc( HWND wnd, WORD message, WORD wParam, LONG lParam );
-
- static BOOL NEAR PASCAL DDERequest( HWND DDElink, LPSTR item, short type );
-
-
- short FAR PASCAL LibMain( HANDLE hModule, WORD wDataSeg, WORD cbHeapSize,
- LPSTR lpszCmdLine )
- /*
- Is called by LibEntry. LibEntry is called by Windows when the DLL is
- loaded. The LibEntry routine is provided in the LIBENTRY.OBJ in the SDK
- Link Libraries disk. (The source LIBENTRY.ASM is also provided.)
-
- LibEntry initializes the DLL's heap, if a HEAPSIZE value is specified
- in the DLL's DEF file. Then LibEntry calls LibMain. The LibMain function
- below satisfies that call.
-
- The LibMain function should perform additional initialization tasks
- required by the DLL. In this example, no initialization tasks are
- required. LibMain should return a value of 1 if the initialization is
- successful.
-
- Returns:
-
- 1 if ok
- 0 if error
- */
- {
- WNDCLASS wc;
-
- hInst = hModule;
-
- /*
- Register our basic window class. Extra bytes are used to keep track
- of the server window, current status of the DDE link, received data
- and a copy of the request being sent to the server.
- */
- wc.style = 0;
- wc.lpfnWndProc = DDEProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 4*sizeof(short);
- wc.hInstance = hInst;
- wc.hIcon = NULL;
- wc.hCursor = NULL;
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = szClassName;
-
- if (!RegisterClass(&wc))
- return 0;
-
- return 1;
- }
-
-
- short FAR PASCAL WEP( short bSystemExit )
- /*
- Performs cleanup tasks when the DLL is unloaded. WEP() is called
- automatically by Windows when the DLL is unloaded (no remaining tasks
- still have the DLL loaded). It is strongly recommended that a DLL have a
- WEP() function, even if it does nothing but returns success (1), as in
- this example.
- */
- {
- return 1;
- }
-
-
- HWND FAR PASCAL DDEInitialize( LPSTR app, LPSTR topic )
- /*
- This function initializes a DDE session with the application "app" on the
- topic "topic".
-
- Returns:
-
- a handle to the DDE Session, or 0 if an error occured
-
- This handle is to be passed to all subsequent calls to DDE
- user code functions.
- */
- {
- ATOM a_app;
- ATOM a_top;
- HWND hServer = 0;
- HWND DDElink;
-
- // Create an offscreen window to handle all DDE communication
- DDElink = CreateWindowEx(WS_EX_NOPARENTNOTIFY, szClassName, "", WS_POPUP,
- -1000, -1000, 10, 10, NULL, NULL, hInst, NULL);
-
- if (VALID_WINDOW(DDElink))
- {
- // Set the CLIENTSTATUS to an initialization state
- SetWindowWord(DDElink, CLIENTSTATUS, INITSTATUS);
-
- // Fill in the application and topic supplied by the caller
- if ((a_app = GlobalAddAtom((LPSTR)app)) != 0)
- {
- if ((a_top = GlobalAddAtom((LPSTR)topic)) == 0)
- {
- GlobalDeleteAtom(a_app);
- DestroyWindow(DDElink);
- DDElink = 0;
- }
- else
- {
- // Send a message out to other applications looking for communication
- // with "app" on "topic"
- SendMessage(0xffff, WM_DDE_INITIATE, DDElink, MAKELONG(a_app, a_top));
-
- // If an application responded its WindowHandle will be stored in
- // SERVERWND by DDEProc
- if ((hServer = GetWindowWord(DDElink, SERVERWND)) == 0)
- {
- // Nobody responded
- DestroyWindow(DDElink);
- DDElink = 0;
- }
- else
- SetWindowWord(DDElink, CLIENTSTATUS, IDLESTATUS);
- }
- }
- else
- {
- DestroyWindow(DDElink);
- DDElink = 0;
- }
- }
-
- // Returns a handle to the DDElink. Since all information on the DDE session
- // is stored in the cbWndExtra of DDElink's window all information is
- // accessable from DDElink.
- return DDElink;
- }
-
-
- void FAR PASCAL DDETerminate( HWND DDElink )
- /*
- This function terminates the DDE session associated with the window
- "DDElink".
-
- Returns:
-
- Void
- */
- {
- HWND server;
-
- if (VALID_WINDOW(DDElink))
- {
- // Get the server window handle
- server = GetWindowWord(DDElink, SERVERWND);
-
- // Terminate any session which exists
- if (VALID_WINDOW(server))
- PostMessage(server, WM_DDE_TERMINATE, DDElink, 0L);
- else
- DestroyWindow(DDElink);
- }
-
- return;
- }
-
-
- BOOL FAR PASCAL DDEExecuteString( HWND DDElink, LPSTR item )
- /*
- This function requests the server to execute the contents of string.
-
- The Application and topic MUST have already be set by a call to DDEInitialize.
-
- Returns:
-
- 0 - Failure.
- 1 - Request sent.
- */
- {
- HANDLE a_item;
- HWND server;
- LPSTR str;
- BOOL rv = FALSE;
-
- if (VALID_WINDOW(DDElink))
- {
- if (GetWindowWord(DDElink, CLIENTSTATUS) == IDLESTATUS)
- {
- server = GetWindowWord(DDElink, SERVERWND);
- if (VALID_WINDOW(server))
- {
- // Allocate the necessary memory first
- if ((a_item = GlobalAlloc(GMEM_DDESHARE, lstrlen(item)+1)) != 0)
- {
- // Dupe the string.
- str = GlobalLock(a_item);
- lstrcpy(str, item);
- GlobalUnlock(a_item);
-
- // Post the request to the server. a_item is freed by the server
- // if the PostMessage succeeded
- if (!PostMessage(server, WM_DDE_EXECUTE, DDElink, MAKELONG(0,a_item)))
- GlobalFree(a_item);
- else
- {
- SetWindowWord(DDElink, CLIENTSTATUS, EXECUTING);
- rv = TRUE;
- }
- }
- }
- }
- }
-
- return rv;
- }
-
-
- BOOL FAR PASCAL DDERequestString( HWND DDElink, LPSTR item )
- /*
- This function requests data from the server in string format.
-
- The Application and topic MUST have already be set by a call to DDEInitialize.
-
- Returns:
-
- 0 - Failure.
- 1 - Request sent.
- */
- {
- return DDERequest(DDElink, item, CF_TEXT);
- }
-
-
- static BOOL NEAR PASCAL DDERequest( HWND DDElink, LPSTR item, short type )
- /*
- This function requests data from the server. The server window is found in
- the cbWndExtra bytes of DDElink.
-
- The Application and topic MUST have already be set by a call to DDEInitialize.
-
- Returns:
-
- 0 - Failure.
- 1 - Request sent.
- */
- {
- ATOM a_item;
- HWND server;
- HANDLE req;
- BOOL rv = FALSE;
- REQUEST_PTR req_ptr;
-
- if (VALID_WINDOW(DDElink))
- {
- if (GetWindowWord(DDElink, CLIENTSTATUS) == IDLESTATUS)
- {
- server = GetWindowWord(DDElink, SERVERWND);
- if (VALID_WINDOW(server))
- {
- // Allocate the necessary memory first
- if ((a_item = GlobalAddAtom((LPSTR)item)) != 0)
- {
- if ((req = GlobalAlloc(GHND, sizeof(REQUEST))) != 0)
- {
- // Post the request to the server.
- if (!PostMessage(server, WM_DDE_REQUEST, DDElink, MAKELONG(type,a_item)))
- {
- GlobalDeleteAtom(a_item);
- GlobalFree(req);
- }
- else
- {
- // Fill in the request data structure
- req_ptr = (REQUEST_PTR)GlobalLock(req);
- req_ptr->type = type;
- lstrcpy(req_ptr->item, (LPSTR)item);
- GlobalUnlock(req);
-
- // Set the CLIENTSTATUS to request made - waiting for response and
- // store a copy of the request in REQUESTHAND
- SetWindowWord(DDElink, CLIENTSTATUS, REQUESTING);
- SetWindowWord(DDElink, REQUESTHAND, req);
- rv = TRUE;
- }
- }
- else
- GlobalDeleteAtom(a_item);
- }
- }
- }
- }
-
- return rv;
- }
-
-
- HANDLE FAR PASCAL DDEDataString( HWND DDElink )
- /*
- This function returns the handle to a string of data which was received
- from the server window in response to a call to DDERequestString.
-
- There must be a call to DDERequestString in order for data to arrive.
-
- The data is returned string format.
-
- Returns:
-
- 0 - No data
- HANDLE - Handle to the data string.
- */
- {
- HANDLE hand=0;
-
- if (VALID_WINDOW(DDElink))
- {
- if (GetWindowWord(DDElink, CLIENTSTATUS) == NEWDATA)
- {
- hand = GetWindowWord(DDElink, SERVERDATA);
- SetWindowWord(DDElink, CLIENTSTATUS, IDLESTATUS);
- }
- }
- return hand;
- }
-
-
- long FAR PASCAL DDEProc( HWND wnd, WORD message, WORD wParam, LONG lParam )
- /*
- This function is the window procedure for all DDE communication. The
- extra bytes at the end of the Window handle contain all information
- about the DDE session.
- */
- {
- GLOBALHANDLE DDE;
- ATOM a_app, a_top, a_item;
- DDEDATA FAR *DDE_ptr;
- char szItem[ITEMLENGTH];
- HANDLE req;
- REQUEST_PTR req_ptr;
- WORD wStatus;
-
- switch (message)
- {
- case WM_DDE_ACK:
-
- wStatus = GetWindowWord(wnd, CLIENTSTATUS);
-
- // Accept an Ack only if we are in a INITSTATUS or EXECUTING
- if (wStatus == INITSTATUS)
- {
- // Store the SERVER window in SERVERWND
- SetWindowWord(wnd, SERVERWND, wParam);
-
- // Clean up the atoms allocated on initialization
- GlobalDeleteAtom(LOWORD(lParam));
- GlobalDeleteAtom(HIWORD(lParam));
- }
- else if (wStatus == EXECUTING)
- {
- // Reset the flag
- SetWindowWord(wnd, CLIENTSTATUS, IDLESTATUS);
-
- // Clean up the global memory
- if (HIWORD(lParam))
- GlobalFree(HIWORD(lParam));
- }
-
- break;
-
- case WM_DDE_TERMINATE:
-
- // Destroy this window
- DestroyWindow(wnd);
- break;
-
-
- case WM_DDE_DATA:
-
-
- // wParam - sending window handle
- // LOWORD lParam - DDEDATA memory handle
- // HIWORD lParam - item atom.
-
- // Must have complete information
- if ((DDE = LOWORD(lParam)) == 0 || (a_item = HIWORD(lParam)) == 0)
- break;
-
- DDE_ptr = (DDEDATA FAR *)GlobalLock(DDE);
-
- ack.bAppReturnCode = 0;
- ack.reserved = 0;
- ack.fBusy = FALSE;
- ack.fAck = FALSE;
-
- // Data has been sent in response to a request - did we request it?
- if (GetWindowWord(wnd, CLIENTSTATUS) == REQUESTING)
- {
- // We only support CF_TEXT format at this time.
- if (DDE_ptr->cfFormat == CF_TEXT)
- {
- // Get the atom which tells us if this data is for our request.
- GlobalGetAtomName(a_item, szItem, sizeof(szItem));
-
- // Get our request
- req = GetWindowWord(wnd, REQUESTHAND);
- if (req)
- {
- req_ptr = (REQUEST FAR *)GlobalLock(req);
-
- // Compare our request with what was sent - are they the same?
- if (lstrcmp(req_ptr->item, szItem) == NULL)
- {
- HANDLE data;
- LPSTR data_ptr;
-
- // Make a copy of the data sent
- if ((data = GlobalAlloc(GHND, lstrlen(DDE_ptr->Value)+1)) != 0)
- {
- data_ptr = GlobalLock(data);
- lstrcpy(data_ptr, DDE_ptr->Value);
- GlobalUnlock(data);
- }
-
- // Store the new data in SERVERDATA and set the CLIENTSTATUS
- // to NEWDATA informing of new data.
- SetWindowWord(wnd, SERVERDATA, data);
- SetWindowWord(wnd, CLIENTSTATUS, NEWDATA);
-
- ack.fAck = TRUE;
- }
-
- // Free our copy of the request - no longer needed.
- GlobalUnlock(req);
- GlobalFree(req);
- SetWindowWord(wnd, REQUESTHAND, 0);
- }
- }
- }
-
- // If the server wants an acknowledgment send it to him.
- if (DDE_ptr->fAckReq == TRUE)
- {
- wStatus = *(WORD *)&ack;
- if (!PostMessage(wParam, WM_DDE_ACK, wnd, MAKELONG(wStatus, a_item)))
- {
- GlobalDeleteAtom(a_item);
- GlobalUnlock(DDE);
- GlobalFree(DDE);
- }
-
- }
- else
- GlobalDeleteAtom(a_item);
-
- GlobalUnlock(DDE);
-
- // Free up memory if we are supposed to
- if (DDE_ptr->fRelease == TRUE || ack.fAck == FALSE)
- GlobalFree(DDE);
-
- break;
-
- default:
- return DefWindowProc(wnd, message, wParam, lParam);
- }
-
- return 0L;
- }
-
-
-