// Borland C++ - (C) Copyright 1991, 1992 by Borland International //******************************************************************* // // program - DDESrvr.c // purpose - DDE server interface routines. This file is part of the // MSGWND project. // //******************************************************************* #define STRICT #include #pragma hdrstop #include #include #include #include #include "ddepack.h" #include "ddesrvr.h" # define WW_CLIENT 0 # define ACK 0x8000 # define BUSY 0x4000 #if defined(__WIN32__) #define SetWindowClient(hWnd,hWndClient)\ SetWindowLong (hWnd, WW_CLIENT, (LONG) (hWndClient)) #define GetWindowClient(hWnd)\ ((HWND) GetWindowLong (hWnd, WW_CLIENT)) #define DDEGetCommandHandle(hCommand)\ ((LPARAM)(hCommand)) #else #define SetWindowClient(hWnd,hWndClient)\ SetWindowWord (hWnd, WW_CLIENT, (WORD) (hWndClient)) #define GetWindowClient(hWnd)\ ((HWND) GetWindowWord (hWnd, WW_CLIENT)) #define DDEGetCommandHandle(hCommand)\ ((LPARAM)HIWORD(hCommand)) #endif static int nServerClassRegistered; static char szServerClass[] = "ddeserver"; static WORD wLastDDEServerMsg; //******************************************************************* // DDEServerInit - called in response to WM_DDE_INITIATE // // paramaters: // hParentWnd - The handle of the server window trying to // respond to this dde conversation. // hClientWnd - The handle of the client window trying to start // this dde conversation. // lParam - lParam send by client window. // Contains atoms of application and topic client // wants to talk about. // szApp - The name of the application server represents. // szTopic - The name of the topic server knows about. // // returns: // The handle of the channel to use to continue the conversation // or // NULL if conversation could not be opened. // //******************************************************************* HWND DDEServerInit(HWND hParentWnd, HWND hClientWnd, LPARAM lParam, char *szApp, char *szTopic) { HINSTANCE hInst; HWND hChannel; ATOM aApp; ATOM aTopic; WNDCLASS wclass; char szClassName[sizeof(szServerClass) + 10]; // Get atoms representing application and topic we will talk about. aApp = GlobalAddAtom(szApp); if (!aApp) return(0); aTopic = GlobalAddAtom(szTopic); if (!aTopic) { GlobalDeleteAtom(aApp); return(0); } // If request is not for application and topic we will talk about // do not open conversaton. if ((aApp != LOWORD(lParam)) || (aTopic != HIWORD(lParam))) { GlobalDeleteAtom(aApp); GlobalDeleteAtom(aTopic); return(0); } // Get parents instance to use in creating window to carry on // dde conversation. hInst = (HANDLE)GetWindowInstance(hParentWnd); if (!hInst) return(0); // Create a unique class name for this instance of the server. sprintf(szClassName, "%s%04X", szServerClass, hInst); // If we have not already done it, register the window class to // carry on this conversation. if (!nServerClassRegistered) { wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = DDEServerWndProc; wclass.cbClsExtra = 0; wclass.cbWndExtra = 2; wclass.hInstance = hInst; wclass.hIcon = 0; wclass.hCursor = 0; wclass.hbrBackground = 0; wclass.lpszMenuName = 0; wclass.lpszClassName = szClassName; // Do not fail if register fails, because another app may have // already registered this class. RegisterClass(&wclass); // So we won't try to register again. nServerClassRegistered = 1; } // Create the window that will remain hidden but will carry on the // conversation wih the dde client. hChannel = CreateWindow(szClassName, // window class name NULL, // window title WS_CHILD, // window style CW_USEDEFAULT, // window origin 0, CW_USEDEFAULT, // window size 0, hParentWnd, // window parent NULL, // window id hInst, // window instance NULL); // no parms // If create of window failed we cannot continue. if (!hChannel) return(0); // Remember the handle of our client. SetWindowClient(hChannel, hClientWnd); // Send acknowledgement to client. wLastDDEServerMsg = WM_DDE_ACK; SendMessage(hClientWnd, (UINT)wLastDDEServerMsg, (WPARAM)hChannel, (LPARAM)DDEPack(WM_DDE_ACK, aApp, aTopic)); // Return handle of window that will carry on the conversation for // this server. return(hChannel); } //******************************************************************* // DDEServerClose - close the dde conversation with a client // // paramaters: // hChannel - The handle of the window conducting // the dde conversation. // //******************************************************************* int DDEServerClose(HWND hChannel) { HWND hClientWnd; // If the channel is still active. if (IsWindow(hChannel)) { wLastDDEServerMsg = WM_DDE_TERMINATE; // Get handle of client we were conversing with. hClientWnd = (HWND)GetWindowClient(hChannel); // If he is still active. if (IsWindow(hClientWnd)) SendMessage(hClientWnd, (UINT)wLastDDEServerMsg, (WPARAM)hChannel, (LPARAM)0L); } return(1); } //******************************************************************* // DDEServerWndProc - window proc to manage interface with client // // paramaters: // hWnd - The window handle for this message // message - The message number // wParam - The WPARAM parameter for this message // lParam - The LPARAM parameter for this message // // returns: // depends on message. // //******************************************************************* LRESULT CALLBACK _export DDEServerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { WORD wStatus; HWND hClientWnd; HANDLE hCommand; HANDLE hData; LPSTR lpData; HANDLE hShData; DDEDATA FAR *lpShData; char szItem[30]; ATOM aItem; LPSTR lpCommand; int nRc; int nSize; switch (message) { case WM_DDE_EXECUTE: // execute a command for client // Get handle of client. hClientWnd = (HWND)wParam; // Init status. wStatus = 0; // Get handle of command client is sending us. hCommand = (HANDLE)DDEGetCommandHandle(lParam); // Lock it down to get address. lpCommand = GlobalLock(hCommand); if (lpCommand) { // Call our function to execute the command. if (DDEExecuteCommand(lpCommand)) wStatus = ACK; GlobalUnlock(hCommand); } // Send acknowledgement back to client. PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd, DDEPack (WM_DDE_ACK, (UINT)wStatus, (UINT)hCommand)); break; case WM_DDE_REQUEST: // data request from a client // Get handle of client. hClientWnd = (HWND)wParam; // Get atom representing data request item. aItem = HIWORD(lParam); if (!GlobalGetAtomName(aItem, szItem, sizeof(szItem))) { // Error if atom not found. PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd, (LPARAM)DDEPack(WM_DDE_ACK, 0, aItem)); return(0L); } // Init return code. nRc = 0; // Don't care about case. strupr(szItem); // Call our function to get the data item. nSize = DDEData(szItem, &hData); // If any data found. if (nSize) { // Get shared memory to send item back in. hShData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, (DWORD) (nSize + sizeof(DDEDATA) + 1)); if (hShData) { // Lock it down to get address. lpShData = (DDEDATA FAR *) GlobalLock(hShData); if (lpShData) { // Setup data header. lpShData->fResponse = 1; lpShData->fRelease = 1; lpShData->fAckReq = 0; lpShData->cfFormat = CF_TEXT; // Lock out local copy of data to get address. lpData = GlobalLock(hData); if (lpData) { // Copy data to shared memory. #if defined(__WIN32__) strcpy((LPSTR)lpShData->Value, lpData); #else _fstrcpy((LPSTR)lpShData->Value, lpData); #endif GlobalUnlock(hData); nRc = 1; } GlobalUnlock(hShData); } } GlobalFree(hData); } if (nRc) { // If ok send data back. PostMessage(hClientWnd, WM_DDE_DATA, (WPARAM)hWnd, (LPARAM)DDEPack (WM_DDE_DATA, (UINT)hShData, (UINT)aItem)); } else { // If errors just send negative acknowlegement back. PostMessage(hClientWnd, WM_DDE_ACK, (WPARAM)hWnd, (LPARAM)DDEPack (WM_DDE_ACK, 0, aItem)); } break; case WM_DDE_TERMINATE: // server says terminate conversation // Get handle of client we are dealing with. hClientWnd = (HWND)GetWindowClient(hWnd); // Ignore if not from our client. if (wParam != (WPARAM)hClientWnd) return(0L); // Forget who client is. SetWindowClient(hWnd, 0); // Tell our parent conversation closed. SendMessage(GetParent(hWnd), WMU_DDE_CLOSED, (WPARAM)hWnd, 0L); // Send terminate to server to acknowledge we recieved // terminate, if we did not initiate the termination ourselves. if ((wLastDDEServerMsg != WM_DDE_TERMINATE) && IsWindow(hClientWnd)) PostMessage(hClientWnd, WM_DDE_TERMINATE, (WPARAM)hWnd, 0L); // Terminate this child window. DestroyWindow(hWnd); break; case WM_DESTROY: // destroy this window // Terminate any ongoing conversation on our way out. DDEServerClose(hWnd); break; default: return(DefWindowProc(hWnd, message, wParam, lParam)); } return(0L); } //*******************************************************************