windows-nt/Source/XPSP1/NT/base/mvdm/wow16/ddeml/hdata.c
2020-09-26 16:20:57 +08:00

488 lines
12 KiB
C

/****************************** Module Header ******************************\
* Module Name: HDATA.C
*
* DDE manager data handle handling routines
*
* Created: 12/14/90 Sanford Staab
*
* Copyright (c) 1988, 1989, 1990 Microsoft Corporation
\***************************************************************************/
#include "ddemlp.h"
HDDEDATA PutData(pSrc, cb, cbOff, aItem, wFmt, afCmd, pai)
LPBYTE pSrc;
DWORD cb;
DWORD cbOff;
ATOM aItem;
WORD wFmt;
WORD afCmd;
PAPPINFO pai;
{
HANDLE hMem;
HDDEDATA hdT;
DIP dip;
/* HACK ALERT!
* make sure the first two words req'd by windows dde is there,
* UNLESS aItem is null in which case we assume it is EXECUTE
* data and don't bother.
*/
if (aItem)
cbOff += 4L;
else
afCmd |= HDATA_EXEC;
if ((hMem = AllocDDESel(
(afCmd & HDATA_APPOWNED) ? DDE_FACKREQ : DDE_FRELEASE,
wFmt, cb + cbOff)) == NULL) {
SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
return(0L);
}
// add to local list - make sure a similar handle isn't already there.
hdT = MAKELONG(afCmd, hMem);
#ifdef DEBUG
if (FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hdT, FPI_DELETE)) {
AssertF(FALSE, "PutData - unexpected handle in hDataPile");
}
#endif // DEBUG
if (AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, CmpHIWORD) == API_ERROR) {
GLOBALFREE(hMem);
SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
return(0L);
}
// add to global list if appowned
if (afCmd & HDATA_APPOWNED) {
dip.hData = hMem;
dip.hTask = pai->hTask;
dip.cCount = 1;
dip.fFlags = afCmd;
if (AddPileItem(pDataInfoPile, (LPBYTE)&dip, CmpWORD) == API_ERROR) {
GLOBALFREE(hMem);
SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
return(0L);
}
}
if (pSrc)
CopyHugeBlock(pSrc, HugeOffset(GLOBALLOCK(hMem), cbOff), cb);
// LOWORD(hData) always == afCmd flags
return(MAKELONG(afCmd, hMem));
}
/*
* This is the internal data handle freeing function. fInternal is TRUE if
* this is called from within the DDEML (vs called via DdeFreeDataHandle())
* It only frees the handle if it is in the local list.
* Appowned data handles are only freed internally if a non-owner task is
* doing the freeing.
* It is important that the LOWORD(hData) be set properly.
*
* These features give this function the folowing desired characteristics:
* 1) Apps cannot free data handles more than once.
* 2) The DDEML cannot free APPOWNED data handles on behalf of the owner
* task. (except on cleanup)
*/
VOID FreeDataHandle(
PAPPINFO pai,
HDDEDATA hData,
BOOL fInternal)
{
DIP *pDip;
BOOL fRelease = 0;
DDEPOKE FAR *pDdeMem;
WORD fmt;
TRACEAPIIN((szT, "FreeDataHandle(%lx, %lx, %d)\n", pai, hData, fInternal));
// appowned data handles are not freed till their count reaches 0.
if ((LOWORD(hData) & HDATA_APPOWNED) &&
(pDip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, PHMEM(hData), 0))) {
// don't internally free if in the context of the owner
if (fInternal && (pDip->hTask == pai->hTask)) {
TRACEAPIOUT((szT, "FreeDataHandle: Internal and of this task - not freed.\n"));
return;
}
if (--pDip->cCount != 0) {
TRACEAPIOUT((szT, "FreeDataHandle: Ref count not 0 - not freed.\n"));
return;
}
FindPileItem(pDataInfoPile, CmpWORD, PHMEM(hData), FPI_DELETE);
fRelease = TRUE;
}
/*
* Apps can only free handles in their local list - this guards against
* multiple frees by an app. (my arnt we nice)
*/
if (!HIWORD(hData) ||
!FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE)) {
TRACEAPIOUT((szT, "FreeDataHandle: Not in local list - not freed.\n"));
return;
}
if (LOWORD(hData) & HDATA_EXEC) {
fRelease |= !(LOWORD(hData) & HDATA_APPOWNED);
} else {
pDdeMem = (DDEPOKE FAR *)GLOBALLOCK(HIWORD(hData));
if (pDdeMem == NULL) {
TRACEAPIOUT((szT, "FreeDataHandle: Lock failed - not freed.\n"));
return;
}
fRelease |= pDdeMem->fRelease;
fmt = pDdeMem->cfFormat;
GLOBALUNLOCK(HIWORD(hData));
}
if (fRelease) {
if (LOWORD(hData) & HDATA_EXEC)
GLOBALFREE(HIWORD(hData));
else
FreeDDEData(HIWORD(hData), fmt);
}
TRACEAPIOUT((szT, "FreeDataHandle: freed.\n"));
}
/*
* This function prepairs data handles on entry into the DDEML API. It has
* the following characteristics:
* 1) APPOWNED data handles are copied to a non-appowned handle if being
* passed to a non-local app.
* 2) non-APPOWNED data handles on loan to a callback are copied so they
* don't get prematurely freed.
* 3) The READONLY bit is set. (in the local list)
*/
HDDEDATA DllEntry(
PCOMMONINFO pcomi,
HDDEDATA hData)
{
if ((!(pcomi->fs & ST_ISLOCAL)) && (LOWORD(hData) & HDATA_APPOWNED) ||
LOWORD(hData) & HDATA_NOAPPFREE && !(LOWORD(hData) & HDATA_APPOWNED)) {
// copy APPOWNED data handles to a fresh handle if not a local conv.
// copy app loaned, non appowned handles as well (this is the
// relay server case)
hData = CopyHDDEDATA(pcomi->pai, hData);
}
LOWORD(hData) |= HDATA_READONLY;
AddPileItem(pcomi->pai->pHDataPile, (LPBYTE)&hData, CmpHIWORD);
// NOTE: the global lists READONLY flag set but thats
// ok because any hData received from a transaction will always be in
// the local list due to RecvPrep().
return(hData);
}
/*
* removes the data handle from the local list. This removes responsibility
* for the data handle from the sending app. APPOWNED handles are not
* removed.
*/
VOID XmitPrep(
HDDEDATA hData,
PAPPINFO pai)
{
if (!(LOWORD(hData) & HDATA_APPOWNED)) {
FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE);
}
}
/*
* Places the received data handle into the apropriate lists and returns
* it with the proper flags set. Returns 0 if invalid hMem. afCmd should
* contain any extra flags desired.
*/
HDDEDATA RecvPrep(
PAPPINFO pai,
HANDLE hMem,
WORD afCmd)
{
DIP *pdip;
HDDEDATA hData;
if (!hMem)
return(0);
// check if its an APPOWNED one, if so, log entry.
if (pdip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hMem, 0)) {
afCmd |= pdip->fFlags;
pdip->cCount++;
}
// if we got one that isnt fRelease, treat it as appowed.
if (!(*(LPWORD)GLOBALLOCK(hMem) & DDE_FRELEASE))
afCmd |= HDATA_APPOWNED;
GLOBALUNLOCK(hMem);
// all received handles are readonly.
hData = (HDDEDATA)MAKELONG(afCmd | HDATA_READONLY, hMem);
/*
* Add (or replace) into local list
*/
AddPileItem(pai->pHDataPile, (LPBYTE)&hData, CmpHIWORD);
return(hData);
}
HANDLE CopyDDEShareHandle(
HANDLE hMem)
{
DWORD cb;
LPBYTE pMem;
cb = GlobalSize(hMem);
pMem = GLOBALLOCK(hMem);
if (pMem == NULL) {
return(0);
}
hMem = GLOBALALLOC(GMEM_DDESHARE, cb);
CopyHugeBlock(pMem, GLOBALPTR(hMem), cb);
return(hMem);
}
HBITMAP CopyBitmap(
PAPPINFO pai,
HBITMAP hbm)
{
BITMAP bm;
HBITMAP hbm2, hbmOld1, hbmOld2;
HDC hdc, hdcMem1, hdcMem2;
if (!GetObject(hbm, sizeof(BITMAP), &bm)) {
return(0);
}
hdc = GetDC(pai->hwndDmg);
if (!hdc) {
return(0);
}
hdcMem1 = CreateCompatibleDC(hdc);
if (!hdcMem1) {
goto Cleanup3;
}
hdcMem2 = CreateCompatibleDC(hdc);
if (!hdcMem2) {
goto Cleanup2;
}
hbmOld1 = SelectObject(hdcMem1, hbm);
hbm2 = CreateCompatibleBitmap(hdcMem1, bm.bmWidth, bm.bmHeight);
if (!hbm2) {
goto Cleanup1;
}
hbmOld2 = SelectObject(hdcMem2, hbm2);
BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
SelectObject(hdcMem1, hbmOld1);
SelectObject(hdcMem2, hbmOld2);
Cleanup1:
DeleteDC(hdcMem2);
Cleanup2:
DeleteDC(hdcMem1);
Cleanup3:
ReleaseDC(pai->hwndDmg, hdc);
return(hbm2);
}
HPALETTE CopyPalette(
HPALETTE hpal)
{
int cPalEntries;
LOGPALETTE *plp;
if (!GetObject(hpal, sizeof(int), &cPalEntries)) {
return(0);
}
plp = (LOGPALETTE *)LocalAlloc(LPTR, sizeof(LOGPALETTE) +
(cPalEntries - 1) * sizeof(PALETTEENTRY));
if (!plp) {
return(0);
}
if (!GetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) {
LocalFree((HLOCAL)plp);
return(0);
}
plp->palVersion = 0x300;
plp->palNumEntries = (WORD)cPalEntries;
hpal = CreatePalette(plp);
if (hpal &&
!SetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) {
hpal = 0;
}
LocalFree((HLOCAL)plp);
return(hpal);
}
HDDEDATA CopyHDDEDATA(
PAPPINFO pai,
HDDEDATA hData)
{
HANDLE hMem;
LPDDE_DATA lpdded;
HDDEDATA hdT;
LPMETAFILEPICT pmfPict;
if (!HIWORD(hData))
return(hData);
hMem = CopyDDEShareHandle((HANDLE)HIWORD(hData));
if (!hMem)
return(NULL);
if (!(LOWORD(hData) & HDATA_EXEC)) {
lpdded = (LPDDE_DATA)GLOBALLOCK(hMem);
if (lpdded == NULL) {
return(NULL);
}
lpdded->wStatus |= DDE_FRELEASE;
if (lpdded != NULL) {
switch (lpdded->wFmt) {
case CF_BITMAP:
case CF_DSPBITMAP:
lpdded->wData = CopyBitmap(pai, lpdded->wData);
break;
case CF_PALETTE:
lpdded->wData = (WORD)CopyPalette((HPALETTE)lpdded->wData);
break;
case CF_DIB:
lpdded->wData = (WORD)CopyDDEShareHandle((HANDLE)lpdded->wData);
break;
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
lpdded->wData = (WORD)CopyDDEShareHandle((HANDLE)lpdded->wData);
if (lpdded->wData) {
pmfPict = (LPMETAFILEPICT)GLOBALLOCK((HANDLE)lpdded->wData);
if (pmfPict != NULL) {
pmfPict->hMF = CopyMetaFile(pmfPict->hMF, NULL);
GLOBALUNLOCK((HANDLE)lpdded->wData);
}
GLOBALUNLOCK((HANDLE)lpdded->wData);
}
break;
#ifdef CF_ENHMETAFILE
case CF_ENHMETAFILE:
lpdded->wData = (WORD)CopyEnhMetaFile(*((HENHMETAFILE FAR *)(&lpdded->wData)), NULL);
break;
#endif // bad because it makes chicago and NT binaries different.
}
GLOBALUNLOCK(hMem);
}
}
hdT = MAKELONG(LOWORD(hData) & ~(HDATA_APPOWNED | HDATA_NOAPPFREE), hMem);
AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, NULL);
return(hdT);
}
VOID FreeDDEData(
HANDLE hMem,
WORD wFmt)
{
DDEDATA FAR *pDdeData;
/*
* This handles the special cases for formats that hold imbedded
* objects. (CF_BITMAP, CF_METAFILEPICT).
*
* The data handle is assumed to be unlocked.
*/
// may need to add "Printer_Picture" for excel/word interaction" but
// this is just between the two of them and they don't use DDEML.
// raor says OLE only worries about these formats as well.
pDdeData = (DDEDATA FAR *)GLOBALLOCK(hMem);
if (pDdeData == NULL) {
return;
}
switch (wFmt) {
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
DeleteObject(*(HANDLE FAR *)(&pDdeData->Value));
break;
case CF_DIB:
/*
* DIBs are allocated by app so we don't use the macro here.
*/
GlobalFree(*(HANDLE FAR *)(&pDdeData->Value));
break;
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
{
HANDLE hmfPict;
LPMETAFILEPICT pmfPict;
/*
* EXCEL sickness - metafile is a handle to a METAFILEPICT
* struct which holds a metafile. (2 levels of indirection!)
*
* We don't use the GLOBAL macros here because these objects
* are allocated by the app. DDEML knows not their history.
*/
hmfPict = *(HANDLE FAR *)(&pDdeData->Value);
pmfPict = (LPMETAFILEPICT)GlobalLock(hmfPict);
if (pmfPict != NULL) {
DeleteMetaFile(pmfPict->hMF);
}
GlobalUnlock(hmfPict);
GlobalFree(hmfPict);
}
break;
#ifdef CF_ENHMETAFILE
case CF_ENHMETAFILE:
DeleteEnhMetaFile(*(HENHMETAFILE FAR *)(&pDdeData->Value));
break;
#endif // This is bad - it forces different binaries for chicago and NT!
}
GLOBALUNLOCK(hMem);
GLOBALFREE(hMem);
}