|
|
/****************************** Module Header ******************************\
* Module Name: Srvr.c Server Main module * * Purpose: Includes All the server communication related routines. * * Created: Oct 1990. * * Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation * * History: * Raor: Wrote the original version. * curts created portable version for WIN16/32 * \***************************************************************************/
#include <windows.h>
#include <shellapi.h>
#include <reghelp.hxx>
#include "cmacs.h"
#include "ole.h"
#include "dde.h"
#include "srvr.h"
#include "strsafe.h"
// LOWWORD - BYTE 0 major verision, BYTE1 minor version,
// HIWORD is reserved
#define OLE_VERSION 0x0901L
extern ATOM aOLE; extern ATOM aSysTopic; extern ATOM aStdExit; extern ATOM aStdCreate; extern ATOM aStdOpen; extern ATOM aStdEdit; extern ATOM aStdCreateFromTemplate; extern ATOM aStdShowItem; extern ATOM aProtocols; extern ATOM aTopics; extern ATOM aFormats; extern ATOM aStatus; extern ATOM cfNative; extern ATOM aEditItems; extern ATOM aStdClose;
extern HANDLE hdllInst;
extern FARPROC lpTerminateClients;
DWORD APIENTRY OleQueryServerVersion () { return OLE_VERSION; }
/***************************** Public Function ****************************\
* OLESTATUS FAR PASCAL OleRegisterServer (lpclass, lpolesrvr, lplhsrvr) * * OleRegisterServer: Registers the server with the server library. * * Parameters: * 1. Ptr to the server class. * 2. Ptr to the olesrvr. This is private to the server app. * (Typically this is the ptr to the private storage area of * server app server related info). * 3. Ptr to the LHSRVR. Place where to pass back the long * handle of the server in DLL (This is private to the DLL). * * return values: * returns OLE_OK if the server is successfully registered . * else returns the corresponding error. * * * History: * Raor: Wrote it, \***************************************************************************/
OLESTATUS APIENTRY OleRegisterServer ( LPCSTR lpclass, // class name
LPOLESERVER lpolesrvr, // ole srvr(private to srvr app)
LHSRVR FAR * lplhsrvr, // where we pass back our private handle
HINSTANCE hInst, OLE_SERVER_USE useFlags ){ HANDLE hsrvr = NULL; LPSRVR lpsrvr = NULL; ATOM aExe = (ATOM)0;
Puts ("OleRegisterServer");
PROBE_READ(lpclass); PROBE_WRITE(lpolesrvr); PROBE_WRITE(lplhsrvr);
// add the app atom to global list
if (!ValidateSrvrClass (lpclass, &aExe)) return OLE_ERROR_CLASS;
hsrvr = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (SRVR)); if (! (hsrvr && (lpsrvr = (LPSRVR)GlobalLock (hsrvr)))) goto errReturn;
// set the signature handle and the app atom.
lpsrvr->sig[0] = 'S'; lpsrvr->sig[1] = 'R'; lpsrvr->hsrvr = hsrvr; lpsrvr->aClass = GlobalAddAtom (lpclass); lpsrvr->lpolesrvr = lpolesrvr; lpsrvr->relLock = TRUE; // set the release lock.
lpsrvr->aExe = aExe; lpsrvr->useFlags = useFlags;
// Create the servre window and do not show it.
if (!(lpsrvr->hwnd = CreateWindow ("SrvrWndClass", "Srvr", WS_OVERLAPPED,0,0,0,0,NULL,NULL, hdllInst, NULL))) goto errReturn;
// save the ptr to the srever struct in the window.
SetWindowLongPtr (lpsrvr->hwnd, 0, (LONG_PTR)lpsrvr);
// Set the signature.
SetWindowWord (lpsrvr->hwnd, WW_LE, WC_LE); SetWindowLongPtr (lpsrvr->hwnd, WW_HANDLE, (LONG_PTR)hInst); *lplhsrvr = (LONG_PTR)lpsrvr;
return OLE_OK;
errReturn: if (lpsrvr){ if (lpsrvr->hwnd) DestroyWindow (lpsrvr->hwnd);
if (lpsrvr->aClass) GlobalDeleteAtom (lpsrvr->aClass);
if (lpsrvr->aExe) GlobalDeleteAtom (lpsrvr->aExe);
GlobalUnlock (hsrvr); }
if (hsrvr) GlobalFree (hsrvr);
return OLE_ERROR_MEMORY;
}
// ValidateSrvrClass checks whether the given server class is valid by
// looking in the win.ini.
BOOL INTERNAL ValidateSrvrClass ( LPCSTR lpclass, ATOM FAR * lpAtom ){ char buf[MAX_STR]; LONG cb = MAX_STR; char key[MAX_STR]; LPSTR lptmp; LPSTR lpbuf; char ch;
if (FAILED(StringCchCopy(key, sizeof(key)/sizeof(key[0]), lpclass))) return FALSE; if (FAILED(StringCchCat(key, sizeof(key)/sizeof(key[0]), "\\protocol\\StdFileEditing\\server"))) return FALSE;
if (QueryClassesRootValueA (key, buf, &cb)) return FALSE;
if (!buf[0]) return FALSE;
// Get exe name without path and then get an atom for that
lptmp = lpbuf = (LPSTR)buf; while ((ch = *lptmp++) && ch != '\0') { if (ch == '\\' || ch == ':') lpbuf = lptmp; } *lpAtom = GlobalAddAtom (lpbuf);
return TRUE; }
/***************************** Public Function ****************************\
* OLESTATUS FAR PASCAL OleRevokeServer (lhsrvr) * * OlerevokeServer: Unregisters the server which has been registered. * * Parameters: * 1. DLL server handle. * * * return values: * returns OLE_OK if the server is successfully unregisterd. * ( It is Ok for the app free the associated space). * If the unregistration is intiated, returns OLE_STARTED. * Calls the Server class release entry point when the server * can be released. * * History: * Raor: Wrote it, \***************************************************************************/
OLESTATUS APIENTRY OleRevokeServer ( LHSRVR lhsrvr ){ HWND hwndSrvr; LPSRVR lpsrvr;
Puts ("OleRevokeServer");
if (!CheckServer (lpsrvr = (LPSRVR)lhsrvr)) return OLE_ERROR_HANDLE;
if (lpsrvr->bTerminate && lpsrvr->termNo) return OLE_WAIT_FOR_RELEASE;
hwndSrvr = lpsrvr->hwnd;
// Terminate the conversation with all clients.
// If there are any clients to be terminated
// return back with OLE_STARTED and srvr relase
// will be called for releasing the server finally.
// we are terminating.
lpsrvr->bTerminate = TRUE; lpsrvr->termNo = 0;
// send ack if Revoke is done as a result of StdExit
if (lpsrvr->fAckExit) { LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK, 0x8000, lpsrvr->hDataExit);
// Post the acknowledge to the client
if (!PostMessageToClient (lpsrvr->hwndExit, WM_DDE_ACK, (WPARAM)lpsrvr->hwnd, lparamNew)) { // if the window died or post failed, delete the atom.
GlobalFree (lpsrvr->hDataExit); DDEFREE(WM_DDE_ACK,lparamNew); } }
// revoks all the documents registered with this server.
RevokeAllDocs (lpsrvr);
// enumerate all the clients which are in your list and post the
// termination.
EnumProps (hwndSrvr, (PROPENUMPROC)lpTerminateClients); // post all the messages with yield which have been collected in enum
// UnblockPostMsgs (hwndSrvr, TRUE);
// reset the release lock. Now it is ok to release the server
// when all the doc clients and server clients have sent back the
// termination.
lpsrvr->relLock = FALSE; return ReleaseSrvr (lpsrvr);
}
// ReleaseSrvr: Called when ever a matching WM_TERMINATE is received
// from doc clients or the server clients of a particular server.
// If there are no more terminates pending, it is ok to release the server.
// Calls the server app "release" proc for releasing the server.
int INTERNAL ReleaseSrvr ( LPSRVR lpsrvr ){
HANDLE hsrvr;
// release srvr is called only when everything is
// cleaned and srvr app can post WM_QUIT
if (lpsrvr->bTerminate){ // only if we are revoking server then see whether it is ok to
// call Release.
// First check whethere any docs are active.
// Doc window is a child window for server window.
if (lpsrvr->termNo || GetWindow (lpsrvr->hwnd, GW_CHILD)) return OLE_WAIT_FOR_RELEASE;
// if the block queue is not empty, do not quit
if (!IsBlockQueueEmpty(lpsrvr->hwnd)) return OLE_WAIT_FOR_RELEASE;
}
if (lpsrvr->relLock) return OLE_WAIT_FOR_RELEASE; // server is locked. So, delay releasing
// Inform server app it is time to clean up and post WM_QUIT.
(*lpsrvr->lpolesrvr->lpvtbl->Release)(lpsrvr->lpolesrvr);
if (lpsrvr->aClass) GlobalDeleteAtom (lpsrvr->aClass); if (lpsrvr->aExe) GlobalDeleteAtom (lpsrvr->aExe); DestroyWindow (lpsrvr->hwnd); GlobalUnlock (hsrvr = lpsrvr->hsrvr); GlobalFree (hsrvr); return OLE_OK; }
//TerminateClients: Call back for the enum properties.
BOOL FAR PASCAL TerminateClients ( HWND hwnd, LPSTR lpstr, HANDLE hdata ){ LPSRVR lpsrvr;
UNREFERENCED_PARAMETER(lpstr);
lpsrvr = (LPSRVR)GetWindowLongPtr (hwnd, 0);
// If the client already died, no terminate.
if (IsWindowValid ((HWND)hdata)) { lpsrvr->termNo++;
// irrespective of the post, incremet the count, so
// that client does not die.
PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, (WPARAM)hwnd, (LPARAM)0); } else ASSERT (FALSE, "TERMINATE: Client's System chanel is missing");
return TRUE; }
LRESULT FAR PASCAL SrvrWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ){
LPSRVR lpsrvr; WORD status = 0; HANDLE hdata; OLESTATUS retval;
if (AddMessage (hwnd, msg, wParam, lParam, WT_SRVR)) return 0L;
lpsrvr = (LPSRVR)GetWindowLongPtr (hwnd, 0);
switch (msg){
case WM_TIMER: UnblockPostMsgs (hwnd, FALSE);
// if no more blocked message empty the queue.
if (IsBlockQueueEmpty (hwnd)) KillTimer (hwnd, wParam);
if (lpsrvr->bTerminate && IsBlockQueueEmpty(lpsrvr->hwnd)) // Now see wheteher we can release the server .
ReleaseSrvr (lpsrvr); break;
case WM_CREATE: DEBUG_OUT ("Srvr create window", 0) break;
case WM_DDE_INITIATE: DEBUG_OUT ("Srvr: DDE init",0); if (lpsrvr->bTerminate){ DEBUG_OUT ("Srvr: No action due to termination process",0) break; }
// class is not matching, so it is not definitely for us.
// for apps sending the EXE for initiate, do not allow if the app
// is mutiple server.
if (!(lpsrvr->aClass == (ATOM)(LOWORD(lParam)) || (lpsrvr->aExe == (ATOM)(LOWORD(lParam)) && IsSingleServerInstance ())))
break;
if (!HandleInitMsg (lpsrvr, lParam)) { if (!(aSysTopic == (ATOM)(HIWORD(lParam)))) {
// if the server window is not the right window for
// DDE conversation, then try with the doc windows.
SendMsgToChildren (hwnd, msg, wParam, lParam);
} break; }
// We can enterain this client. Put him in our client list
// and acknowledge the intiate.
if (!AddClient (hwnd, (HWND)wParam, (HWND)wParam)) break;
lpsrvr->cClients++; lpsrvr->bnoRelease = FALSE; // add the atoms and post acknowledge
DuplicateAtom (LOWORD(lParam)); DuplicateAtom (HIWORD(lParam));
SendMessage ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lParam); break;
case WM_DDE_EXECUTE: { HANDLE hData = GET_WM_DDE_EXECUTE_HDATA(wParam,lParam);
DEBUG_OUT ("srvr: execute", 0)
// Are we terminating
if (lpsrvr->bTerminate) { DEBUG_OUT ("Srvr: sys execute after terminate posted",0) // !!! are we supposed to free the data
GlobalFree (hData); break; }
retval = SrvrExecute (hwnd, hData, (HWND)wParam); SET_MSG_STATUS (retval, status)
if (!lpsrvr->bTerminate) { LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,status,hData);
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd, lparamNew)) { GlobalFree (hData); DDEFREE(WM_DDE_ACK,lparamNew); } }
break; }
case WM_DDE_TERMINATE: DEBUG_OUT ("Srvr: DDE terminate",0)
DeleteClient (lpsrvr->hwnd, (HWND)wParam); lpsrvr->cClients--;
if (lpsrvr->bTerminate){ if ((--lpsrvr->termNo == 0) && (IsBlockQueueEmpty (lpsrvr->hwnd))) // Now see wheteher we can release the server .
ReleaseSrvr (lpsrvr);
// if we released the server, then
// by the time we come here,, we have destroyed the window
}else { // If client intiated the terminate. post matching terminate
PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, (LPARAM)0);
// callback release tell the srvr app, it can exit if needs.
// Inform server app it is time to clean up and post WM_QUIT.
// only if no docs present.
#if 0
if (lpsrvr->cClients == 0 && (GetWindow (lpsrvr->hwnd, GW_CHILD) == NULL)) { #endif
if (QueryRelease (lpsrvr)){
(*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr); } } break;
case WM_DDE_REQUEST: { ATOM aItem = GET_WM_DDE_REQUEST_ITEM(wParam,lParam);
if (lpsrvr->bTerminate || !IsWindowValid ((HWND) wParam)) goto RequestErr;
if(RequestDataStd (lParam, (HANDLE FAR *)&hdata) != OLE_OK){ LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_ACK,0x8000, aItem);
// if request failed, then acknowledge with error.
if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, (WPARAM)hwnd,lparamNew)) { DDEFREE(WM_DDE_ACK,lparamNew); RequestErr: if (aItem) GlobalDeleteAtom (aItem); } } else { // post the data message and we are not asking for any
// acknowledge.
LPARAM lparamNew = MAKE_DDE_LPARAM(WM_DDE_REQUEST,hdata,aItem);
if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, (WPARAM)hwnd, lparamNew)) { GlobalFree (hdata); DDEFREE(WM_DDE_REQUEST,lparamNew); goto RequestErr; } } break; }
case WM_DESTROY: DEBUG_OUT ("Srvr: Destroy window",0) break;
default: DEBUG_OUT ("Srvr: Default message",0) return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0L;
}
BOOL INTERNAL HandleInitMsg ( LPSRVR lpsrvr, LPARAM lParam ){
// If it is not system or Ole, this is not the server.
if (!((aSysTopic == (ATOM)(HIWORD(lParam))) || (aOLE == (ATOM)(HIWORD(lParam)))))
return FALSE;
// single instance MDI accept
if (lpsrvr->useFlags == OLE_SERVER_SINGLE) return TRUE;
// this server is multiple instance. So, check for any clients or docs.
if (!GetWindow (lpsrvr->hwnd, GW_CHILD) && !lpsrvr->cClients) return TRUE;
return FALSE;
}
// AddClient: Adds the client as property to the server
// window. Key is the string generated from the window
// handle and the data is the window itself.
BOOL INTERNAL AddClient ( HWND hwnd, HANDLE hkey, HANDLE hdata ){ char buf[20];
MapToHexStr ((LPSTR)buf, hkey); return SetProp (hwnd, (LPSTR)buf, hdata);
}
//DeleteClient: deletes the client from the server clients list.
BOOL INTERNAL DeleteClient ( HWND hwnd, HANDLE hkey ){ char buf[20];
MapToHexStr ((LPSTR)buf, hkey); return (RemoveProp(hwnd, (LPSTR)buf)!= NULL); }
// FindClient: Finds whether a given client is
// in the server client list.
HANDLE INTERNAL FindClient ( HWND hwnd, HANDLE hkey ){
char buf[20];
MapToHexStr ((LPSTR)buf, hkey); return GetProp (hwnd, (LPSTR)buf); }
// SrvrExecute: takes care of the WM_DDE_EXEXCUTE for the
// server.
OLESTATUS INTERNAL SrvrExecute ( HWND hwnd, HANDLE hdata, HWND hwndClient ){ ATOM aCmd; BOOL fActivate;
LPSTR lpdata = NULL; HANDLE hdup = NULL; OLESTATUS retval = OLE_ERROR_MEMORY;
LPSTR lpdocname; LPSTR lptemplate;
LPOLESERVERDOC lpoledoc = NULL; LPDOC lpdoc = NULL; LPSRVR lpsrvr; LPOLESERVER lpolesrvr; LPSTR lpnextarg; LPSTR lpclassname; LPSTR lpitemname; LPSTR lpopt; char buf[MAX_STR]; WORD wCmdType;
// !!! this code can be lot simplified if we do the argument scanning
// seperately and return the ptrs to the args. Rewrite later on.
if (!(hdup = DuplicateData (hdata))) goto errRtn;
if (!(lpdata = GlobalLock (hdup))) goto errRtn;
DEBUG_OUT (lpdata, 0)
lpsrvr = (LPSRVR)GetWindowLongPtr (hwnd, 0);
lpolesrvr = lpsrvr->lpolesrvr;
if (*lpdata++ != '[') // commands start with the left sqaure bracket
goto errRtn;
retval = OLE_ERROR_SYNTAX; // scan upto the first arg
if (!(wCmdType = ScanCommand (lpdata, WT_SRVR, &lpdocname, &aCmd))) goto errRtn;
if (wCmdType == NON_OLE_COMMAND) { if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE)) retval = OLE_ERROR_PROTOCOL; else { retval = (*lpolesrvr->lpvtbl->Execute) (lpolesrvr, hdata); }
goto errRtn1; }
if (aCmd == aStdExit){ if (*lpdocname) goto errRtn1;
lpsrvr->fAckExit = TRUE; lpsrvr->hwndExit = hwndClient; lpsrvr->hDataExit = hdata; retval = (*lpolesrvr->lpvtbl->Exit) (lpolesrvr); lpsrvr->fAckExit = FALSE; goto end2; }
// scan the next argument.
if (!(lpnextarg = ScanArg(lpdocname))) goto errRtn;
//////////////////////////////////////////////////////////////////////////
//
// [StdShowItem("docname", "itemname"[, "true"])]
//
//////////////////////////////////////////////////////////////////////////
if (aCmd == aStdShowItem) {
// first find the documnet. If the doc does not exist, then
// blow it off.
if (!(lpdoc = FindDoc (lpsrvr, lpdocname))) goto errRtn1;
lpitemname = lpnextarg;
if( !(lpopt = ScanArg(lpitemname))) goto errRtn1;
// scan for the optional parameter
// Optional can be only TRUE or FALSE.
fActivate = FALSE; if (*lpopt) {
if( !(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate))) goto errRtn1;
if (*lpnextarg) goto errRtn1;
}
// scan it. But, igonre the arg.
retval = DocShowItem (lpdoc, lpitemname, !fActivate); goto end2;
}
//////////////////////////////////////////////////////////////////////////
//
// [StdCloseDocument ("docname")]
//
//////////////////////////////////////////////////////////////////////////
if (aCmd == aStdClose) { if (!(lpdoc = FindDoc (lpsrvr, lpdocname))) goto errRtn1;
if (*lpnextarg) goto errRtn1;
retval = (*lpdoc->lpoledoc->lpvtbl->Close)(lpdoc->lpoledoc); goto end2; }
if (aCmd == aStdOpen) { // find if any document is already open.
// if the doc is open, then no need to call srvr app.
if (FindDoc (lpsrvr, lpdocname)){ retval = OLE_OK; goto end1;
} }
if (aCmd == aStdCreate || aCmd == aStdCreateFromTemplate) { lpclassname = lpdocname; lpdocname = lpnextarg; if( !(lpnextarg = ScanArg(lpdocname))) goto errRtn1;
}
// check whether we can create/open more than one doc.
if ((lpsrvr->useFlags == OLE_SERVER_MULTI) && GetWindow (lpsrvr->hwnd, GW_CHILD)) goto errRtn;
// No Doc. register the document. lpoledoc is being probed
// for validity. So, pass some writeable ptr. It is not
// being used to access anything yet
if (OleRegisterServerDoc ((LHSRVR)lpsrvr, lpdocname, (LPOLESERVERDOC)NULL, (LHDOC FAR *)&lpdoc)) goto errRtn;
//////////////////////////////////////////////////////////////////////////
//
// [StdOpenDocument ("docname")]
//
//////////////////////////////////////////////////////////////////////////
// Documnet does not exit.
if(aCmd == aStdOpen) {
retval = (*lpolesrvr->lpvtbl->Open)(lpolesrvr, (LHDOC)lpdoc, lpdocname, (LPOLESERVERDOC FAR *) &lpoledoc); goto end; } else { lpdoc->fEmbed = TRUE; }
//////////////////////////////////////////////////////////////////////////
//
// [StdNewDocument ("classname", "docname")]
//
//////////////////////////////////////////////////////////////////////////
if (aCmd == aStdCreate) { retval = (*lpolesrvr->lpvtbl->Create) (lpolesrvr, (LHDOC)lpdoc, lpclassname, lpdocname, (LPOLESERVERDOC FAR *) &lpoledoc);
goto end; }
//////////////////////////////////////////////////////////////////////////
//
// [StdEditDocument ("docname")]
//
//////////////////////////////////////////////////////////////////////////
if (aCmd == aStdEdit){
GlobalGetAtomName (lpsrvr->aClass, (LPSTR)buf, MAX_STR);
retval = (*lpolesrvr->lpvtbl->Edit) (lpolesrvr, (LHDOC)lpdoc, (LPSTR)buf, lpdocname, (LPOLESERVERDOC FAR *) &lpoledoc); goto end; }
//////////////////////////////////////////////////////////////////////////
//
// [StdNewFormTemplate ("classname", "docname". "templatename)]
//
//////////////////////////////////////////////////////////////////////////
if (aCmd == aStdCreateFromTemplate){ lptemplate = lpnextarg; if(!(lpnextarg = ScanArg(lpnextarg))) goto errRtn;
retval = (*lpolesrvr->lpvtbl->CreateFromTemplate)(lpolesrvr, (LHDOC)lpdoc, lpclassname, lpdocname, lptemplate, (LPOLESERVERDOC FAR *) &lpoledoc);
goto end;
}
DEBUG_OUT ("Unknown command", 0);
end:
if (retval != OLE_OK) goto errRtn;
// Successful execute. remember the server app private doc handle here.
lpdoc->lpoledoc = lpoledoc;
end1: // make sure that the srg string is indeed terminated by
// NULL.
if (*lpnextarg) retval = OLE_ERROR_SYNTAX;
errRtn:
if ( retval != OLE_OK){ // delete the oledoc structure
if (lpdoc) OleRevokeServerDoc ((LHDOC)lpdoc); }
end2: errRtn1:
if (lpdata) GlobalUnlock (hdup);
if (hdup) GlobalFree (hdup);
if (retval == OLE_OK) lpsrvr->bnoRelease = TRUE;
return retval; }
void SendMsgToChildren ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ){
hwnd = GetWindow(hwnd, GW_CHILD); while (hwnd) { SendMessage (hwnd, msg, wParam, lParam); hwnd = GetWindow (hwnd, GW_HWNDNEXT); } }
OLESTATUS INTERNAL RequestDataStd ( LPARAM lparam, LPHANDLE lphdde ){
char buf[MAX_STR]; ATOM item; HANDLE hnew = NULL;
if (!(item = (ATOM)(HIWORD (lparam)))) goto errRtn;
GlobalGetAtomName (item, (LPSTR)buf, MAX_STR);
if (item == aEditItems){ hnew = MakeGlobal ((LPSTR)"StdHostNames\tStdDocDimensions\tStdTargetDevice"); goto PostData;
}
if (item == aProtocols) { hnew = MakeGlobal ((LPSTR)"Embedding\tStdFileEditing"); goto PostData; }
if (item == aTopics) { hnew = MakeGlobal ((LPSTR)"Doc"); goto PostData; }
if (item == aFormats) { hnew = MakeGlobal ((LPSTR)"Picture\tBitmap"); goto PostData; }
if (item == aStatus) { hnew = MakeGlobal ((LPSTR)"Ready"); goto PostData; }
// format we do not understand.
goto errRtn;
PostData:
// Duplicate the DDE data
if (MakeDDEData (hnew, CF_TEXT, lphdde, TRUE)){ // !!! why are we duplicating the atom.
DuplicateAtom ((ATOM)(HIWORD (lparam))); return OLE_OK; } errRtn: return OLE_ERROR_MEMORY; }
BOOL INTERNAL QueryRelease ( LPSRVR lpsrvr ){
HWND hwnd; LPDOC lpdoc;
// Incase the terminate is called immediately after
// the Std at sys level clear this.
if (lpsrvr->bnoRelease) { lpsrvr->bnoRelease = FALSE; return FALSE; }
if (lpsrvr->cClients) return FALSE;
hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
// if either the server or the doc has any clients
// return FALSE;
while (hwnd){ lpdoc = (LPDOC)GetWindowLongPtr (hwnd, 0); if (lpdoc->cClients) return FALSE;
hwnd = GetWindow (hwnd, GW_HWNDNEXT); } return TRUE;
}
//IsSingleServerInstance: returns true if the app is single server app else
//false.
BOOL INTERNAL IsSingleServerInstance () { HWND hwnd; WORD cnt = 0; HANDLE hTask; char buf[MAX_STR] = "";
hwnd = GetWindow (GetDesktopWindow(), GW_CHILD); hTask = (HANDLE)ULongToPtr(GetCurrentThreadId());
while (hwnd) { if (hTask == GetWindowTask (hwnd)) { if (GetClassName (hwnd, (LPSTR)buf, MAX_STR)) { if (lstrcmp ((LPSTR)buf, SRVR_CLASS) == 0) cnt++; } } hwnd = GetWindow (hwnd, GW_HWNDNEXT); }
if (cnt == 1) return TRUE; else return FALSE;
}
|