|
|
/****************************** 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); }
|