/****************************** Module Header ******************************\ * Module Name: hdata.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * DDE Manager data handle functions * * Created: 11/12/91 Sanford Staab * \***************************************************************************/ #define DDEMLDB #include "precomp.h" #pragma hdrstop /***************************************************************************\ * DdeCreateDataHandle (DDEML API) * * Description * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG7(LOG_GENERAL, HDDEDATA, DUMMYCALLINGTYPE, DdeCreateDataHandle, DWORD, idInst, LPBYTE, pSrc, DWORD, cb, DWORD, cbOff, HSZ, hszItem, UINT, wFmt, UINT, afCmd) HDDEDATA DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb, DWORD cbOff, HSZ hszItem, UINT wFmt, UINT afCmd) { PCL_INSTANCE_INFO pcii; HDDEDATA hRet = 0; if (cb == -1) { RIPMSG0(RIP_WARNING, "DdeCreateDataHandle called with cb == -1"); return NULL; } EnterDDECrit; pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (afCmd & ~HDATA_APPOWNED) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } if (cb + cbOff < sizeof(DWORD) && pSrc == NULL && (wFmt == CF_METAFILEPICT || wFmt == CF_DSPMETAFILEPICT || wFmt == CF_DIB || wFmt == CF_BITMAP || wFmt == CF_DSPBITMAP || wFmt == CF_PALETTE || wFmt == CF_ENHMETAFILE || wFmt == CF_DSPENHMETAFILE)) { /* * We have the nasty possibility of blowing up in FreeDDEData if we * don't initialize the data for formats with indirect data to 0. * This is because GlobalLock/GlobalSize do not adequately validate * random numbers given to them. */ cb += 4; } hRet = InternalCreateDataHandle(pcii, pSrc, cb, cbOff, hszItem ? afCmd : (afCmd | HDATA_EXECUTE), (WORD)((afCmd & HDATA_APPOWNED) ? 0 : DDE_FRELEASE), (WORD)wFmt); if (!hRet) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); } Exit: LeaveDDECrit; return (hRet); } /***************************************************************************\ * InternalCreateDataHandle * * Description: * Worker function for creating a data handle. If cb is -1, pSrc is * a GMEM_DDESHARE data handle. 0 is return ed on error. * * History: * 11-19-91 sanfords Created. \***************************************************************************/ HDDEDATA InternalCreateDataHandle( PCL_INSTANCE_INFO pcii, LPBYTE pSrc, DWORD cb, // cb of actual data to initialize with DWORD cbOff, // offset from start of data DWORD flags, WORD wStatus, WORD wFmt) { PDDEMLDATA pdd; HDDEDATA hRet; LPBYTE p; DWORD cbOff2; CheckDDECritIn; pdd = (PDDEMLDATA)DDEMLAlloc(sizeof(DDEMLDATA)); if (pdd == NULL) { return (0); } if (cb == -1) { pdd->hDDE = (HANDLE)pSrc; } else { if (flags & HDATA_EXECUTE) { cbOff2 = 0; } else { cbOff2 = sizeof(WORD) + sizeof(WORD); // skip wStatus, wFmt } pdd->hDDE = UserGlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, cb + cbOff + cbOff2); if (pdd->hDDE == NULL) { DDEMLFree(pdd); return (0); } if (!(flags & HDATA_EXECUTE)) { PDDE_DATA pdde; USERGLOBALLOCK(pdd->hDDE, pdde); UserAssert(pdde); pdde->wStatus = wStatus; pdde->wFmt = wFmt; USERGLOBALUNLOCK(pdd->hDDE); } } pdd->flags = (WORD)flags; hRet = (HDDEDATA)CreateHandle((ULONG_PTR)pdd, HTYPE_DATA_HANDLE, InstFromHandle(pcii->hInstClient)); if (!hRet) { WOWGLOBALFREE(pdd->hDDE); DDEMLFree(pdd); return (0); } if (cb != -1 && pSrc != NULL) { USERGLOBALLOCK(pdd->hDDE, p); UserAssert(p); RtlCopyMemory(p + cbOff + cbOff2, pSrc, cb); USERGLOBALUNLOCK(pdd->hDDE); pdd->flags |= HDATA_INITIALIZED; } return (hRet); } /***************************************************************************\ * DdeAddData (DDEML API) * * Description: * Copys data from a user buffer to a data handles. Reallocates if needed. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG4(LOG_GENERAL, HDDEDATA, DUMMYCALLINGTYPE, DdeAddData, HDDEDATA, hData, LPBYTE, pSrc, DWORD, cb, DWORD, cbOff) HDDEDATA DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff) { LPSTR pMem; PDDEMLDATA pdd; PCL_INSTANCE_INFO pcii; HDDEDATA hRet = 0; HANDLE hTempDDE; EnterDDECrit; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { goto Exit; } pcii = PciiFromHandle((HANDLE)hData); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (!(pdd->flags & HDATA_EXECUTE)) { cbOff += 4; } if (cb + cbOff > UserGlobalSize(pdd->hDDE)) { /* * If the realloc failed, free the old ptr. We continue * on in order to maintain compatibility with previous DDE code. */ hTempDDE = UserGlobalReAlloc(pdd->hDDE, cb + cbOff, GMEM_MOVEABLE | GMEM_ZEROINIT); if ((hTempDDE == NULL) && ((pdd->hDDE) != NULL)) { UserGlobalFree(pdd->hDDE); } pdd->hDDE = hTempDDE; } USERGLOBALLOCK(pdd->hDDE, pMem); if (pMem == NULL) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); goto Exit; } hRet = hData; if (pSrc != NULL) { try { RtlCopyMemory(pMem + cbOff, pSrc, cb); pdd->flags |= HDATA_INITIALIZED; } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); hRet = 0; } } USERGLOBALUNLOCK(pdd->hDDE); Exit: LeaveDDECrit; return (hRet); } /***************************************************************************\ * DdeGetData (DDEML API) * * Description: * Copys data from a data handle into a user buffer. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG4(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, DdeGetData, HDDEDATA, hData, LPBYTE, pDst, DWORD, cbMax, DWORD, cbOff) DWORD DdeGetData( HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff) { DWORD cbCopied = 0; DWORD cbSize; PDDEMLDATA pdd; PCL_INSTANCE_INFO pcii; EnterDDECrit; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pcii = PciiFromHandle((HANDLE)hData); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if (!(pdd->flags & HDATA_EXECUTE)) { cbOff += 4; } cbSize = (DWORD)UserGlobalSize(pdd->hDDE); if (cbOff >= cbSize) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } if (pDst == NULL) { cbCopied = cbSize - cbOff; goto Exit; } else { LPSTR pMem; cbCopied = min(cbMax, cbSize - cbOff); USERGLOBALLOCK(pdd->hDDE, pMem); UserAssert(pMem); try { RtlCopyMemory(pDst, pMem + cbOff, cbCopied); } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); cbCopied = 0; } if (pMem != NULL) { USERGLOBALUNLOCK(pdd->hDDE); } } Exit: LeaveDDECrit; return (cbCopied); } /***************************************************************************\ * DdeAccessData (DDEML API) * * Description: * Locks a data handle for access. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG2(LOG_GENERAL, LPBYTE, DUMMYCALLINGTYPE, DdeAccessData, HDDEDATA, hData, LPDWORD, pcbDataSize) LPBYTE DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize) { PCL_INSTANCE_INFO pcii; PDDEMLDATA pdd; LPBYTE pRet = NULL; DWORD cbOff; EnterDDECrit; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { goto Exit; } pcii = PciiFromHandle((HANDLE)hData); cbOff = pdd->flags & HDATA_EXECUTE ? 0 : 4; if (pcbDataSize != NULL) { *pcbDataSize = (DWORD)UserGlobalSize(pdd->hDDE) - cbOff; } USERGLOBALLOCK(pdd->hDDE, pRet); UserAssert(pRet); pRet = (LPBYTE)pRet + cbOff; Exit: LeaveDDECrit; return (pRet); } /***************************************************************************\ * DdeUnaccessData (DDEML API) * * Description: * Unlocks a data handle * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeUnaccessData, HDDEDATA, hData) BOOL DdeUnaccessData( HDDEDATA hData) { PDDEMLDATA pdd; BOOL fSuccess = FALSE; EnterDDECrit; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { goto Exit; } USERGLOBALUNLOCK(pdd->hDDE); fSuccess = TRUE; Exit: LeaveDDECrit; return (fSuccess); } /***************************************************************************\ * DdeFreeDataHandle (DDEML API) * * Description: * Releases application interest in a data handle. * * History: * 11-1-91 sanfords Created. \***************************************************************************/ FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeFreeDataHandle, HDDEDATA, hData) BOOL DdeFreeDataHandle( HDDEDATA hData) { PDDEMLDATA pdd; BOOL fSuccess = FALSE; EnterDDECrit; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { goto Exit; } if (pdd->flags & HDATA_NOAPPFREE) { fSuccess = TRUE; goto Exit; } fSuccess = InternalFreeDataHandle(hData, TRUE); Exit: LeaveDDECrit; return (fSuccess); } /***************************************************************************\ * InternalFreeDataHandle * * Description: * Frees a data handle and its contents. The contents are NOT freed for * APPOWNED data handles unless fIgnorefRelease is set. * * History: * 11-19-91 sanfords Created. \***************************************************************************/ BOOL InternalFreeDataHandle( HDDEDATA hData, BOOL fIgnorefRelease) { PDDEMLDATA pdd; CheckDDECritIn; pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)hData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { return (FALSE); } if (pdd->flags & HDATA_EXECUTE) { if (!(pdd->flags & HDATA_APPOWNED) || fIgnorefRelease) { WOWGLOBALFREE(pdd->hDDE); } } else { FreeDDEData(pdd->hDDE, fIgnorefRelease, TRUE); } DDEMLFree(pdd); DestroyHandle((HANDLE)hData); return (TRUE); } /***************************************************************************\ * ApplyFreeDataHandle * * Description: * Used during data handle cleanup. * * History: * 11-19-91 sanfords Created. \***************************************************************************/ BOOL ApplyFreeDataHandle( HANDLE hData) { BOOL fRet; CheckDDECritOut; EnterDDECrit; fRet = InternalFreeDataHandle((HDDEDATA)hData, FALSE); LeaveDDECrit; return(fRet); } /***************************************************************************\ * FreeDDEData * * Description: * Used for freeing DDE data including any special indirect objects * associated with the data depending on the format. This function * SHOULD NOT BE USED TO FREE EXECUTE DATA! * * The data is not freed if the fRelease bit is clear and fIgnoreRelease * is FALSE. * * The fFreeTruelyGlobalObjects parameter is used to distinguish tracking * layer frees from DDEML frees. Data in certain formats (CF_BITMAP, * CF_PALETTE) is maintained on the gdi CSR server side. When this is * passed between processes, gdi is not able to maintain multiple process * ownership on these objects so the objects must be made global. Thus * the tracking layer should NOT free these objects on behalf of another * process because they are truely global- however, DDEML can do this * because it is following the protocol which delclares who is in charge * of freeing global data. (YUCK!) * * History: * 11-19-91 sanfords Created. \***************************************************************************/ /* * WARNING: This is exported for NetDDE use - DO NOT CHANGE THE PARAMETERS! */ VOID FreeDDEData( HANDLE hDDE, BOOL fIgnorefRelease, BOOL fFreeTruelyGlobalObjects) { PDDE_DATA pdde; LPMETAFILEPICT pmfPict; DWORD cb; USERGLOBALLOCK(hDDE, pdde); if (pdde == NULL) { return ; } if ((pdde->wStatus & DDE_FRELEASE) || fIgnorefRelease) { cb = (DWORD)GlobalSize(hDDE); /* * Because there is the possibility that the data never got * initialized we need to do this in a try-except so we * behave nicely. */ switch (pdde->wFmt) { case CF_BITMAP: case CF_DSPBITMAP: case CF_PALETTE: if (cb >= sizeof(HANDLE)) { if (fFreeTruelyGlobalObjects) { if (pdde->Data != 0) { DeleteObject((HANDLE)pdde->Data); } } else { /* * !fFreeTruelyGlobalObject implies we are only freeing * the Gdi proxy. (another process may still have this * object in use.) * * ChrisWil: removed this call. No longer * applicable in KMode. * * GdiDeleteLocalObject((ULONG)pdde->Data); * */ } } break; case CF_DIB: if (cb >= sizeof(HANDLE)) { if (pdde->Data != 0) { WOWGLOBALFREE((HANDLE)pdde->Data); } } break; case CF_METAFILEPICT: case CF_DSPMETAFILEPICT: if (cb >= sizeof(HANDLE)) { if (pdde->Data != 0) { USERGLOBALLOCK(pdde->Data, pmfPict); if (pmfPict != NULL) { if (GlobalSize((HANDLE)pdde->Data) >= sizeof(METAFILEPICT)) { DeleteMetaFile(pmfPict->hMF); } USERGLOBALUNLOCK((HANDLE)pdde->Data); WOWGLOBALFREE((HANDLE)pdde->Data); } } } break; case CF_ENHMETAFILE: case CF_DSPENHMETAFILE: if (cb >= sizeof(HANDLE)) { if (pdde->Data != 0) { DeleteEnhMetaFile((HANDLE)pdde->Data); } } break; } USERGLOBALUNLOCK(hDDE); WOWGLOBALFREE(hDDE); } else { USERGLOBALUNLOCK(hDDE); } } HBITMAP CopyBitmap( HBITMAP hbm) { BITMAP bm; HBITMAP hbm2 = NULL, hbmOld1, hbmOld2; HDC hdc, hdcMem1, hdcMem2; if (!GetObject(hbm, sizeof(BITMAP), &bm)) { return(0); } hdc = NtUserGetDC(NULL); // screen DC 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: NtUserReleaseDC(NULL, hdc); return(hbm2); } HPALETTE CopyPalette( HPALETTE hpal) { int cPalEntries; LOGPALETTE *plp; if (!GetObject(hpal, sizeof(int), &cPalEntries)) { return(0); } plp = (LOGPALETTE *)DDEMLAlloc(sizeof(LOGPALETTE) + (cPalEntries - 1) * sizeof(PALETTEENTRY)); if (!plp) { return(0); } if (!GetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) { DDEMLFree(plp); return(0); } plp->palVersion = 0x300; plp->palNumEntries = (WORD)cPalEntries; hpal = CreatePalette(plp); if (hpal != NULL) { if (!SetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) { DeleteObject(hpal); hpal = NULL; } } DDEMLFree(plp); return(hpal); } /***************************************************************************\ * CopyDDEData * * Description: * Used to copy DDE data apropriately. * * History: * 11-19-91 sanfords Created. \***************************************************************************/ HANDLE CopyDDEData( HANDLE hDDE, BOOL fIsExecute) { HANDLE hDDENew; PDDE_DATA pdde, pddeNew; LPMETAFILEPICT pmfPict; HANDLE hmfPict; hDDENew = UserGlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, UserGlobalSize(hDDE)); if (!hDDENew) { return (0); } USERGLOBALLOCK(hDDE, pdde); if (pdde == NULL) { UserGlobalFree(hDDENew); return (0); } USERGLOBALLOCK(hDDENew, pddeNew); UserAssert(pddeNew); RtlCopyMemory(pddeNew, pdde, UserGlobalSize(hDDE)); if (!fIsExecute) { switch (pdde->wFmt) { case CF_BITMAP: case CF_DSPBITMAP: pddeNew->Data = (KERNEL_PVOID)CopyBitmap((HBITMAP)pdde->Data); break; case CF_PALETTE: pddeNew->Data = (KERNEL_PVOID)CopyPalette((HPALETTE)pdde->Data); break; case CF_DIB: pddeNew->Data = (KERNEL_PVOID)CopyDDEData((HANDLE)pdde->Data, TRUE); break; case CF_METAFILEPICT: case CF_DSPMETAFILEPICT: hmfPict = CopyDDEData((HANDLE)pdde->Data, TRUE); USERGLOBALLOCK(hmfPict, pmfPict); if (pmfPict == NULL) { WOWGLOBALFREE(hmfPict); USERGLOBALUNLOCK(hDDENew); WOWGLOBALFREE(hDDENew); USERGLOBALUNLOCK(hDDE); return (FALSE); } pmfPict->hMF = CopyMetaFile(pmfPict->hMF, NULL); USERGLOBALUNLOCK(hmfPict); pddeNew->Data = (KERNEL_PVOID)hmfPict; break; case CF_ENHMETAFILE: case CF_DSPENHMETAFILE: pddeNew->Data = (KERNEL_PVOID)CopyEnhMetaFile((HANDLE)pdde->Data, NULL); break; } } USERGLOBALUNLOCK(hDDENew); USERGLOBALUNLOCK(hDDE); return (hDDENew); }