void IW::CRender::Play(HENHMETAFILE hemf) { IW::CDCRender dc(*this); bool bHasPal = dc.GetDeviceCaps(BITSPIXEL) <= 8; // Create a logical palette from the colors in the color table UINT nColors = GetEnhMetaFilePaletteEntries(hemf, 0, NULL); CPalette pal; if (bHasPal && nColors != GDI_ERROR && nColors != 0) { bHasPal = false; DWORD dwSize = sizeof (LOGPALETTE) + ((nColors - 1) * sizeof (PALETTEENTRY)); LPLOGPALETTE logPalette = IW_ALLOCA(LPLOGPALETTE, dwSize); logPalette->palVersion = 0x300; logPalette->palNumEntries = nColors; if (nColors == GetEnhMetaFilePaletteEntries(hemf, nColors, logPalette->palPalEntry)) { pal.CreatePalette(logPalette); } } HPALETTE hOldPal = NULL; if (bHasPal) { hOldPal = dc.SelectPalette(pal, TRUE); dc.RealizePalette(); } CRect rcClip = _pSurface->GetClipRect(); int nHeightRender = rcClip.bottom - rcClip.top; int nWidthRender = rcClip.right - rcClip.left; CBrush brush; CRect r(0, 0, nWidthRender, nHeightRender); if (brush.CreateSolidBrush(RGB(255,255,255))) { dc.FillRect(&r, brush); } PlayEnhMetaFile(dc, hemf, &r); ::GdiFlush(); if (hOldPal) dc.SelectPalette(hOldPal, FALSE); }
HPALETTE GetEMFPalette(HENHMETAFILE hEmf, HDC hDC) { // query number of entries int no = GetEnhMetaFilePaletteEntries(hEmf, 0, NULL); if ( no<=0 ) return NULL; // allocation LOGPALETTE * pLogPalette = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + (no-1) * sizeof(PALETTEENTRY)]; pLogPalette->palVersion = 0x300; pLogPalette->palNumEntries = no; // get real data GetEnhMetaFilePaletteEntries(hEmf, no, pLogPalette->palPalEntry); HPALETTE hPal = CreatePalette(pLogPalette); delete [] (BYTE *) pLogPalette; return hPal; }
bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight) { if (hFile == NULL) return false; HENHMETAFILE hMeta; HDC hDC; int cx,cy; //save the current position of the file long pos = hFile->Tell(); // Read the Metafile and convert to an Enhanced Metafile METAFILEHEADER mfh; hMeta = ConvertWmfFiletoEmf(hFile, &mfh); if (hMeta) { // ok, it's a WMF ///////////////////////////////////////////////////////////////////// // We use the original WMF size information, because conversion to // EMF adjusts the Metafile to Full Screen or does not set rclBounds at all // ENHMETAHEADER emh; // UINT uRet; // uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile // sizeof(ENHMETAHEADER), // size of buffer, in bytes // &emh); // address of buffer to receive data // if (!uRet){ // DeleteEnhMetaFile(hMeta); // return false; // } // // calculate size // cx = emh.rclBounds.right - emh.rclBounds.left; // cy = emh.rclBounds.bottom - emh.rclBounds.top; ///////////////////////////////////////////////////////////////////// // calculate size // scale the metafile (pixels/inch of metafile => pixels/inch of display) // mfh.inch already checked to be <> 0 hDC = ::GetDC(0); int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX); int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY); ::ReleaseDC(0, hDC); cx = (mfh.bbox.right - mfh.bbox.left) * cx1 / mfh.inch; cy = (mfh.bbox.bottom - mfh.bbox.top) * cy1 / mfh.inch; } else { // maybe it's an EMF... hFile->Seek(pos,SEEK_SET); ENHMETAHEADER emh; hMeta = ConvertEmfFiletoEmf(hFile, &emh); if (!hMeta){ strcpy(info.szLastError,"corrupted WMF"); return false; // definitively give up } // ok, it's an EMF // calculate size cx = emh.rclBounds.right - emh.rclBounds.left; cy = emh.rclBounds.bottom - emh.rclBounds.top; } if (info.nEscape) { // Check if cancelled DeleteEnhMetaFile(hMeta); strcpy(info.szLastError,"Cancelled"); return false; } if (!cx || !cy) { DeleteEnhMetaFile(hMeta); strcpy(info.szLastError,"empty WMF"); return false; } if (nForceWidth) cx=nForceWidth; if (nForceHeight) cy=nForceHeight; ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size HDC hDC0 = GetDC(0); // DC of screen HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen ReleaseDC(0, hDC0); // don't need anymore. get rid of it. if (hDC){ if (hBitmap){ RECT rc = {0,0,cx,cy}; int bpp = ::GetDeviceCaps(hDC, BITSPIXEL); HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap); // clear out the entire bitmap with windows background // because the MetaFile may not contain background information DWORD dwBack = XMF_COLOR_BACK; #if XMF_SUPPORT_TRANSPARENCY if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT; #endif DWORD OldColor = SetBkColor(hDC, dwBack); ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); SetBkColor(hDC, OldColor); //retrieves optional palette entries from the specified enhanced metafile PLOGPALETTE plogPal; PBYTE pjTmp; HPALETTE hPal; int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL); if (iEntries) { if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { DeleteObject(hBitmap); DeleteDC(hDC); DeleteEnhMetaFile(hMeta); strcpy(info.szLastError,"Cancelled"); return false; } plogPal->palVersion = 0x300; plogPal->palNumEntries = (WORD) iEntries; pjTmp = (PBYTE) plogPal; pjTmp += 4; GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); hPal = CreatePalette(plogPal); GlobalFree(plogPal); SelectPalette(hDC, hPal, FALSE); RealizePalette(hDC); } // Play the Metafile into Memory DC BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context hMeta, // handle to an enhanced metafile &rc); // pointer to bounding rectangle SelectObject(hDC, hBitmapOld); DeleteEnhMetaFile(hMeta); // we are done with this one if (info.nEscape) { // Check if cancelled DeleteObject(hBitmap); DeleteDC(hDC); strcpy(info.szLastError,"Cancelled"); return false; } // the Bitmap now has the image. // Create our DIB and convert the DDB into DIB if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) { DeleteObject(hBitmap); DeleteDC(hDC); return false; } #if XMF_SUPPORT_TRANSPARENCY if (bpp == 24) { RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT }; SetTransColor(rgbTrans); } #endif // We're finally ready to get the DIB. Call the driver and let // it party on our bitmap. It will fill in the color table, // and bitmap bits of our global memory block. bRet = GetDIBits(hDC, hBitmap, 0, (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS); DeleteObject(hBitmap); DeleteDC(hDC); return (bRet!=0); } else { DeleteDC(hDC); } } else { if (hBitmap) DeleteObject(hBitmap); } DeleteEnhMetaFile(hMeta); return false; }
void PLWEMFDecoder::Open (PLDataSource * pDataSrc) { PLASSERT_VALID(this); PLASSERT(m_bm == 0); PLASSERT(m_memdc == 0); PLASSERT(m_hemf == 0); SAPMFILEHEADER* pplaceablehdr = NULL; bool isadobe = false; bool isemf; // Get the type of the file (WMF or EMF) from the file name if (pDataSrc->NameIsWide()){ wchar_t* strname = _wcsdup(pDataSrc->GetNameW()); PLASSERT(strname); if (strname == NULL) { // This should never happen under 32-Bit, but who knows? PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during strdup."); } _wcsupr(strname); isemf = wcsstr(strname,L".EMF") != NULL; free(strname); } else{ char* strname = _strdup(pDataSrc->GetName()); PLASSERT(strname); if (strname == NULL) { // This should never happen under 32-Bit, but who knows? PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during strdup."); } _strupr(strname); bool isemf = strstr(strname,".EMF") != NULL; free(strname); } // Get a DC for the display m_dc = ::GetDC(NULL); PLASSERT(m_dc); if (m_dc == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate device context."); } if (isemf) { // We have an enhanced meta file which makes it alot easier m_hemf = SetEnhMetaFileBits(pDataSrc->GetFileSize(),pDataSrc->ReadEverything()); } else { // Buh, old 16-Bit WMF, Convert it to an enhanced metafile before proceeding. // Also, check if this is a placeable metafile with an Adobe Placeable header pplaceablehdr = (SAPMFILEHEADER*)pDataSrc->ReadEverything(); PLBYTE* p = NULL; UINT size; // If we have an adobe header, skip it to use only the real windows-conform data if (pplaceablehdr->key == ALDUSKEY) { isadobe = true; p = pDataSrc->ReadEverything()+sizeof(SAPMFILEHEADER); size = pDataSrc->GetFileSize() - sizeof(SAPMFILEHEADER); } else { // Else use the whole file contents as the metafile and assume // a native 16-Bit Windows-conform WMF p = pDataSrc->ReadEverything(); size = pDataSrc->GetFileSize(); } #ifdef _MFC_VER PLASSERT(AfxIsValidAddress(p,size,false)); #endif m_hemf = SetWinMetaFileBits(size,p,m_dc,NULL); } // If m_hemf is NULL, windows refused to load the metafile. If this is // the case, we're done. Notify the caller if (m_hemf == NULL) { raiseError (PL_ERRFORMAT_NOT_SUPPORTED,"Windows Metafile functions failed to load this image."); } // Get the header from the enhanced metafile, It contains some // useful information which will aid us during constuction of // the bitmap. // The header is of variable length. First get the amount of // memory required for the header UINT sizeneeded = GetEnhMetaFileHeader(m_hemf,0,NULL); if (sizeneeded == 0) { raiseError (PL_ERRFORMAT_UNKNOWN,"No header information in metafile"); } // Allocate storage for the header and read it in m_phdr = (LPENHMETAHEADER) new PLBYTE[sizeneeded]; if (m_phdr == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Out of memory during allocation of header."); } m_phdr->iType = EMR_HEADER; m_phdr->nSize = sizeneeded; #ifdef _MFC_VER PLASSERT(AfxIsValidAddress(m_phdr,sizeneeded,true)); #endif GetEnhMetaFileHeader(m_hemf,sizeneeded,m_phdr); int bpp = GetDeviceCaps(m_dc,BITSPIXEL); // Calculate the dimensions of the final bitmap. If we have // a placeable header in the WMF, we use the dimensions of // that image, else we use the calculated dimensions in the // EMF int width,height; if (isadobe) { PLASSERT(pplaceablehdr); int lpx = GetDeviceCaps(m_dc,LOGPIXELSX); int lpy = GetDeviceCaps(m_dc,LOGPIXELSY); // Calculate the absolute with and height and transform from twips to pixel width = (int) (pplaceablehdr->Right-pplaceablehdr->Left) * lpx / pplaceablehdr->inch; height = (int) (pplaceablehdr->Bottom-pplaceablehdr->Top) * lpy / pplaceablehdr->inch; } else { // Use the rclFrame of the header because it is the true device independent // information and also some applications (e.g. Corel) don't fill the // rclBounds correctly // Using: // MetaPixelsX = MetaWidthMM * MetaPixels / (MetaMM * 100); // where: // MetaWidthMM = metafile width in 0.01mm units // MetaPixels = width in pixels of the reference device // MetaMM = width in millimeters of the reference device // Same applies to the Y axis width = ((m_phdr->rclFrame.right - m_phdr->rclFrame.left) * m_phdr->szlDevice.cx) / (m_phdr->szlMillimeters.cx*100); height = ((m_phdr->rclFrame.bottom - m_phdr->rclFrame.top) * m_phdr->szlDevice.cy) / (m_phdr->szlMillimeters.cy*100); } // If this is a very old WMF without a PLACEABLE info, // we use somewhat meaningful defaults. Also, if the header was // not written correctly, we use this as a fallback if (width <= 0) { width = 320; } if (height <= 0) { height = 200; } // Create a device content for the screen, and a memory device // content to play the metafile to m_memdc = CreateCompatibleDC(m_dc); PLASSERT(m_memdc); if (m_memdc == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate device context."); } m_bm = CreateCompatibleBitmap(m_dc,width,height); if (m_bm == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate memory bitmap."); } m_holdbm = SelectObject(m_memdc,m_bm); // If the metafile has a palette, read it in UINT pe = GetEnhMetaFilePaletteEntries(m_hemf, 0, NULL); // pe is the real number of palette entries. To make the resulting // bitmap more useful, we always setup a 256 color palette if the // metafile has a palette if (pe>0 && pe<256) { SetBmpInfo (PLPoint (width, height), PLPoint(0,0), PLPixelFormat::L8); } else { SetBmpInfo (PLPoint (width, height), PLPoint(0,0), PLPixelFormat::B8G8R8A8); } }
void PLWEMFDecoder::GetImage (PLBmpBase & Bmp) { HPALETTE hpal = NULL; LPLOGPALETTE plogpal (0); if (GetBitsPerPixel() == 8) { plogpal = (LPLOGPALETTE)new PLBYTE[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256)]; memset(plogpal,0x0,sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*256); plogpal->palVersion = 0x300; plogpal->palNumEntries = 256; if (plogpal == NULL) { PLASSERT(false); raiseError (PL_ERRNO_MEMORY,"Cannot allocate palette."); } UINT pe = GetEnhMetaFilePaletteEntries(m_hemf, 0, NULL); GetEnhMetaFilePaletteEntries(m_hemf, pe, plogpal->palPalEntry); } // Setup a logical palette for our memory dc and also a // paintlib compatible palette for the paintlib bitmap PLPixel32 pPal[256]; if (plogpal) { for (UINT i = 0; i < 256; i++) { pPal[i] = *(PLPixel32*)&plogpal->palPalEntry[i]; } if ((hpal = CreatePalette((LPLOGPALETTE)plogpal))) { m_holdpal = SelectPalette(m_memdc, hpal, false); RealizePalette(m_memdc); } Bmp.SetPalette(pPal); delete [] plogpal; } // Play the metafile into the device context // First, setup a bounding rectangle and fill // the memory dc with white (some metafiles only // use a black pen to draw and have no actual fill // color set, This would cause a black on black // painting which is rather useless RECT rc; rc.left = rc.top = 0; rc.bottom = GetHeight(); rc.right = GetWidth(); FillRect(m_memdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH)); // Heeere we go.... BOOL bres = PlayEnhMetaFile(m_memdc,m_hemf,&rc); // Finally, convert the Windows bitmap into a paintlib bitmap PLWinBmp& winbmp = dynamic_cast<PLWinBmp&>(Bmp); BITMAPINFO* pBMI = (BITMAPINFO*)winbmp.GetBMI(); PLBYTE* pBits = (PLBYTE*)winbmp.GetBits(); if (GetBitsPerPixel() == 8) { GetDIBits(m_dc, m_bm, 0, GetHeight(), winbmp.GetBits(), pBMI, DIB_RGB_COLORS); } else { GetDIBits(m_dc, m_bm, 0, GetHeight(), winbmp.GetBits(), pBMI, DIB_PAL_COLORS); } }
BOOL KCanvasWindow::Print(void) { HDC hDCPrinter; int iEntries; if (hMetaFile == NULL) return FALSE; // if (SpoolFile.PlaySpoolFile(CurEmfFileName, NULL, NULL, NULL)) // return TRUE; { PRINTDLG pd; memset(&pd, 0, sizeof(pd)); pd.lStructSize = sizeof(PRINTDLG); pd.hwndOwner = m_hWnd; pd.Flags = PD_RETURNDC; pd.hInstance = hInstance; if (!PrintDlg(&pd) || (pd.hDC==NULL)) return FALSE; hDCPrinter = pd.hDC; } // EmfScope.UnlinkClientServer(); { DOCINFO DocInfo; char title[128]; // put a special tag before the title so spehon32 can ignore it strcpy(title, ItsMe); GetEnhMetaFileDescription(hMetaFile, sizeof(title)-strlen(title), title+strlen(title)); memset(&DocInfo, 0, sizeof(DocInfo)); DocInfo.cbSize = sizeof(DOCINFO); DocInfo.lpszDocName = title; DocInfo.lpszOutput = NULL; StartDoc(hDCPrinter, &DocInfo); } StartPage(hDCPrinter); iEntries = GetEnhMetaFilePaletteEntries(hMetaFile, 0, NULL); if (iEntries) { PLOGPALETTE plogPal; PBYTE pjTmp; HPALETTE hPal; if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { MessageBox(m_hWnd, "Failed in Creating Palette!", "Error", MB_OK); } plogPal->palVersion = 0x300; plogPal->palNumEntries = (WORD) iEntries; pjTmp = (PBYTE) plogPal; pjTmp += 8; GetEnhMetaFilePaletteEntries(hMetaFile, iEntries, (PPALETTEENTRY)pjTmp); hPal = CreatePalette(plogPal); GlobalFree(plogPal); SelectPalette(hDCPrinter, hPal, FALSE); RealizePalette(hDCPrinter); } { RECT rc; ENHMETAHEADER EnhMetaHdr; GetEnhMetaFileHeader(hMetaFile, sizeof(ENHMETAHEADER), &EnhMetaHdr); rc.top = 0; rc.left = 0; rc.right = EnhMetaHdr.szlDevice.cx; rc.bottom = EnhMetaHdr.szlDevice.cy; if (!PlayEnhMetaFile(hDCPrinter, hMetaFile, &rc)) { char text[128]; wsprintf(text, "Fail in PlayEnhMetaFile! Error %ld\n", GetLastError()); MessageBox(0, text, "Play", MB_OK); } } EndPage(hDCPrinter); EndDoc(hDCPrinter); // EmfScope.LinkClientServer(); return TRUE; }
STDMETHODIMP CDropTarget::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { #ifdef _DEBUG printf("IDropTarget::Drop\n"); #endif //_DEBUG DWORD dwOKEffects = *pdwEffect; { //We do this because grfKeyState will always have the mouse button used off DWORD temp = LastKeyState; //Get the position of the drop DragOver(grfKeyState, pt, pdwEffect); LastKeyState = temp; } //Remove the effects pDataObj = NULL; DragLeave(); bool copying = (*pdwEffect & DROPEFFECT_COPY) != 0; size_t totallen = 0; BYTE *data = NULL; bool gotdata = false; UINT *formats = NULL; UINT numformats = 0; FORMATETC *fel = NULL; UINT numfe = 0; bool NeedToChooseFormat = true; int IndexOfDataToInsert = -1; bool NeedToChooseMoveorCopy = (LastKeyState | grfKeyState) & (MK_MBUTTON | MK_RBUTTON) || hexwnd.always_pick_move_copy; if (hexwnd.dragging) // Internal data { hexwnd.dragging = FALSE; if (NeedToChooseMoveorCopy) { int choice = PopupDropMenu(pt); if (choice == 0) { pDataObject->Release(); *pdwEffect = DROPEFFECT_NONE; return S_OK; } copying = choice != 1; } int iMove1stEnd = hexwnd.iGetStartOfSelection(); int iMove2ndEndorLen = hexwnd.iGetEndOfSelection(); int iMovePosOrg = hexwnd.new_pos; if (!copying && hexwnd.new_pos > iMove2ndEndorLen) hexwnd.new_pos += iMove1stEnd - iMove2ndEndorLen - 1; iMovePos = hexwnd.new_pos; iMoveOpTyp = copying ? OPTYP_COPY : OPTYP_MOVE; SimpleArray<BYTE> olddata; const int len = iMove2ndEndorLen - iMove1stEnd + 1; if (grfKeyState & MK_SHIFT) // Overwrite { if (copying) { //Just [realloc &] memmove if (iMovePos + len > hexwnd.m_dataArray.GetLength()) // Need more space { olddata.AppendArray(&hexwnd.m_dataArray[iMovePos], hexwnd.m_dataArray.GetLength() - iMovePos); if (hexwnd.m_dataArray.SetSize(iMovePos + len)) { hexwnd.m_dataArray.ExpandToSize(); memmove(&hexwnd.m_dataArray[iMovePos], &hexwnd.m_dataArray[iMove1stEnd], len); } } else // Enough space { olddata.AppendArray(&hexwnd.m_dataArray[iMovePos], len); memmove(&hexwnd.m_dataArray[iMovePos], &hexwnd.m_dataArray[iMove1stEnd], len); } hexwnd.push_undorecord(iMovePos, olddata, olddata.GetLength(), &hexwnd.m_dataArray[iMovePos], len); } else //Moving { if (iMovePos > iMove1stEnd) //Forward { olddata.AppendArray(&hexwnd.m_dataArray[iMove1stEnd], iMovePosOrg + len - iMove1stEnd); hexwnd.move_copy_sub(iMove1stEnd, iMove2ndEndorLen, 0); hexwnd.m_dataArray.RemoveAt(iMovePos+len,len); hexwnd.push_undorecord(iMove1stEnd, olddata, olddata.GetLength(), &hexwnd.m_dataArray[iMove1stEnd], iMovePosOrg - iMove1stEnd); } else //Backward { if (iMove1stEnd-iMovePos>=len) { olddata.AppendArray(&hexwnd.m_dataArray[iMovePos], iMove1stEnd + len - iMovePos); memmove(&hexwnd.m_dataArray[iMovePos],&hexwnd.m_dataArray[iMove1stEnd],len); hexwnd.m_dataArray.RemoveAt(iMove1stEnd,len); } else { olddata.AppendArray(&hexwnd.m_dataArray[iMovePos], iMove1stEnd + len - (iMovePos + len - iMove1stEnd) - iMovePos); memmove(&hexwnd.m_dataArray[iMovePos],&hexwnd.m_dataArray[iMove1stEnd],len); hexwnd.m_dataArray.RemoveAt(iMovePos+len,len-(iMovePos + len - iMove1stEnd)); } hexwnd.push_undorecord(iMovePos, olddata, olddata.GetLength(), &hexwnd.m_dataArray[iMovePos], iMove1stEnd - iMovePos); } } hexwnd.iStartOfSelection = iMovePos; hexwnd.iEndOfSelection = iMovePos+len-1; hexwnd.bFilestatusChanged = true; hexwnd.bSelected = true; hexwnd.resize_window(); } else // Insert { hexwnd.CMD_move_copy(iMove1stEnd, iMove2ndEndorLen, 1); } } else // External data { STGMEDIUM stm; HRESULT err = E_UNEXPECTED; //Get the formats enumerator IEnumFORMATETC *iefe = 0; pDataObject->EnumFormatEtc(DATADIR_GET, &iefe); if (iefe == 0) { #ifdef _DEBUG printf("Unable to create a drag-drop data enumerator\n"); #endif //_DEBUG goto ERR; } iefe->Reset(); //Get the available formats for(;;) { void *temp = realloc(fel, (numfe + 1) * sizeof(FORMATETC)); if (temp != NULL) { fel = (FORMATETC*) temp; temp = NULL; int r; r = iefe->Next(1, &fel[numfe], NULL); if (r != S_OK) break;//No more formats numfe++; } else if (fel == NULL) { //We only go here if nothing could be allocated #ifdef _DEBUG printf("Not enough memory for the drag-drop format list\n"); #endif //_DEBUG goto ERR_ENUM; } } UINT i; /*Check which format should be inserted according to user preferences*/ if (numfe == 0) { MessageBox(hexwnd.pwnd, GetLangString(IDS_DD_NO_DATA), MB_OK); err = S_OK; *pdwEffect = DROPEFFECT_NONE; goto ERR_ENUM; } if (hexwnd.prefer_CF_HDROP) { for (i = 0 ; i < numfe ; i++) { if (fel[i].cfFormat == CF_HDROP) { //Return no effect & let shell32 handle it if (S_OK == pDataObject->GetData(&fel[i], &stm)) { hexwnd.dropfiles((HDROP)stm.hGlobal); } err = S_OK; *pdwEffect = DROPEFFECT_NONE; goto ERR_ENUM; } } } if (numfe == 1) { IndexOfDataToInsert = 0; } else if (hexwnd.prefer_CF_BINARYDATA) { for (i = 0 ; i < numfe ; i++) { if (fel[i].cfFormat == CF_BINARYDATA) { NeedToChooseFormat = false; IndexOfDataToInsert = i; break; } } } else if (hexwnd.prefer_CF_TEXT) { for (i = 0 ; i < numfe ; i++) { if (fel[i].cfFormat == CF_TEXT) { NeedToChooseFormat = false; IndexOfDataToInsert = i; break; } } } if (NeedToChooseFormat) { dialog<DragDropDlg> params; params.allowable_effects = dwOKEffects & (DROPEFFECT_COPY | DROPEFFECT_MOVE); params.effect = copying; params.formatetcs = fel; params.numformatetcs = numfe; params.formats = NULL; params.numformats = 0; int ret = params.DoModal(hexwnd.pwnd); if (ret < 0) { //An error occured or the user canceled the operation err = S_OK; *pdwEffect = DROPEFFECT_NONE; goto ERR_ENUM; } numformats = params.numformats; formats = params.formats; copying = params.effect; } else if (NeedToChooseMoveorCopy) { int choice = PopupDropMenu(pt); if (choice == 0) { err = S_OK; *pdwEffect = DROPEFFECT_NONE; goto ERR_ENUM; } copying = choice != 1; } if (IndexOfDataToInsert >= 0 && formats == NULL) { formats = (UINT*)&IndexOfDataToInsert; numformats = 1; } //for each selected format for (i = 0 ; i < numformats ; i++) { FORMATETC fe = fel[formats[i]]; /*It is important that when debugging (with M$VC at least) you do not step __into__ the below GetData call If you do the app providing the data source will die & GetData will return OLE_E_NOTRUNNING or E_FAIL The solution is to step over the call It is also possible that a debugger will be opened & attach itself to the data provider */ if (pDataObject->GetData(&fe, &stm) == S_OK) { //Get len size_t len = 0; switch (stm.tymed) { case TYMED_HGLOBAL: len = GlobalSize(stm.hGlobal); break; #ifndef __CYGWIN__ case TYMED_FILE: { int fh = _wopen(stm.lpszFileName, _O_BINARY | _O_RDONLY); if (fh != -1) { len = _filelength(fh); if (len == (size_t)-1) len = 0; _close(fh); } } break; #endif //__CYGWIN__ case TYMED_ISTREAM: { STATSTG stat; if (S_OK == stm.pstm->Stat(&stat, STATFLAG_NONAME)) len = (size_t)stat.cbSize.LowPart; } break; //This case is going to be a bitch to implement so it can wait for a while //It will need to be a recursive method that stores the STATSTG structures (+ the name), contents/the bytes of data in streams/property sets case TYMED_ISTORAGE: { MessageBox(hexwnd.pwnd, GetLangString(IDS_DD_TYMED_NOTSUP), MB_OK); } break; // IStorage* case TYMED_GDI: { len = GetObject(stm.hBitmap, 0, NULL); if (len) { DIBSECTION t; GetObject(stm.hBitmap, len, &t); len += t.dsBm.bmHeight*t.dsBm.bmWidthBytes*t.dsBm.bmPlanes; } } break; // HBITMAP case TYMED_MFPICT: { len = GlobalSize(stm.hMetaFilePict); METAFILEPICT *pMFP = (METAFILEPICT*)GlobalLock(stm.hMetaFilePict); if (pMFP) { len += GetMetaFileBitsEx(pMFP->hMF, 0, NULL); GlobalUnlock(stm.hMetaFilePict); } } break; // HMETAFILE #ifndef __CYGWIN__ case TYMED_ENHMF: { len = GetEnhMetaFileHeader(stm.hEnhMetaFile, 0, NULL); DWORD n = GetEnhMetaFileDescriptionW(stm.hEnhMetaFile, 0, NULL); if (n && n != GDI_ERROR) len += sizeof(WCHAR) * n; len += GetEnhMetaFileBits(stm.hEnhMetaFile, 0, NULL); n = GetEnhMetaFilePaletteEntries(stm.hEnhMetaFile, 0, NULL); if (n && n != GDI_ERROR) len += sizeof(LOGPALETTE) + (n - 1) * sizeof(PALETTEENTRY); } break; // HENHMETAFILE #endif //__CYGWIN__ //case TYMED_NULL:break; } if (!len) continue; /*Malloc We do this so that if the data access fails we only need free(data) and don't need to mess around with the m_dataArray. Perhaps in the future the m_dataArray can support undoable actions.*/ BYTE* t = (BYTE*)realloc(data, len); if (!t) continue; data = t; memset(data, 0, len); //Get data switch (stm.tymed) { case TYMED_HGLOBAL: { if (LPVOID pmem = GlobalLock(stm.hGlobal)) { memcpy(data, pmem, len); gotdata = true; GlobalUnlock(stm.hGlobal); } } break; #ifndef __CYGWIN__ case TYMED_FILE: { int fh = _wopen(stm.lpszFileName, _O_BINARY | _O_RDONLY); if (fh != -1) { if (0 < _read(fh, data, len)) gotdata = true; _close(fh); } } break; #endif //__CYGWIN__ case TYMED_ISTREAM: { LARGE_INTEGER zero = { 0 }; ULARGE_INTEGER pos; if (S_OK == stm.pstm->Seek(zero, STREAM_SEEK_CUR, &pos)) { stm.pstm->Seek(zero, STREAM_SEEK_SET, NULL); if (S_OK == stm.pstm->Read(data, len, NULL)) gotdata = true; stm.pstm->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_SET, NULL); } } break; //This case is going to be a bitch to implement so it can wait for a while //It will need to be a recursive method that stores the STATSTG structures (+ the name), contents/the bytes of data in streams/property sets case TYMED_ISTORAGE: { MessageBox(hexwnd.pwnd, GetLangString(IDS_DD_TYMED_NOTSUP), MB_OK); goto ERR_ENUM; } break;//IStorage* case TYMED_GDI: { int l = GetObject(stm.hBitmap, len, data); if (l) { BITMAP* bm = (BITMAP*)data; if (bm->bmBits) memcpy(&data[l], bm->bmBits, len-l); else GetBitmapBits(stm.hBitmap, len-l, &data[l]); gotdata = true; } } break; // HBITMAP case TYMED_MFPICT: { if (METAFILEPICT *pMFP = (METAFILEPICT *)GlobalLock(stm.hMetaFilePict)) { memcpy(data, pMFP, sizeof *pMFP); GetMetaFileBitsEx(pMFP->hMF, len - sizeof(*pMFP), &data[sizeof(*pMFP)]); GlobalUnlock(stm.hMetaFilePict); gotdata = true; } } break;//HMETAFILE #ifndef __CYGWIN__ case TYMED_ENHMF: { DWORD i = 0, n = 0, l = len; n = GetEnhMetaFileHeader(stm.hEnhMetaFile, l, (ENHMETAHEADER*)&data[i]); l -= n; i += n; n = GetEnhMetaFileDescriptionW(stm.hEnhMetaFile, l / sizeof(WCHAR), (LPWSTR)&data[i]); if (n && n != GDI_ERROR) { n *= sizeof(WCHAR);l -= n; i += n; } n = GetEnhMetaFileBits(stm.hEnhMetaFile, l, &data[i]); l -= n; i += n; n = GetEnhMetaFilePaletteEntries(stm.hEnhMetaFile, 0, NULL); if (n && n != GDI_ERROR) { LOGPALETTE* lp = (LOGPALETTE*)&data[i]; lp->palVersion = 0x300; lp->palNumEntries = (USHORT)n; l -= sizeof(lp->palVersion) + sizeof(lp->palNumEntries); n = GetEnhMetaFilePaletteEntries(stm.hEnhMetaFile, l / sizeof(PALETTEENTRY), &lp->palPalEntry[0]); i += n*sizeof(PALETTEENTRY); } if (i) gotdata = true; } break; // HENHMETAFILE #endif //__CYGWIN__ //case TYMED_NULL:break; } ReleaseStgMedium(&stm); if (gotdata) { BYTE* DataToInsert = data; if (fe.cfFormat == CF_BINARYDATA) { len = *(DWORD*)data; DataToInsert += 4; } else if (fe.cfFormat == CF_TEXT || fe.cfFormat == CF_OEMTEXT) { len = strlen((char*)data); } else if (fe.cfFormat == CF_UNICODETEXT) { len = sizeof(wchar_t)*wcslen((wchar_t*)data); } // Insert/overwrite data into m_dataArray if (grfKeyState&MK_SHIFT) { /* Overwite */ SimpleArray<BYTE> olddata; DWORD upper = 1 + hexwnd.m_dataArray.GetUpperBound(); if (hexwnd.new_pos+len > upper) { olddata.AppendArray(&hexwnd.m_dataArray[hexwnd.new_pos + (int)totallen], upper - hexwnd.new_pos + (int)totallen); /* Need more space */ if (hexwnd.m_dataArray.SetSize(hexwnd.new_pos + totallen + len)) { hexwnd.m_dataArray.ExpandToSize(); memcpy(&hexwnd.m_dataArray[hexwnd.new_pos + (int)totallen], DataToInsert, len); hexwnd.push_undorecord(hexwnd.new_pos + totallen, olddata, olddata.GetLength(), DataToInsert, len); gotdata = true; totallen += len; } } else { /* Enough space */ olddata.AppendArray(&hexwnd.m_dataArray[hexwnd.new_pos + (int)totallen], len); memcpy(&hexwnd.m_dataArray[hexwnd.new_pos + (int)totallen], DataToInsert, len); hexwnd.push_undorecord(hexwnd.new_pos + totallen, olddata, olddata.GetLength(), DataToInsert, len); gotdata = true; totallen += len; } } else if (hexwnd.m_dataArray.InsertAtGrow(hexwnd.new_pos + totallen, DataToInsert, 0, len)) { /* Insert */ hexwnd.push_undorecord(hexwnd.new_pos + totallen, NULL, 0, DataToInsert, len); gotdata = true; totallen += len; } } } } // For each selected format // Release the data free(data); data = NULL; if (IndexOfDataToInsert < 0) { free(formats); formats = NULL; } if (gotdata) { hexwnd.iStartOfSelection = hexwnd.new_pos; hexwnd.iEndOfSelection = hexwnd.new_pos + totallen - 1; hexwnd.bFilestatusChanged = true; hexwnd.bSelected = true; hexwnd.resize_window(); hexwnd.synch_sibling(); } *pdwEffect = copying ? DROPEFFECT_COPY : DROPEFFECT_MOVE; err = S_OK; ERR_ENUM: iefe->Release(); free(fel); ERR: pDataObject->Release(); return err; } pDataObject->Release(); return S_OK; }