1867 lines
48 KiB
C
1867 lines
48 KiB
C
/****************************** Module Header ******************************\
|
|
* Module Name: Item.c Object(item) main module
|
|
*
|
|
* Purpose: Includes All the object releated routiens.
|
|
*
|
|
* Created: Oct 1990.
|
|
*
|
|
* Copyright (c) 1990 - 1992 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* Raor (../10/1990) Designed, coded
|
|
* curts created portable version for WIN16/32
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
#include "windows.h"
|
|
#include "cmacs.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;
|
|
#ifdef WIN16
|
|
extern BOOL bWin30;
|
|
#endif
|
|
|
|
HWND hwndItem;
|
|
HANDLE hddeRename;
|
|
HWND hwndRename;
|
|
|
|
UINT enummsg;
|
|
UINT enuminfo;
|
|
LPOLEOBJECT enumlpoleobject;
|
|
OLECLIENTVTBL clVtbl;
|
|
BOOL bClientUnlink;
|
|
|
|
BOOL fAdviseSaveDoc;
|
|
BOOL fAdviseSaveItem;
|
|
|
|
char * stdStrTable[STDHOSTNAMES+1] =
|
|
{
|
|
NULL,
|
|
"StdTargetDevice",
|
|
"StdDocDimensions",
|
|
"StdColorScheme",
|
|
"StdHostNames"
|
|
};
|
|
|
|
#ifdef WIN16
|
|
extern HANDLE (FAR PASCAL *lpfnSetMetaFileBitsBetter) (HANDLE);
|
|
#endif
|
|
|
|
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 lpdoc,
|
|
LPSTR lpitemname
|
|
){
|
|
ATOM aItem;
|
|
|
|
Puts ("SearchItem");
|
|
|
|
// If the item passed is an atom, get its name.
|
|
if (!HIWORD(lpitemname))
|
|
aItem = (ATOM) (LOWORD(lpitemname));
|
|
else if (!lpitemname[0])
|
|
aItem = (ATOM)0;
|
|
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, (WNDENUMPROC)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 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(lpitemname),
|
|
(LPSTR)buf, MAX_STR);
|
|
else
|
|
buf[0] = '\0';
|
|
|
|
lpitemname = (LPSTR)buf;
|
|
}
|
|
|
|
if (hwnd) {
|
|
// we found the item window
|
|
lpclient = (LPCLIENT)GetWindowLongPtr (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 lhdoc,
|
|
LPSTR lpitemname,
|
|
LPCLIENT FAR * lplpclient,
|
|
BOOL bSrvr
|
|
){
|
|
LPDOC lpdoc;
|
|
HANDLE hclient = NULL;
|
|
LPCLIENT lpclient = NULL;
|
|
OLESTATUS 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(lpitemname);
|
|
}
|
|
else if (!lpitemname[0])
|
|
lpclient->aItem = (ATOM)0;
|
|
else
|
|
lpclient->aItem = GlobalAddAtom (lpitemname);
|
|
|
|
lpclient->oleClient.lpvtbl = &clVtbl;
|
|
lpclient->oleClient.lpvtbl->CallBack = ItemCallBack;
|
|
|
|
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 = CreateWindowEx (WS_EX_NOPARENTNOTIFY,"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.
|
|
SetWindowLongPtr (lpclient->hwnd, 0, (LONG_PTR)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
|
|
){
|
|
return RevokeObject (lpoleclient, TRUE);
|
|
|
|
}
|
|
|
|
// OleRevokeObject: Revokes an object (unregisres an object
|
|
// from the document tree.
|
|
|
|
OLESTATUS INTERNAL RevokeObject (
|
|
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 = (ATOM)0;
|
|
}
|
|
|
|
if (lpclient->hwnd) {
|
|
SetWindowLongPtr (lpclient->hwnd, 0, (LONG_PTR)NULL);
|
|
|
|
// another static for enumerating the properties.
|
|
// we need to change these .
|
|
bClientUnlink = bUnlink;
|
|
|
|
EnumProps(lpclient->hwnd, (PROPENUMPROC)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 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)GetWindowLongPtr (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 hwnd,
|
|
LONG data
|
|
){
|
|
|
|
LPCLIENT lpclient;
|
|
int cmd;
|
|
HANDLE hclinfo;
|
|
PCLINFO pclinfo = NULL;
|
|
|
|
|
|
lpclient = (LPCLIENT)GetWindowLongPtr (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 (
|
|
HWND hwndDoc,
|
|
HWND hwndClient
|
|
){
|
|
|
|
EnumChildWindows (hwndDoc, (WNDENUMPROC)lpFindItemWnd,
|
|
MAKELONG (hwndClient, ITEM_DELETECLIENT));
|
|
|
|
}
|
|
|
|
|
|
// DeleteAllItems: Deletes all the objects of a given
|
|
// document window.
|
|
|
|
|
|
void INTERNAL DeleteAllItems (
|
|
HWND hwndDoc
|
|
){
|
|
|
|
EnumChildWindows (hwndDoc, (WNDENUMPROC)lpFindItemWnd, MAKELONG (NULL, ITEM_DELETE));
|
|
|
|
}
|
|
|
|
|
|
// Object widnow proc:
|
|
|
|
LRESULT FAR PASCAL ItemWndProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
){
|
|
|
|
LPCLIENT lpclient;
|
|
|
|
lpclient = (LPCLIENT)GetWindowLongPtr (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 lpdoc,
|
|
HWND hwndClient,
|
|
LPARAM lparam
|
|
){
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
LPCLIENT lpclient;
|
|
DDEPOKE FAR * lpPoke = NULL;
|
|
HANDLE hPoke = NULL;
|
|
HANDLE hnew = NULL;
|
|
OLECLIPFORMAT format;
|
|
BOOL fRelease = FALSE;
|
|
ATOM aItem = GET_WM_DDE_POKE_ITEM((WPARAM)NULL,lparam);
|
|
|
|
UNREFERENCED_PARAMETER(hwndClient);
|
|
|
|
// Get the object handle first. Look in the registration
|
|
// tree and if one is not created otherwise create one.
|
|
|
|
retval = FindItem (lpdoc, (LPSTR) MAKEINTATOM(aItem),
|
|
(LPCLIENT FAR *)&lpclient);
|
|
|
|
if (retval != OLE_OK)
|
|
goto errRtn;
|
|
|
|
hPoke = GET_WM_DDE_POKE_HDATA((WPARAM)NULL,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 lpdoc,
|
|
HWND hwndClient,
|
|
LPARAM lparam
|
|
){
|
|
char buf[MAX_STR];
|
|
int options;
|
|
LPCLIENT lpclient;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
HANDLE hclinfo = NULL;
|
|
PCLINFO pclinfo = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(hwndClient);
|
|
|
|
if (!(HIWORD (lparam)))
|
|
buf[0] = '\0';
|
|
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] == '\0') {
|
|
// 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 lpdoc,
|
|
HWND hwndClient,
|
|
LPARAM lparam,
|
|
BOOL FAR * lpfack
|
|
){
|
|
HANDLE hopt = GET_WM_DDE_ADVISE_HOPTIONS((WPARAM)NULL,lparam);
|
|
ATOM aItem = GET_WM_DDE_ADVISE_ITEM((WPARAM)NULL,lparam);
|
|
DDEADVISE FAR *lpopt;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
|
|
if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
|
|
goto errrtn;
|
|
|
|
#ifdef FIREWALLS
|
|
ASSERT ((aItem == 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 lpdoc,
|
|
HWND hwndClient,
|
|
LPARAM lparam,
|
|
BOOL FAR * lpfack
|
|
){
|
|
HANDLE hopt = GET_WM_DDE_ADVISE_HOPTIONS((WPARAM)NULL,lparam);
|
|
ATOM aitem = GET_WM_DDE_ADVISE_ITEM((WPARAM)NULL,lparam);
|
|
DDEADVISE FAR *lpopt = NULL;
|
|
OLECLIPFORMAT format = 0;
|
|
char buf[MAX_STR];
|
|
int options;
|
|
LPCLIENT lpclient;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
HANDLE hclinfo = NULL;
|
|
PCLINFO pclinfo = NULL;
|
|
|
|
if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
|
|
goto errRtn;
|
|
|
|
if (!aitem)
|
|
buf[0] = '\0';
|
|
else
|
|
GlobalGetAtomName (aitem, (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 == (SHORT)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 = (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 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 (
|
|
LPSTR lpbuf,
|
|
int far *lpoptions
|
|
){
|
|
ATOM aModifier;
|
|
|
|
*lpoptions = OLE_CHANGED;
|
|
while ( *lpbuf && *lpbuf != '/')
|
|
lpbuf++;
|
|
|
|
// no modifier same as /change
|
|
|
|
if (*lpbuf == '\0')
|
|
return OLE_OK;
|
|
|
|
*lpbuf++ = '\0'; // 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 lpdoc,
|
|
HWND hwndClient,
|
|
LPARAM lparam,
|
|
LPHANDLE lphdde
|
|
){
|
|
OLESTATUS retval = OLE_OK;
|
|
HANDLE hdata;
|
|
LPCLIENT lpclient;
|
|
char buf[20];
|
|
|
|
// 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, (OLECLIPFORMAT)(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,
|
|
(OLECLIPFORMAT)(LOWORD(lparam)), (LPHANDLE)&hdata);
|
|
|
|
if (retval != OLE_OK)
|
|
goto errRtn;
|
|
|
|
if (LOWORD(lparam) == CF_METAFILEPICT)
|
|
ChangeOwner (hdata);
|
|
|
|
// Duplicate the DDE data
|
|
if (MakeDDEData(hdata, (OLECLIPFORMAT)(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;
|
|
|
|
}
|
|
|
|
#ifdef WIN32
|
|
HANDLE INTERNAL BmDuplicate (
|
|
HBITMAP hold
|
|
){
|
|
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 | GMEM_DDESHARE, dwSize+sizeof(BITMAP)+sizeof(DWORD))))
|
|
return NULL;
|
|
|
|
if (!(lpMem = (LPBYTE)GlobalLock (hMem))){
|
|
GlobalFree (hMem);
|
|
return NULL;
|
|
}
|
|
*((DWORD FAR *) lpMem) = dwSize;
|
|
*(BITMAP FAR *) (lpMem+sizeof(DWORD)) = bm;
|
|
lpMem += (sizeof(DWORD) + sizeof (BITMAP));
|
|
dwSize = GetBitmapBits (hold, 0, NULL);
|
|
retVal = GetBitmapBits (hold, dwSize, lpMem);
|
|
|
|
GlobalUnlock (hMem);
|
|
return hMem;
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
//MakeDDEData: Create a Global DDE data handle from the server
|
|
// app data handle.
|
|
|
|
BOOL INTERNAL MakeDDEData (
|
|
HANDLE hdata,
|
|
OLECLIPFORMAT format,
|
|
LPHANDLE lph,
|
|
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 || format == CF_ENHMETAFILE))
|
|
size = (DWORD)GlobalSize (hdata) + sizeof (DDEDATA);
|
|
else
|
|
#ifdef WIN32HACK
|
|
{
|
|
if (format == CF_BITMAP)
|
|
hdata = BmDuplicate(hdata);
|
|
|
|
size = sizeof (HANDLE_PTR) + sizeof (DDEDATA);
|
|
}
|
|
#else
|
|
size = sizeof (HANDLE_PTR) + sizeof (DDEDATA);
|
|
#endif
|
|
|
|
|
|
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 = (WORD)format;
|
|
lpdata->fResponse = (WORD)fResponse;
|
|
|
|
if (!bnative) {
|
|
// If not native, stick in the handle what the server gave us.
|
|
|
|
// Com1x bug 23211: data misalignment: truncate handle to 32 bits on Win64
|
|
// because a) handle is only 32 bit significant; b) this was causing data misalignment
|
|
// error; c) we're only allocating 32 bits for it above.
|
|
#ifdef _WIN64
|
|
if (format == CF_METAFILEPICT)
|
|
*(void* __unaligned*)lpdata->Value = hdata;
|
|
else
|
|
#endif
|
|
*(LONG*)lpdata->Value = HandleToLong(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 lpoleclient,
|
|
OLE_NOTIFICATION 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)GetWindowLongPtr (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,
|
|
cfLink, (LPHANDLE)&hdata);
|
|
}
|
|
else {
|
|
if(IsFormatAvailable (lpclient, cfOwnerLink)) {
|
|
|
|
// Get the link data.
|
|
retval = (*lpoleobject->lpvtbl->GetData) (lpoleobject,
|
|
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 = (ATOM)0;
|
|
}
|
|
|
|
// 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, cfBinary, (LPHANDLE)&hddeRename,
|
|
FALSE)) {
|
|
retval = OLE_ERROR_MEMORY;
|
|
goto errrtn;
|
|
}
|
|
|
|
EnumProps(hStdWnd, (PROPENUMPROC)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, (PROPENUMPROC)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, (PROPENUMPROC)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 hwnd,
|
|
LPSTR lpstr,
|
|
HANDLE hdata
|
|
){
|
|
LPDOC lpdoc;
|
|
|
|
UNREFERENCED_PARAMETER(lpstr);
|
|
|
|
lpdoc = (LPDOC)GetWindowLongPtr (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, (WPARAM)hwnd, (LPARAM)0))
|
|
lpdoc->termNo++;
|
|
|
|
//DeleteClient (hwnd, (HWND)hdata);
|
|
//lpdoc->cClients--;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL FAR PASCAL SendRenameMsg (
|
|
HWND hwnd,
|
|
LPSTR lpstr,
|
|
HANDLE hclinfo
|
|
){
|
|
ATOM aData = (ATOM)0;
|
|
HANDLE hdde = NULL;
|
|
PCLINFO pclinfo = NULL;
|
|
HWND hwndClient;
|
|
LPARAM lParamNew;
|
|
|
|
UNREFERENCED_PARAMETER(lpstr);
|
|
|
|
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
|
|
lParamNew = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
|
|
if (!PostMessageToClientWithBlock (hwndClient,WM_DDE_DATA,
|
|
(WPARAM)GetParent(hwnd),lParamNew))
|
|
{
|
|
DDEFREE(WM_DDE_DATA,lParamNew);
|
|
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 hwnd,
|
|
LPSTR lpstr,
|
|
HANDLE hclinfo
|
|
){
|
|
PCLINFO pclinfo = NULL;
|
|
HANDLE hdde = NULL;
|
|
ATOM aData = (ATOM)0;
|
|
int retval;
|
|
HANDLE hdata;
|
|
LPCLIENT lpclient;
|
|
LPARAM lParamNew;
|
|
|
|
|
|
if (!(pclinfo = (PCLINFO) LocalLock (hclinfo)))
|
|
goto errRtn;
|
|
|
|
lpclient = (LPCLIENT)GetWindowLongPtr (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,
|
|
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, cfNative, (LPHANDLE)&hdde, FALSE))
|
|
goto errRtn;
|
|
|
|
}
|
|
|
|
|
|
// Make the item atom with the options.
|
|
aData = MakeDataAtom (lpclient->aItem, enummsg);
|
|
lParamNew = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
|
|
// Post the message
|
|
if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA,
|
|
(WPARAM)GetParent(hwnd), lParamNew))
|
|
{
|
|
DDEFREE(WM_DDE_DATA,lParamNew);
|
|
goto errRtn;
|
|
}
|
|
hdde = NULL;
|
|
aData = (ATOM)0;
|
|
}
|
|
|
|
// 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);
|
|
Puts("sending metafile...");
|
|
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);
|
|
lParamNew = MAKE_DDE_LPARAM(WM_DDE_DATA,hdde,aData);
|
|
// now post the message to the client;
|
|
if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA,
|
|
(WPARAM)GetParent(hwnd), lParamNew))
|
|
{
|
|
DDEFREE(WM_DDE_DATA,lParamNew);
|
|
goto errRtn;
|
|
}
|
|
|
|
hdde = NULL;
|
|
aData = (ATOM)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
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 (
|
|
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 (
|
|
ATOM aItem
|
|
){
|
|
char str[MAX_STR];
|
|
|
|
if (!aItem)
|
|
return 0;
|
|
|
|
if (!GlobalGetAtomName (aItem, (LPSTR) str, MAX_STR))
|
|
return 0;
|
|
|
|
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 0;
|
|
}
|
|
|
|
//
|
|
// The wire representation of STDDOCDIMENSIONS is a 16-bit
|
|
// format. This means instead of 4 longs, there are
|
|
// 4 shorts. This structure is used below to pick the data
|
|
// from the wire representation.
|
|
// backward compatible is the name of the game.
|
|
//
|
|
typedef struct tagRECT16
|
|
{
|
|
SHORT left;
|
|
SHORT top;
|
|
SHORT right;
|
|
SHORT bottom;
|
|
|
|
} RECT16, *LPRECT16;
|
|
|
|
// 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 lpdoc,
|
|
HWND hwndClient,
|
|
HANDLE hdata,
|
|
int index
|
|
){
|
|
DDEDATA FAR * lpdata = NULL;
|
|
HANDLE hnew = NULL;
|
|
LPOLESERVERDOC lpoledoc;
|
|
LPHOSTNAMES lphostnames;
|
|
OLESTATUS retval = OLE_ERROR_MEMORY;
|
|
OLECLIPFORMAT format;
|
|
BOOL fRelease;
|
|
RECT rcDoc;
|
|
|
|
if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata))))
|
|
goto errRtn;
|
|
|
|
format = lpdata->cfFormat;
|
|
fRelease = lpdata->fRelease;
|
|
|
|
#ifdef FIREWALSS
|
|
ASSERT (format == 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 = ((LPRECT16)(lpdata->Value))->top;
|
|
rcDoc.bottom = 0;
|
|
rcDoc.right = ((LPRECT16)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) ULongToPtr(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 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 lpclient,
|
|
LPSTR lppropname
|
|
){
|
|
HANDLE hclinfo = NULL;
|
|
PCLINFO pclinfo = NULL;
|
|
HANDLE hdata;
|
|
OLESTATUS retval;
|
|
HWND hwnd;
|
|
LPDOC lpdoc;
|
|
|
|
|
|
|
|
lpdoc = (LPDOC)GetWindowLongPtr (GetParent (lpclient->hwnd), 0);
|
|
|
|
// find if any StdTargetDeviceInfo item is present at all
|
|
hwnd = SearchItem (lpdoc, (LPSTR)ULongToPtr(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 (
|
|
HANDLE hmfp
|
|
){
|
|
LPMETAFILEPICT lpmfp;
|
|
|
|
#ifdef WIN16
|
|
if (lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)) {
|
|
if (bWin30)
|
|
GiveToGDI (lpmfp->hMF);
|
|
else {
|
|
if (lpfnSetMetaFileBitsBetter)
|
|
(*lpfnSetMetaFileBitsBetter) (lpmfp->hMF);
|
|
}
|
|
|
|
GlobalUnlock (hmfp);
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
UNREFERENCED_PARAMETER(hmfp);
|
|
UNREFERENCED_PARAMETER(lpmfp);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
HANDLE INTERNAL MakeItemData (
|
|
DDEPOKE FAR * lpPoke,
|
|
HANDLE hPoke,
|
|
OLECLIPFORMAT cfFormat
|
|
){
|
|
HANDLE hnew;
|
|
LPSTR lpnew;
|
|
DWORD dwSize;
|
|
|
|
|
|
if (cfFormat == CF_ENHMETAFILE)
|
|
return CopyEnhMetaFile (LongToHandle(*(LONG*)lpPoke->Value), NULL);
|
|
|
|
if (cfFormat == CF_METAFILEPICT) {
|
|
#ifdef _WIN64
|
|
return DuplicateMetaFile(*(void* _unaligned*)lpPoke->Value);
|
|
#else
|
|
return DuplicateMetaFile (*(LPHANDLE)lpPoke->Value);
|
|
#endif
|
|
}
|
|
|
|
if (cfFormat == CF_BITMAP)
|
|
return DuplicateBitmap (LongToHandle(*(LONG*)lpPoke->Value));
|
|
|
|
if (cfFormat == CF_DIB)
|
|
return DuplicateData (LongToHandle(*(LONG*)lpPoke->Value));
|
|
|
|
// Now we are dealing with normal case
|
|
if (!(dwSize = (DWORD)GlobalSize (hPoke)))
|
|
return NULL;
|
|
|
|
dwSize = dwSize - sizeof (DDEPOKE) + sizeof(BYTE);
|
|
|
|
if (hnew = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, dwSize)) {
|
|
if (lpnew = GlobalLock (hnew)) {
|
|
UtilMemCpy (lpnew, (LPSTR) lpPoke->Value, dwSize);
|
|
GlobalUnlock (hnew);
|
|
}
|
|
else {
|
|
GlobalFree (hnew);
|
|
hnew = NULL;
|
|
}
|
|
}
|
|
|
|
return hnew;
|
|
}
|
|
|
|
|
|
|
|
HANDLE INTERNAL DuplicateMetaFile (
|
|
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 (
|
|
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;
|
|
}
|
|
|
|
|
|
|