X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9e2896e5c8944c5f5227fa080e1b781c4a6f2600..7b9da2077d0975db6c965a85c91d5aca671ab5e3:/src/msw/ole/dataobj.cpp diff --git a/src/msw/ole/dataobj.cpp b/src/msw/ole/dataobj.cpp index 46cfd66c4b..21eae48819 100644 --- a/src/msw/ole/dataobj.cpp +++ b/src/msw/ole/dataobj.cpp @@ -48,6 +48,8 @@ #include #endif +#include + #include "wx/msw/ole/oleutils.h" // ---------------------------------------------------------------------------- @@ -56,7 +58,9 @@ #ifdef __WXDEBUG__ static const wxChar *GetTymedName(DWORD tymed); -#endif // Debug +#else // !Debug + #define GetTymedName(tymed) "" +#endif // Debug/!Debug // to be moved into wx/msw/bitmap.h extern size_t wxConvertBitmapToDIB(BITMAPINFO *pbi, const wxBitmap& bitmap); @@ -429,6 +433,19 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, case TYMED_HGLOBAL: { + wxDataFormat format = pformatetc->cfFormat; + + // this is quite weird, but for file drag and drop, explorer + // calls our SetData() with the formats we do *not* support! + // + // as we can't fix this bug in explorer (it's a bug because it + // should only use formats returned by EnumFormatEtc), do the + // check here + if ( !m_pDataObject->IsSupportedFormat(format) ) { + // go away! + return DV_E_FORMATETC; + } + // copy data void *pBuf = GlobalLock(pmedium->hGlobal); if ( pBuf == NULL ) { @@ -443,17 +460,17 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, // synthetise it for known formats and we suppose that all data // in custom formats starts with a DWORD containing the size size_t size; - switch ( pformatetc->cfFormat ) + switch ( format ) { case CF_TEXT: case CF_OEMTEXT: size = strlen((const char *)pBuf); break; - +#ifndef __WATCOMC__ case CF_UNICODETEXT: size = wcslen((const wchar_t *)pBuf); break; - +#endif case CF_BITMAP: case CF_HDROP: // these formats don't use size at all, anyhow (but @@ -461,6 +478,12 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, size = 0; break; + case CF_DIB: + // the handler will calculate size itself (it's too + // complicated to do it here) + size = 0; + break; + default: { // we suppose that the size precedes the data @@ -470,7 +493,6 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, } } - wxDataFormat format = pformatetc->cfFormat; bool ok = m_pDataObject->SetData(format, size, pBuf); GlobalUnlock(pmedium->hGlobal); @@ -531,15 +553,13 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc) // and now check the type of data requested wxDataFormat format = pformatetc->cfFormat; if ( m_pDataObject->IsSupportedFormat(format) ) { -#ifdef __WXDEBUG__ wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"), - wxDataObject::GetFormatName(format)); -#endif // Debug + wxGetFormatName(format)); } else { wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s unsupported"), - wxDataObject::GetFormatName(format)); + wxGetFormatName(format)); return DV_E_FORMATETC; } @@ -549,13 +569,11 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc) if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) && !(tymed & TYMED_HGLOBAL) ) { // it's not what we're waiting for -#ifdef __WXDEBUG__ wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s != %s"), GetTymedName(tymed), GetTymedName(format == wxDF_BITMAP ? TYMED_GDI : TYMED_HGLOBAL)); -#endif // Debug return DV_E_TYMED; } @@ -669,6 +687,7 @@ bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const } #ifdef __WXDEBUG__ + const char *wxDataObject::GetFormatName(wxDataFormat format) { // case 'xxx' is not a valid value for switch of enum 'wxDataFormat' @@ -703,6 +722,7 @@ const char *wxDataObject::GetFormatName(wxDataFormat format) #pragma warning(default:4063) #endif // VC++ } + #endif // Debug // ---------------------------------------------------------------------------- @@ -920,6 +940,8 @@ bool wxFileDataObject::SetData(size_t WXUNUSED(size), const void *pData) // get number of files (magic value -1) UINT nFiles = ::DragQueryFile(hdrop, (unsigned)-1, NULL, 0u); + wxCHECK_MSG ( nFiles != (UINT)-1, FALSE, wxT("wrong HDROP handle") ); + // for each file get the length, allocate memory and then get the name wxString str; UINT len, n; @@ -940,68 +962,196 @@ bool wxFileDataObject::SetData(size_t WXUNUSED(size), const void *pData) return TRUE; } +void wxFileDataObject::AddFile(const wxString& file) +{ + // just add file to filenames array + // all useful data (such as DROPFILES struct) will be + // created later as necessary + m_filenames.Add(file); +} + +size_t wxFileDataObject::GetDataSize() const +{ + // size returned will be the size of the DROPFILES structure, + // plus the list of filesnames (null byte separated), plus + // a double null at the end + + // if no filenames in list, size is 0 + if ( m_filenames.GetCount() == 0 ) + return 0; + + // inital size of DROPFILES struct + null byte + size_t sz = sizeof(DROPFILES) + 1; + + size_t count = m_filenames.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + // add filename length plus null byte + sz += m_filenames[i].Len() + 1; + } + + return sz; +} + +bool wxFileDataObject::GetDataHere(void *pData) const +{ + // pData points to an externally allocated memory block + // created using the size returned by GetDataSize() + + // if pData is NULL, or there are no files, return + if ( !pData || m_filenames.GetCount() == 0 ) + return FALSE; + + // convert data pointer to a DROPFILES struct pointer + LPDROPFILES pDrop = (LPDROPFILES) pData; + + // initialize DROPFILES struct + pDrop->pFiles = sizeof(DROPFILES); + pDrop->fNC = FALSE; // not non-client coords +#if wxUSE_UNICODE + pDrop->fWide = TRUE; +#else // ANSI + pDrop->fWide = FALSE; +#endif // Unicode/Ansi + + // set start of filenames list (null separated) + wxChar *pbuf = (wxChar*) ((BYTE *)pDrop + sizeof(DROPFILES)); + + size_t count = m_filenames.GetCount(); + for (size_t i = 0; i < count; i++ ) + { + // copy filename to pbuf and add null terminator + size_t len = m_filenames[i].Len(); + memcpy(pbuf, m_filenames[i], len); + pbuf += len; + *pbuf++ = wxT('\0'); + } + + *pbuf = wxT('\0'); // add final null terminator + + return TRUE; +} + // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- -// otherwise VC++ would give here: -// "local variable 'bi' may be used without having been initialized" -// even though in fact it may not -#ifdef __VISUALC__ - #pragma warning(disable:4701) -#endif // __VISUALC__ +static size_t wxGetNumOfBitmapColors(size_t bitsPerPixel) +{ + switch ( bitsPerPixel ) + { + case 1: + // monochrome bitmap, 2 entries + return 2; + + case 4: + return 16; + + case 8: + return 256; + + case 24: + // may be used with 24bit bitmaps, but we don't use it here - fall + // through + + case 16: + case 32: + // bmiColors not used at all with these bitmaps + return 0; + + default: + wxFAIL_MSG( wxT("unknown bitmap format") ); + return 0; + } +} size_t wxConvertBitmapToDIB(BITMAPINFO *pbi, const wxBitmap& bitmap) { + wxASSERT_MSG( bitmap.Ok(), wxT("invalid bmp can't be converted to DIB") ); + // shouldn't be selected into a DC or GetDIBits() would fail wxASSERT_MSG( !bitmap.GetSelectedInto(), wxT("can't copy bitmap selected into wxMemoryDC") ); + // prepare all the info we need + BITMAP bm; HBITMAP hbmp = (HBITMAP)bitmap.GetHBITMAP(); + if ( !GetObject(hbmp, sizeof(bm), &bm) ) + { + wxLogLastError("GetObject(bitmap)"); + + return 0; + } + + // calculate the number of bits per pixel and the number of items in + // bmiColors array (whose meaning depends on the bitmap format) + WORD biBits = bm.bmPlanes * bm.bmBitsPixel; + WORD biColors = wxGetNumOfBitmapColors(biBits); + + BITMAPINFO bi2; + + bool wantSizeOnly = pbi == NULL; + if ( wantSizeOnly ) + pbi = &bi2; + + // just for convenience + BITMAPINFOHEADER& bi = pbi->bmiHeader; - BITMAPINFO bi; + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = bm.bmWidth; + bi.biHeight = bm.bmHeight; + bi.biPlanes = 1; + bi.biBitCount = biBits; + bi.biCompression = BI_RGB; + bi.biSizeImage = 0; + bi.biXPelsPerMeter = 0; + bi.biYPelsPerMeter = 0; + bi.biClrUsed = 0; + bi.biClrImportant = 0; - // first get the info + // memory we need for BITMAPINFO only + DWORD dwLen = bi.biSize + biColors * sizeof(RGBQUAD); + + // first get the image size ScreenHDC hdc; - if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi ? pbi : &bi, DIB_RGB_COLORS) ) + if ( !GetDIBits(hdc, hbmp, 0, bi.biHeight, NULL, pbi, DIB_RGB_COLORS) ) { wxLogLastError("GetDIBits(NULL)"); return 0; } - if ( !pbi ) + if ( wantSizeOnly ) { - // we were only asked for size needed for the buffer, not to actually - // copy the data - return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage; + // size of the header + size of the image + return dwLen + bi.biSizeImage; } // and now copy the bits - if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1, - pbi, DIB_RGB_COLORS) ) + void *image = (char *)pbi + dwLen; + if ( !GetDIBits(hdc, hbmp, 0, bi.biHeight, image, pbi, DIB_RGB_COLORS) ) { wxLogLastError("GetDIBits"); return 0; } - return sizeof(BITMAPINFO) + pbi->bmiHeader.biSizeImage; + return dwLen + bi.biSizeImage; } -#ifdef __VISUALC__ - #pragma warning(default:4701) -#endif // __VISUALC__ - wxBitmap wxConvertDIBToBitmap(const BITMAPINFO *pbmi) { // here we get BITMAPINFO struct followed by the actual bitmap bits and // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader; + // offset of image from the beginning of the header + DWORD ofs = wxGetNumOfBitmapColors(pbmih->biBitCount) * sizeof(RGBQUAD); + void *image = (char *)pbmih + sizeof(BITMAPINFOHEADER) + ofs; + ScreenHDC hdc; HBITMAP hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT, - pbmi + 1, pbmi, DIB_RGB_COLORS); + image, pbmi, DIB_RGB_COLORS); if ( !hbmp ) { wxLogLastError("CreateDIBitmap");