|
|
/****************************** Module Header ******************************\
* Module Name: Item.c Object(item) main module * * Purpose: Includes All the object releated routiens. * * Created: Oct 1990. * * Copyright (c) 1990, 1991 Microsoft Corporation * * History: * Raor (../10/1990) Designed, coded * * \***************************************************************************/
#include "cmacs.h"
#include "windows.h"
#include "ole.h"
#include "dde.h"
#include "srvr.h"
extern HANDLE hdllInst; extern FARPROC lpFindItemWnd; extern FARPROC lpItemCallBack; extern FARPROC lpSendDataMsg; extern FARPROC lpSendRenameMsg; extern FARPROC lpDeleteClientInfo; extern FARPROC lpEnumForTerminate;
extern ATOM cfNative; extern ATOM cfBinary; extern ATOM aClose; extern ATOM aChange; extern ATOM aSave; extern ATOM aEditItems; extern ATOM aStdDocName;
extern WORD cfLink; extern WORD cfOwnerLink;
extern BOOL bWin30;
HWND hwndItem; HANDLE hddeRename; HWND hwndRename;
WORD enummsg; WORD enuminfo; LPOLEOBJECT enumlpoleobject; OLECLIENTVTBL clVtbl; BOOL bClientUnlink;
BOOL fAdviseSaveDoc; BOOL fAdviseSaveItem;
char * stdStrTable[STDHOSTNAMES+1] = {NULL, "StdTargetDevice", "StdDocDimensions", "StdColorScheme", "StdHostNames"};
extern HANDLE (FAR PASCAL *lpfnSetMetaFileBitsBetter) (HANDLE);
void ChangeOwner (HANDLE hmfp);
// !!!change child enumeration.
// !!!No consistency in errors (Sometimes Bools and sometimes OLESTATUS).
//SearchItem: Searches for a given item in a document tree.
//If found, returns the corresponding child windows handle.
HWND INTERNAL SearchItem (lpdoc, lpitemname) LPDOC lpdoc; LPSTR lpitemname; { ATOM aItem;
Puts ("SearchItem");
// If the item passed is an atom, get its name.
if (!HIWORD(lpitemname)) aItem = (ATOM) (LOWORD((DWORD)lpitemname)); else if (!lpitemname[0]) aItem = NULL; else aItem = GlobalFindAtom (lpitemname);
hwndItem = NULL;
// !!! We should avoid hwndItem static. It should not cause
// any problems since while enumerating we will not be calling
// any window procs or no PostMessages are entertained.
EnumChildWindows (lpdoc->hwnd, lpFindItemWnd, MAKELONG (aItem, ITEM_FIND));
return hwndItem;
}
// FindItem: Given the itemname and the document handle,
// searches for the the item (object) in the document tree.
// Items are child windows for the document window.
// !!! change the child windows to somekind of
// linked lists at the item level. This will free up
// the space taken by the item windows.
int INTERNAL FindItem (lpdoc, lpitemname, lplpclient) LPDOC lpdoc; LPSTR lpitemname; LPCLIENT FAR * lplpclient; { LPCLIENT lpclient; HWND hwnd; char buf[MAX_STR];
Puts ("FindItem");
hwnd = SearchItem (lpdoc, lpitemname);
if (!HIWORD(lpitemname)){ if (LOWORD(lpitemname)) GlobalGetAtomName ((ATOM)LOWORD((DWORD)lpitemname), (LPSTR)buf, MAX_STR); else buf[0] = NULL;
lpitemname = (LPSTR)buf; }
if (hwnd) { // we found the item window
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
#ifdef FIREWALLS
ASSERT ((CheckPointer(lpclient, WRITE_ACCESS)), "In Item the client handle missing") ASSERT ((CheckPointer(lpclient->lpoleobject, WRITE_ACCESS)), "In Item object handle missing")
#endif
*lplpclient = lpclient; return OLE_OK;
}
// Item (object)window is not create yet. Let us create one.
return RegisterItem ((LHDOC)lpdoc, lpitemname, lplpclient, TRUE); }
//RegisterItem: Given the document handle and the item string
//creates item with the given document.
int INTERNAL RegisterItem (lhdoc, lpitemname, lplpclient, bSrvr) LHDOC lhdoc; LPSTR lpitemname; LPCLIENT FAR * lplpclient; BOOL bSrvr; {
LPDOC lpdoc; HANDLE hclient = NULL; LPCLIENT lpclient = NULL; int retval = OLE_ERROR_MEMORY; LPOLESERVERDOC lpoledoc; LPOLEOBJECT lpoleobject = NULL;
Puts ("CreateItem");
lpdoc = (LPDOC)lhdoc;
#ifdef FIREWALLS
ASSERT ((CheckPointer (lplpclient, WRITE_ACCESS)), "invalid lplpclient"); #endif
// First create the callback client structure.
hclient = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (CLIENT)); if(!(hclient && (lpclient = (LPCLIENT)GlobalLock (hclient)))) goto errRtn;
lpclient->hclient = hclient; hclient = NULL;
if (!HIWORD(lpitemname)) { ASSERT (!bSrvr, "invalid lpitemname in RegisterItem\n"); lpclient->aItem = LOWORD((DWORD)lpitemname); } else if (!lpitemname[0]) lpclient->aItem = NULL; else lpclient->aItem = GlobalAddAtom (lpitemname);
lpclient->oleClient.lpvtbl = &clVtbl; lpclient->oleClient.lpvtbl->CallBack = (int (CALLBACK *)(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT))lpItemCallBack;
lpoledoc = lpdoc->lpoledoc;
// Call the server app to create its own object structure and link
// it to the given document.
// Call the server if the item is not one of the standard items.
if (bSrvr) { retval = (*lpoledoc->lpvtbl->GetObject)(lpoledoc, lpitemname, (LPOLEOBJECT FAR *)&lpoleobject, (LPOLECLIENT)lpclient); if (retval != OLE_OK) goto errRtn; }
lpclient->lpoleobject = lpoleobject;
lpclient->hwnd = CreateWindow ("ItemWndClass", "ITEM", WS_CHILD,0,0,0,0,lpdoc->hwnd,NULL, hdllInst, NULL);
if (lpclient->hwnd == NULL) goto errRtn;
// save the ptr to the item in the window.
SetWindowLong (lpclient->hwnd, 0, (LONG)lpclient); *lplpclient = lpclient; return OLE_OK;
errRtn:
if (lpclient) RevokeObject ((LPOLECLIENT)lpclient, FALSE);
else { if(hclient) GlobalFree (hclient); }
return retval;
}
OLESTATUS FAR PASCAL OleRevokeObject (lpoleclient) LPOLECLIENT lpoleclient; { return RevokeObject (lpoleclient, TRUE);
} // OleRevokeObject: Revokes an object (unregisres an object
// from the document tree.
OLESTATUS INTERNAL RevokeObject (lpoleclient, bUnlink) LPOLECLIENT lpoleclient; BOOL bUnlink; {
HANDLE hclient; LPCLIENT lpclient;
lpclient = (LPCLIENT)lpoleclient;
PROBE_WRITE(lpoleclient); if (lpclient->lpoleobject) { // first call the object for deletetion.
#ifdef FIREWALLS
if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBECT")
if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT(lpclient->lpoleobject->lpvtbl->Release, "Invalid pointer to Release method") #endif
(*lpclient->lpoleobject->lpvtbl->Release)(lpclient->lpoleobject);
}
if (ISATOM(lpclient->aItem)) { GlobalDeleteAtom (lpclient->aItem); lpclient->aItem = NULL; }
if (lpclient->hwnd) { SetWindowLong (lpclient->hwnd, 0, (LONG)NULL);
// another static for enumerating the properties.
// we need to change these .
bClientUnlink = bUnlink;
EnumProps(lpclient->hwnd, lpDeleteClientInfo); // post all the messages with yield which have been collected in enum
// UnblockPostMsgs (lpclient->hwnd, FALSE);
DestroyWindow (lpclient->hwnd); }
GlobalUnlock (hclient = lpclient->hclient); GlobalFree (hclient); return OLE_OK;
}
BOOL FAR PASCAL DeleteClientInfo (hwnd, lpstr, hclinfo) HWND hwnd; LPSTR lpstr; HANDLE hclinfo; { PCLINFO pclinfo = NULL; HWND hwndDoc; LPDOC lpdoc;
#ifdef FIREWALLS
ASSERT (hclinfo, "Client info null in item property list"); #endif
// delete the printer dev info block
if(pclinfo = (PCLINFO)LocalLock (hclinfo)){ if(pclinfo->hdevInfo) GlobalFree (pclinfo->hdevInfo);
if (bClientUnlink) { // terminate the conversation for the client.
TerminateDocClients ((hwndDoc = GetParent(hwnd)), NULL, pclinfo->hwnd); lpdoc = (LPDOC)GetWindowLong (hwndDoc, 0); // for some reason this delete is gving circular lists for properties
//DeleteClient (hwndDoc, pclinfo->hwnd);
//lpdoc->cClients--;
} LocalUnlock (hclinfo); } LocalFree (hclinfo); RemoveProp (hwnd, lpstr); return TRUE; }
// Call back for the Object windows numeration. data field
// has the command and the extra information
BOOL FAR PASCAL FindItemWnd (hwnd, data) HWND hwnd; LONG data; {
LPCLIENT lpclient; int cmd; HANDLE hclinfo; PCLINFO pclinfo;
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
#ifdef FIREWALLS
// ASSERT (lpclient, "In Item the client handle missing")
#endif
cmd = HIWORD(data); switch (cmd) { case ITEM_FIND: if (lpclient->aItem == (ATOM)(LOWORD (data))) { // we found the window we required. Remember the
// object window.
hwndItem = hwnd; return FALSE; // terminate enumeration.
} break;
case ITEM_SAVED: if (lpclient->lpoleobject) { if (ItemCallBack ((LPOLECLIENT) lpclient, OLE_SAVED, lpclient->lpoleobject) == OLE_ERROR_CANT_UPDATE_CLIENT) fAdviseSaveDoc = FALSE; } break;
case ITEM_DELETECLIENT:
// delete the client from our list if we have one
hclinfo = FindClient (hwnd, (HWND) (LOWORD(data))); if (hclinfo){ // delete the printer dev info block
if(pclinfo = (PCLINFO)LocalLock (hclinfo)){ if(pclinfo->hdevInfo) GlobalFree (pclinfo->hdevInfo); LocalUnlock (hclinfo); } LocalFree (hclinfo); DeleteClient ( hwnd, (HWND) (LOWORD(data))); } break;
case ITEM_DELETE: // delete the client it self.
RevokeObject ((LPOLECLIENT)lpclient, FALSE); break;
} return TRUE; // continue enumeration.
}
//DeleteFromItemsList: Deletes a client from the object lists of
//all the objects of a given document. Thie client possibly
//is terminating the conversation with our doc window.
void INTERNAL DeleteFromItemsList (hwndDoc, hwndClient) HWND hwndDoc; HWND hwndClient; {
EnumChildWindows (hwndDoc, lpFindItemWnd, MAKELONG (hwndClient, ITEM_DELETECLIENT));
}
// DeleteAllItems: Deletes all the objects of a given
// document window.
void INTERNAL DeleteAllItems (hwndDoc) HWND hwndDoc; {
EnumChildWindows (hwndDoc, lpFindItemWnd, MAKELONG (NULL, ITEM_DELETE));
}
// Object widnow proc:
long FAR PASCAL ItemWndProc(hwnd, msg, wParam, lParam) HWND hwnd; WORD msg; WORD wParam; LONG lParam; {
LPCLIENT lpclient;
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
switch (msg) { case WM_DESTROY: DEBUG_OUT("Item: Destroy window",0)
#ifdef FIREWALLS
ASSERT (!lpclient, "while destroy Item client is not null") #endif
break; default: DEBUG_OUT("item: Default message",0) return DefWindowProc (hwnd, msg, wParam, lParam);
} return 0L;
}
// PokeData: Prepares and gives the data to the server app thru
// the SetData object method.
OLESTATUS INTERNAL PokeData (lpdoc, hwndClient, lparam) LPDOC lpdoc; HWND hwndClient; LONG lparam; { int retval = OLE_ERROR_MEMORY; LPCLIENT lpclient; DDEPOKE FAR * lpPoke = NULL; HANDLE hPoke = NULL; HANDLE hnew = NULL; int format; BOOL fRelease = FALSE;
// Get the object handle first. Look in the registration
// tree and if one is not created otherwise create one.
retval = FindItem (lpdoc, (LPSTR) MAKEINTATOM(HIWORD(lparam)), (LPCLIENT FAR *)&lpclient);
if (retval != OLE_OK) goto errRtn;
hPoke = (HANDLE)(LOWORD (lparam)); if(!(hPoke && (lpPoke = (DDEPOKE FAR *) GlobalLock (hPoke)))) goto errRtn;
GlobalUnlock (hPoke);
format = lpPoke->cfFormat; fRelease = lpPoke->fRelease;
// We found the item. Now prepare the data to be given to the object
if (!(hnew = MakeItemData (lpPoke, hPoke, format))) goto errRtn;
// Now send the data to the object
#ifdef FIREWALLS
if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (lpclient->lpoleobject->lpvtbl->SetData, "Invalid pointer to SetData method") #endif
retval = (*lpclient->lpoleobject->lpvtbl->SetData) (lpclient->lpoleobject, format, hnew);
// We free the data if server returns OLE_ERROR_SETDATA_FORMAT.
// Otherwise server must've deleted it.
if (retval == OLE_ERROR_SETDATA_FORMAT) { if (!FreeGDIdata (hnew, format)) GlobalFree (hnew); }
errRtn: if (retval == OLE_OK && fRelease) { if (hPoke) GlobalFree (hPoke); }
return retval; }
OLESTATUS INTERNAL UnAdviseData (lpdoc, hwndClient, lparam) LPDOC lpdoc; HWND hwndClient; LONG lparam; {
char buf[MAX_STR]; int options; LPCLIENT lpclient; int retval = OLE_ERROR_MEMORY; HANDLE hclinfo = NULL; PCLINFO pclinfo = NULL;
if (!(HIWORD (lparam))) buf[0] = NULL; else GlobalGetAtomName ((ATOM)(HIWORD (lparam)), (LPSTR)buf, MAX_STR);
// Scan for the advise options like "Close", "Save" etc
// at the end of the item.
if((retval = ScanItemOptions ((LPSTR)buf, (int far *)&options)) != OLE_OK) goto errRtn;
if (buf[0] == NULL) { // Unadvise for null should terminate all the advises
DeleteFromItemsList (lpdoc->hwnd, hwndClient); return OLE_OK; }
// Now get the corresponding object.
retval = FindItem (lpdoc, (LPSTR)buf, (LPCLIENT FAR *)&lpclient); if (retval != OLE_OK) goto errRtn;
// Find the client structure to be attcahed to the object.
if ((hclinfo = FindClient (lpclient->hwnd, hwndClient)) == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL ){ retval = OLE_ERROR_MEMORY; goto errRtn; }
pclinfo->options &= (~(0x0001 << options));
errRtn: if (pclinfo) LocalUnlock (hclinfo); return retval;
}
// AdviseStdItems: This routine takes care of the DDEADVISE for a
//particular object in given document. Creates a client strutcure
//and attaches to the property list of the object window.
OLESTATUS INTERNAL AdviseStdItems (lpdoc, hwndClient, lparam, lpfack) LPDOC lpdoc; HWND hwndClient; LONG lparam; BOOL FAR * lpfack; {
HANDLE hopt = NULL; DDEADVISE FAR *lpopt; OLESTATUS retval = OLE_ERROR_MEMORY;
hopt = (HANDLE) (LOWORD (lparam)); if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt))) goto errrtn;
#ifdef FIREWALLS
ASSERT ((ATOM) (HIWORD (lparam) == aStdDocName), "AdviseStdItem is not Documentname"); #endif
*lpfack = lpopt->fAckReq; retval = SetStdInfo (lpdoc, hwndClient, (LPSTR)"StdDocumentName", NULL);
if (lpopt) GlobalUnlock (hopt);
errrtn:
if (retval == OLE_OK) // !!! make sure that we have to free the data for error case
GlobalFree (hopt); return retval; }
//AdviseData: This routine takes care of the DDEADVISE for a
//particular object in given document. Creates a client strutcure
//and attaches to the property list of the object window.
OLESTATUS INTERNAL AdviseData (lpdoc, hwndClient, lparam, lpfack) LPDOC lpdoc; HWND hwndClient; LONG lparam; BOOL FAR * lpfack; {
HANDLE hopt = NULL; DDEADVISE FAR *lpopt = NULL; int format = NULL; char buf[MAX_STR]; int options; LPCLIENT lpclient; int retval = OLE_ERROR_MEMORY; HANDLE hclinfo = NULL; PCLINFO pclinfo = NULL;
hopt = (HANDLE) (LOWORD (lparam)); if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt))) goto errRtn;
if (!(HIWORD (lparam))) buf[0] = NULL; else GlobalGetAtomName ((ATOM)(HIWORD (lparam)), (LPSTR)buf, MAX_STR);
// Scan for the advise options like "Close", "Save" etc
// at the end of the item.
if((retval = ScanItemOptions ((LPSTR)buf, (int far *)&options)) != OLE_OK) goto errRtn;
// Now get the corresponding object.
retval = FindItem (lpdoc, (LPSTR)buf, (LPCLIENT FAR *)&lpclient); if (retval != OLE_OK) goto errRtn;
if (!IsFormatAvailable (lpclient, lpopt->cfFormat)){ retval = OLE_ERROR_DATATYPE; // this format is not supported;
goto errRtn; }
*lpfack = lpopt->fAckReq;
// Create the client structure to be attcahed to the object.
if (!(hclinfo = FindClient (lpclient->hwnd, hwndClient))) hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL){ retval = OLE_ERROR_MEMORY; goto errRtn; }
// Remember the client window (Needed for sending DATA later on
// when the data change message comes from the server)
pclinfo->hwnd = hwndClient; if (lpopt->cfFormat == (int)cfNative) pclinfo->bnative = TRUE; else pclinfo->format = lpopt->cfFormat;
// Remeber the data transfer options.
pclinfo->options |= (0x0001 << options); pclinfo->bdata = !lpopt->fDeferUpd; LocalUnlock (hclinfo); pclinfo = NULL;
// if the entry exists already, delete it.
DeleteClient (lpclient->hwnd, hwndClient);
// Now add this client to item client list
// !!! This error recovery is not correct.
if(!AddClient (lpclient->hwnd, hwndClient, hclinfo)) goto errRtn;
errRtn: if (lpopt) GlobalUnlock (hopt);
if (pclinfo) LocalUnlock (hclinfo);
if (retval == OLE_OK) { // !!! make sure that we have to free the data
GlobalFree (hopt);
}else { if (hclinfo) LocalFree (hclinfo); } return retval;
}
BOOL INTERNAL IsFormatAvailable (lpclient, cfFormat) LPCLIENT lpclient; OLECLIPFORMAT cfFormat; { OLECLIPFORMAT cfNext = 0;
do{
#ifdef FIREWALLS
if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBECT") else if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (lpclient->lpoleobject->lpvtbl->EnumFormats, "Invalid pointer to EnumFormats method") #endif
cfNext = (*lpclient->lpoleobject->lpvtbl->EnumFormats) (lpclient->lpoleobject, cfNext); if (cfNext == cfFormat) return TRUE;
}while (cfNext != 0);
return FALSE; }
//ScanItemOptions: Scan for the item options like Close/Save etc.
OLESTATUS INTERNAL ScanItemOptions (lpbuf, lpoptions) LPSTR lpbuf; int far *lpoptions; {
ATOM aModifier;
*lpoptions = OLE_CHANGED; while ( *lpbuf && *lpbuf != '/') { #if defined(FE_SB) //[J1]
lpbuf = AnsiNext( lpbuf ); //[J1]
#else //[J1]
lpbuf++; #endif
} //[J1]
// no modifier same as /change
if (*lpbuf == NULL) return OLE_OK;
*lpbuf++ = NULL; // seperate out the item string
// We are using this in the caller.
if (!(aModifier = GlobalFindAtom (lpbuf))) return OLE_ERROR_SYNTAX;
if (aModifier == aChange) return OLE_OK;
// Is it a save?
if (aModifier == aSave){ *lpoptions = OLE_SAVED; return OLE_OK; } // Is it a Close?
if (aModifier == aClose){ *lpoptions = OLE_CLOSED; return OLE_OK; }
// unknow modifier
return OLE_ERROR_SYNTAX;
}
//RequestData: Sends data in response to a DDE Request message.
// for agiven doc and an object.
OLESTATUS INTERNAL RequestData (lpdoc, hwndClient, lparam, lphdde) LPDOC lpdoc; HWND hwndClient; LONG lparam; LPHANDLE lphdde; {
OLESTATUS retval = OLE_OK; HANDLE hdata; LPCLIENT lpclient; char buf[6];
// If edit environment Send data if we can
if ((HIWORD (lparam)) == aEditItems) return RequestDataStd (lparam, lphdde);
// Get the object.
retval = FindItem (lpdoc, (LPSTR) MAKEINTATOM(HIWORD(lparam)), (LPCLIENT FAR *)&lpclient); if (retval != OLE_OK) goto errRtn;
retval = OLE_ERROR_DATATYPE; if (!IsFormatAvailable (lpclient, (int)(LOWORD (lparam)))) goto errRtn;
// Now ask the item for the given format data
#ifdef FIREWALLS
ASSERT (lpclient->lpoleobject->lpvtbl->GetData, "Invalid pointer to GetData method") #endif
MapToHexStr ((LPSTR)buf, hwndClient); SendDevInfo (lpclient, (LPSTR)buf);
retval = (*lpclient->lpoleobject->lpvtbl->GetData) (lpclient->lpoleobject, (int)(LOWORD (lparam)), (LPHANDLE)& hdata);
if (retval != OLE_OK) goto errRtn;
if (LOWORD(lparam) == CF_METAFILEPICT) ChangeOwner (hdata);
// Duplicate the DDE data
if(MakeDDEData(hdata, (int)(LOWORD (lparam)), lphdde, TRUE)){ // !!! Why do we have to duplicate the atom
DuplicateAtom ((ATOM)(HIWORD (lparam))); return OLE_OK; } else return OLE_ERROR_MEMORY;
errRtn: return retval;
}
//MakeDDEData: Create a Global DDE data handle from the server
// app data handle.
BOOL INTERNAL MakeDDEData (hdata, format, lph, fResponse) HANDLE hdata; LPHANDLE lph; int format; BOOL fResponse; { DWORD size; HANDLE hdde = NULL; DDEDATA FAR *lpdata= NULL; BOOL bnative; LPSTR lpdst; LPSTR lpsrc;
if (!hdata) { *lph = NULL; return TRUE; }
if (bnative = !(format == CF_METAFILEPICT || format == CF_DIB || format == CF_BITMAP)) size = GlobalSize (hdata) + sizeof (DDEDATA); else size = sizeof (LONG) + sizeof (DDEDATA);
hdde = (HANDLE) GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, size); if (hdde == NULL || (lpdata = (DDEDATA FAR *) GlobalLock (hdde)) == NULL) goto errRtn;
// set the data otions. Ask the client to delete
// it always.
lpdata->fRelease = TRUE; // release the data
lpdata->cfFormat = format; lpdata->fResponse = fResponse;
if (!bnative) // If not native, stick in the handle what the server gave us.
*(LPHANDLE)lpdata->Value = hdata;
else { // copy the native data junk here.
lpdst = (LPSTR)lpdata->Value; if(!(lpsrc = (LPSTR)GlobalLock (hdata))) goto errRtn;
size -= sizeof (DDEDATA); UtilMemCpy (lpdst, lpsrc, size); GlobalUnlock (hdata); GlobalFree (hdata);
}
GlobalUnlock (hdde); *lph = hdde; return TRUE;
errRtn: if (lpdata) GlobalUnlock (hdde);
if (hdde) GlobalFree (hdde);
if (bnative) GlobalFree (hdata);
return FALSE; }
// ItemCallback: Calback routine for the server to inform the
// data changes. When the change message is received, DDE data
// message is sent to each of the clients depending on the
// options.
int FAR PASCAL ItemCallback (lpoleclient, msg, lpoleobject) LPOLECLIENT lpoleclient; WORD msg; // notification message
LPOLEOBJECT lpoleobject; {
LPCLIENT lpclient; int retval = OLE_OK; HANDLE hdata = NULL; LPSTR lpdata = NULL; LPDOC lpdoc; HWND hStdWnd;
lpclient = (LPCLIENT)lpoleclient; lpdoc = (LPDOC)GetWindowLong (GetParent (lpclient->hwnd), 0);
if (msg == OLE_RENAMED) { #ifdef FIREWALLS
if (!CheckPointer (lpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid lpoleobject") else if (!CheckPointer (lpoleobject->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (lpoleobject->lpvtbl->GetData, "Invalid pointer to GetData method") #endif
if (IsFormatAvailable (lpclient, cfLink)) {
// Get the link data.
retval = (*lpoleobject->lpvtbl->GetData) (lpoleobject, (int)cfLink, (LPHANDLE)&hdata); } else { if(IsFormatAvailable (lpclient, cfOwnerLink)) {
// Get the link data.
retval = (*lpoleobject->lpvtbl->GetData) (lpoleobject, (int)cfOwnerLink, (LPHANDLE)& hdata); #ifdef FIREWALLS
ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY") #endif
} else retval = OLE_ERROR_DATATYPE; }
if (retval != OLE_OK) goto errrtn;
if (!(lpdata = (LPSTR)GlobalLock (hdata))) goto errrtn;
if (lpdoc->aDoc) { GlobalDeleteAtom (lpdoc->aDoc); lpdoc->aDoc = NULL; }
// Move the string to the beginning and still terminated by null;
lstrcpy (lpdata, lpdata + lstrlen (lpdata) + 1); lpdoc->aDoc = GlobalAddAtom (lpdata);
// Now make the DDE data block
GlobalUnlock (hdata); lpdata = NULL;
// find if any StdDocName item is present at all
if (!(hStdWnd = SearchItem (lpdoc, (LPSTR) MAKEINTATOM(aStdDocName)))) GlobalFree (hdata); else {
// hdata is freed by Makeddedata
if (!MakeDDEData (hdata, (int)cfBinary, (LPHANDLE)&hddeRename, FALSE)) { retval = OLE_ERROR_MEMORY; goto errrtn; }
EnumProps(hStdWnd, lpSendRenameMsg); // post all the messages with yield which have been collected in enum
// UnblockPostMsgs (hStdWnd, FALSE);
GlobalFree (hddeRename); }
// static. Avoid this. This may not cause any problems for now.
// if there is any better way, change it.
hwndRename = hStdWnd;
// Post termination for each of the doc clients.
EnumProps (lpdoc->hwnd, lpEnumForTerminate);
lpdoc->fEmbed = FALSE;
// post all the messages with yield which have been collected in enum
// UnblockPostMsgs (lpdoc->hwnd, FALSE);
return OLE_OK;
errrtn: if (lpdata) GlobalUnlock (hdata);
if (hdata) GlobalFree (hdata);
return retval;
} else {
// !!! any better way to do instead of putting in static
// (There may not be any problems since we are not allowing
// any messages to get thru while we are posting messages).
if ((enummsg = msg) == OLE_SAVED) fAdviseSaveItem = FALSE;
enumlpoleobject = lpoleobject;
#ifdef FIREWALLS
ASSERT (lpclient->hwnd && IsWindowValid (lpclient->hwnd), " Not valid object") #endif
// Enumerate all the clients and send DDE_DATA if necessary.
EnumProps(lpclient->hwnd, lpSendDataMsg); // post all the messages with yield which have been collected in enum
// UnblockPostMsgs (lpclient->hwnd, FALSE);
if ((msg == OLE_SAVED) && lpdoc->fEmbed && !fAdviseSaveItem) return OLE_ERROR_CANT_UPDATE_CLIENT;
return OLE_OK; } }
BOOL FAR PASCAL EnumForTerminate (hwnd, lpstr, hdata) HWND hwnd; LPSTR lpstr; HANDLE hdata; {
LPDOC lpdoc;
lpdoc = (LPDOC)GetWindowLong (hwnd , 0);
// This client is in the rename list. So, no terminate
if(hwndRename && FindClient (hwndRename, (HWND)hdata)) return TRUE;
if (PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, hwnd, NULL)) lpdoc->termNo++;
//DeleteClient (hwnd, (HWND)hdata);
//lpdoc->cClients--;
return TRUE; }
BOOL FAR PASCAL SendRenameMsg (hwnd, lpstr, hclinfo) HWND hwnd; LPSTR lpstr; HANDLE hclinfo; { ATOM aData = NULL; HANDLE hdde = NULL; PCLINFO pclinfo = NULL; HWND hwndClient;
if (!(pclinfo = (PCLINFO) LocalLock (hclinfo))) goto errrtn;
// Make the item atom with the options.
aData = DuplicateAtom (aStdDocName); hdde = DuplicateData (hddeRename);
hwndClient = pclinfo->hwnd; LocalUnlock (hclinfo);
// Post the message
if (!PostMessageToClientWithBlock (hwndClient, WM_DDE_DATA, (HWND)GetParent (hwnd), MAKELONG (hdde, aData))) goto errrtn;
return TRUE;
errrtn:
if (hdde) GlobalFree (hdde); if (aData) GlobalDeleteAtom (aData);
return TRUE;
}
//SendDataMsg: Send data to the clients, if the data change options
//match the data advise options.
BOOL FAR PASCAL SendDataMsg (hwnd, lpstr, hclinfo) HWND hwnd; LPSTR lpstr; HANDLE hclinfo; { PCLINFO pclinfo = NULL; HANDLE hdde = NULL; ATOM aData = NULL; int retval; HANDLE hdata; LPCLIENT lpclient;
if (!(pclinfo = (PCLINFO) LocalLock (hclinfo))) goto errRtn;
lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
#ifdef FIREWALLS
ASSERT ((CheckPointer(lpclient, WRITE_ACCESS)), "In Item the client handle missing") #endif
// if the client dead, then no message
if (!IsWindowValid(pclinfo->hwnd)) goto errRtn;
if (pclinfo->options & (0x0001 << enummsg)) { fAdviseSaveItem = TRUE; SendDevInfo (lpclient, lpstr);
// send message if the client needs data for every change or
// only for the selective ones he wants.
// now look for the data option.
if (pclinfo->bnative){ // prepare native data
if (pclinfo->bdata){
// Wants the data with DDE_DATA message
// Get native data from the server.
#ifdef FIREWALLS
if (!CheckPointer (enumlpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBECT") else if (!CheckPointer (enumlpoleobject->lpvtbl,WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (enumlpoleobject->lpvtbl->GetData, "Invalid pointer to GetData method") #endif
retval = (*enumlpoleobject->lpvtbl->GetData) (enumlpoleobject, (int)cfNative, (LPHANDLE)& hdata); #ifdef FIREWALLS
ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY"); #endif
if (retval != OLE_OK) goto errRtn;
// Prepare the DDE data block.
if(!MakeDDEData (hdata, (int)cfNative, (LPHANDLE)&hdde, FALSE)) goto errRtn;
}
// Make the item atom with the options.
aData = MakeDataAtom (lpclient->aItem, enummsg); // Post the message
if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA, (HWND)GetParent (hwnd), MAKELONG (hdde, aData))) goto errRtn; hdde = NULL; aData = NULL; }
// Now post the data for the disply format
if (pclinfo->format){ if (pclinfo->bdata){ #ifdef FIREWALLS
if (!CheckPointer (enumlpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBECT") else if (!CheckPointer (enumlpoleobject->lpvtbl,WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (enumlpoleobject->lpvtbl->GetData, "Invalid pointer to GetData method") #endif
retval = (*enumlpoleobject->lpvtbl->GetData) (enumlpoleobject, pclinfo->format, (LPHANDLE)& hdata);
#ifdef FIREWALLS
ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY"); #endif
if (retval != OLE_OK) goto errRtn;
if (pclinfo->format == CF_METAFILEPICT) ChangeOwner (hdata);
if(!MakeDDEData (hdata, pclinfo->format, (LPHANDLE)&hdde, FALSE)) goto errRtn;
}
// atom is deleted. So, we need to duplicate for every post
aData = MakeDataAtom (lpclient->aItem, enummsg); // now post the message to the client;
if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA, (HWND)GetParent (hwnd), MAKELONG (hdde, aData))) goto errRtn;
hdde = NULL; aData = NULL;
}
}
errRtn: if (pclinfo) LocalUnlock (hclinfo);
if (hdde) GlobalFree (hdde);
if (aData) GlobalDeleteAtom (aData);
return TRUE;
}
// IsAdviseStdItems: returns true if the item is one of the standard items
// StdDocName;
BOOL INTERNAL IsAdviseStdItems (aItem) ATOM aItem; {
if ( aItem == aStdDocName) return TRUE; else return FALSE; }
// GetStdItemIndex: returns index to Stditems in the "stdStrTable" if the item
// is one of the standard items StdHostNames, StdTargetDevice,
// StdDocDimensions, StdColorScheme
int INTERNAL GetStdItemIndex (aItem) ATOM aItem; { char str[MAX_STR];
if (!aItem) return NULL;
if (!GlobalGetAtomName (aItem, (LPSTR) str, MAX_STR)) return NULL;
if (!lstrcmpi (str, stdStrTable[STDTARGETDEVICE])) return STDTARGETDEVICE; else if (!lstrcmpi (str, stdStrTable[STDHOSTNAMES])) return STDHOSTNAMES; else if (!lstrcmpi (str, stdStrTable[STDDOCDIMENSIONS])) return STDDOCDIMENSIONS; else if (!lstrcmpi (str, stdStrTable[STDCOLORSCHEME])) return STDCOLORSCHEME;
return NULL; }
// PokeStdItems: Pokes the data for the standard items.
// For StdHostnames, StdDocDimensions and SetColorScheme the data is
// sent immediately and for the the StdTargetDeviceinfo the
// data is set in each client block and the data is sent just
// before the GetData call for rendering the right data.
OLESTATUS INTERNAL PokeStdItems (lpdoc, hwndClient, lparam) LPDOC lpdoc; HWND hwndClient; LONG lparam; { int index; DDEDATA FAR * lpdata = NULL; HANDLE hdata = NULL; HANDLE hnew = NULL; LPOLESERVERDOC lpoledoc; LPHOSTNAMES lphostnames; OLESTATUS retval = OLE_ERROR_MEMORY; int format; BOOL fRelease; RECT rcDoc;
index = HIWORD(lparam); hdata = (HANDLE)(LOWORD (lparam)); if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata)))) goto errRtn;
format = lpdata->cfFormat; fRelease = lpdata->fRelease;
#ifdef FIREWALSS
ASSERT (format == (int)cfBinary, "Format is not binary"); #endif
// we have extracted the data successfully.
lpoledoc = lpdoc->lpoledoc; #ifdef FIREWALLS
if (!CheckPointer (lpoledoc, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLESERVERDOC") else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLESERVERDOCVTBL") #endif
if (index == STDHOSTNAMES){ lphostnames = (LPHOSTNAMES)lpdata->Value; #ifdef FIREWALLS
ASSERT (lpoledoc->lpvtbl->SetHostNames, "Invalid pointer to SetHostNames method") #endif
retval = (*lpoledoc->lpvtbl->SetHostNames)(lpdoc->lpoledoc, (LPSTR)lphostnames->data, ((LPSTR)lphostnames->data) + lphostnames->documentNameOffset); goto end; }
if (index == STDDOCDIMENSIONS){ #ifdef FIREWALLS
ASSERT (lpoledoc->lpvtbl->SetDocDimensions, "Invalid pointer to SetDocDimensions method") #endif
rcDoc.left = 0; rcDoc.top = ((LPRECT)(lpdata->Value))->top; rcDoc.bottom = 0; rcDoc.right = ((LPRECT)lpdata->Value)->left;
retval = (*lpoledoc->lpvtbl->SetDocDimensions)(lpdoc->lpoledoc, (LPRECT)&rcDoc);
goto end;
}
if (index == STDCOLORSCHEME) { #ifdef FIREWALLS
ASSERT (lpoledoc->lpvtbl->SetColorScheme, "Invalid pointer to SetColorScheme method") #endif
retval = (*lpoledoc->lpvtbl->SetColorScheme)(lpdoc->lpoledoc, (LPLOGPALETTE) lpdata->Value); goto end; } #ifdef FIREWALLS
ASSERT (index == STDTARGETDEVICE, "Unknown standard item"); #endif
// case of the printer decvice info
if (!(hnew = MakeItemData ((DDEPOKE FAR *)lpdata, hdata, format))) goto errRtn;
// Go thru the all the items lists for this doc and replace the
// printer device info information.
// Free the block we duplicated.
retval = SetStdInfo (lpdoc, hwndClient, (LPSTR) (MAKELONG(STDTARGETDEVICE,0)),hnew);
end: errRtn: if (hnew) // can only be global memory block
GlobalFree (hnew);
if (lpdata) { GlobalUnlock (hdata); if (retval == OLE_OK && fRelease) GlobalFree (hdata); } return retval; }
// SetStdInfo: Sets the targetdevice info. Creates a client
// for "StdTargetDevice". This item is created only within the
// lib and it is never visible in server app. When the change
// message comes from the server app, before we ask for
// the data, we send the targetdevice info if there is
// info for the client whom we are trying to send the data
// on advise.
int INTERNAL SetStdInfo (lpdoc, hwndClient, lpitemname, hdata) LPDOC lpdoc; HWND hwndClient; LPSTR lpitemname; HANDLE hdata; { HWND hwnd; HANDLE hclinfo = NULL; PCLINFO pclinfo = NULL; LPCLIENT lpclient; OLESTATUS retval = OLE_OK;
// first create/find the StdTargetDeviceItem.
if ((hwnd = SearchItem (lpdoc, lpitemname)) == NULL){ retval = RegisterItem ((LHDOC)lpdoc, lpitemname, (LPCLIENT FAR *)&lpclient, FALSE);
if (retval != OLE_OK) goto errRtn;
hwnd = lpclient->hwnd;
}
#ifdef FIREWALLS
ASSERT (retval == OLE_OK, "No StdTragetDevice or StdDocname item"); #endif
if(hclinfo = FindClient (hwnd, hwndClient)){ if (pclinfo = (PCLINFO) LocalLock (hclinfo)){ if (pclinfo->hdevInfo) GlobalFree (pclinfo->hdevInfo); pclinfo->bnewDevInfo = TRUE; if (hdata) pclinfo->hdevInfo = DuplicateData (hdata); else pclinfo->hdevInfo = NULL; pclinfo->hwnd = hwndClient; LocalUnlock (hclinfo);
// We do not have to reset the client because we did not
// change the handle it self.
} } else { // Create the client structure to be attcahed to the object.
hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO)); if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL) goto errRtn;
pclinfo->bnewDevInfo = TRUE; if (hdata) pclinfo->hdevInfo = DuplicateData (hdata); else pclinfo->hdevInfo = NULL;
pclinfo->hwnd = hwndClient; LocalUnlock (hclinfo);
// Now add this client to item client list
// !!! This error recovery is not correct.
if (!AddClient (hwnd, hwndClient, hclinfo)) goto errRtn;
} return OLE_OK; errRtn: if (pclinfo) LocalUnlock (hclinfo);
if (hclinfo) LocalFree (hclinfo); return OLE_ERROR_MEMORY; }
// SendDevInfo: Sends targetdevice info to the the object.
// Caches the last targetdevice info sent to the object.
// If the targetdevice block is same as the one in the
// cache, then no targetdevice info is sent.
// (!!! There might be some problem here getting back
// the same global handle).
void INTERNAL SendDevInfo (lpclient, lppropname) LPCLIENT lpclient; LPSTR lppropname; {
HANDLE hclinfo = NULL; PCLINFO pclinfo = NULL; HANDLE hdata; OLESTATUS retval; HWND hwnd; LPDOC lpdoc;
lpdoc = (LPDOC)GetWindowLong (GetParent (lpclient->hwnd), 0);
// find if any StdTargetDeviceInfo item is present at all
hwnd = SearchItem (lpdoc, (LPSTR) (MAKELONG(STDTARGETDEVICE, 0))); if (hwnd == NULL) return;
hclinfo = GetProp (hwnd, lppropname);
// This client has not set any target device info. no need to send
// any stdtargetdevice info
if (hclinfo != NULL) { if (!(pclinfo = (PCLINFO)LocalLock (hclinfo))) goto end;
// if we cached it, do not send it again.
if ((!pclinfo->bnewDevInfo) && pclinfo->hdevInfo == lpclient->hdevInfo) goto end;
pclinfo->bnewDevInfo = FALSE; if(!(hdata = DuplicateData (pclinfo->hdevInfo))) goto end; } else {
// already screen
if (!lpclient->hdevInfo) goto end;
//for screen send NULL.
hdata = NULL; }
// Now send the targetdevice info
#ifdef FIREWALLS
if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBECT") else if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS)) ASSERT (0, "Invalid LPOLEOBJECTVTBL") else ASSERT (lpclient->lpoleobject->lpvtbl->SetTargetDevice, "Invalid pointer to SetTargetDevice method") #endif
retval = (*lpclient->lpoleobject->lpvtbl->SetTargetDevice) (lpclient->lpoleobject, hdata);
if (retval == OLE_OK) { if (pclinfo) lpclient->hdevInfo = pclinfo->hdevInfo; else lpclient->hdevInfo = NULL;
} // !!! error case who frees the data?'
end: if (pclinfo) LocalUnlock (hclinfo);
return; }
void ChangeOwner (hmfp) HANDLE hmfp; { LPMETAFILEPICT lpmfp;
if (lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)) { if (bWin30) GiveToGDI (lpmfp->hMF); else { if (lpfnSetMetaFileBitsBetter) (*lpfnSetMetaFileBitsBetter) (lpmfp->hMF); }
GlobalUnlock (hmfp); } }
HANDLE INTERNAL MakeItemData (lpPoke, hPoke, cfFormat) DDEPOKE FAR * lpPoke; HANDLE hPoke; OLECLIPFORMAT cfFormat; { HANDLE hnew; LPSTR lpnew; DWORD dwSize;
if (cfFormat == CF_METAFILEPICT) return DuplicateMetaFile (*(LPHANDLE)lpPoke->Value);
if (cfFormat == CF_BITMAP) return DuplicateBitmap (*(LPHANDLE)lpPoke->Value);
if (cfFormat == CF_DIB) return DuplicateData (*(LPHANDLE)lpPoke->Value);
// Now we are dealing with normal case
if (!(dwSize = GlobalSize (hPoke))) return NULL;
dwSize = dwSize - sizeof (DDEPOKE) + sizeof(BYTE);
if (hnew = GlobalAlloc (GMEM_MOVEABLE, dwSize)) { if (lpnew = GlobalLock (hnew)) { UtilMemCpy (lpnew, (LPSTR) lpPoke->Value, dwSize); GlobalUnlock (hnew); } else { GlobalFree (hnew); hnew = NULL; } }
return hnew; }
HANDLE INTERNAL DuplicateMetaFile (hSrcData) HANDLE hSrcData; { LPMETAFILEPICT lpSrcMfp; LPMETAFILEPICT lpDstMfp = NULL; HANDLE hMF = NULL; HANDLE hDstMfp = NULL;
if (!(lpSrcMfp = (LPMETAFILEPICT) GlobalLock(hSrcData))) return NULL;
GlobalUnlock (hSrcData);
if (!(hMF = CopyMetaFile (lpSrcMfp->hMF, NULL))) return NULL;
if (!(hDstMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))) goto errMfp;
if (!(lpDstMfp = (LPMETAFILEPICT) GlobalLock (hDstMfp))) goto errMfp;
GlobalUnlock (hDstMfp);
*lpDstMfp = *lpSrcMfp; lpDstMfp->hMF = hMF; return hDstMfp; errMfp: if (hMF) DeleteMetaFile (hMF);
if (hDstMfp) GlobalFree (hDstMfp);
return NULL; }
HBITMAP INTERNAL DuplicateBitmap (hold) HBITMAP hold; { HBITMAP hnew; HANDLE hMem; LPSTR lpMem; LONG retVal = TRUE; DWORD dwSize; BITMAP bm;
// !!! another way to duplicate the bitmap
GetObject (hold, sizeof(BITMAP), (LPSTR) &bm); dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) * ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
if (!(hMem = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize))) return NULL;
if (!(lpMem = GlobalLock (hMem))){ GlobalFree (hMem); return NULL; }
GetBitmapBits (hold, dwSize, lpMem); if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight, bm.bmPlanes, bm.bmBitsPixel, NULL)) retVal = SetBitmapBits (hnew, dwSize, lpMem);
GlobalUnlock (hMem); GlobalFree (hMem);
if (hnew && (!retVal)) { DeleteObject (hnew); hnew = NULL; }
return hnew; }
|