]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/clipbrd.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/clipbrd.cpp 
   3 // Purpose:     Clipboard functionality 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29 #include "wx/clipbrd.h" 
  32     #include "wx/object.h" 
  36     #include "wx/bitmap.h" 
  40     #include "wx/dataobj.h" 
  44     #include "wx/metafile.h" 
  50 #include "wx/msw/private.h" 
  51 #include "wx/msw/ole/oleutils.h" 
  54     #include "wx/msw/dib.h" 
  57 // wxDataObject is tied to OLE/drag and drop implementation, therefore so are 
  58 // the functions using wxDataObject in wxClipboard 
  59 //#define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP 
  61 #if wxUSE_OLE && !defined(__WXWINCE__) 
  63     #define wxUSE_OLE_CLIPBOARD 1 
  64 #else // !wxUSE_DATAOBJ 
  65     // use Win clipboard API 
  66     #define wxUSE_OLE_CLIPBOARD 0 
  69 #if wxUSE_OLE_CLIPBOARD 
  71 #endif // wxUSE_OLE_CLIPBOARD 
  73 // =========================================================================== 
  75 // =========================================================================== 
  77 // --------------------------------------------------------------------------- 
  78 // old-style clipboard functions using Windows API 
  79 // --------------------------------------------------------------------------- 
  81 static bool gs_wxClipboardIsOpen 
= false; 
  83 bool wxOpenClipboard() 
  85     wxCHECK_MSG( !gs_wxClipboardIsOpen
, true, wxT("clipboard already opened.") ); 
  87     wxWindow 
*win 
= wxTheApp
->GetTopWindow(); 
  90         gs_wxClipboardIsOpen 
= ::OpenClipboard((HWND
)win
->GetHWND()) != 0; 
  92         if ( !gs_wxClipboardIsOpen 
) 
  93             wxLogSysError(_("Failed to open the clipboard.")); 
  95         return gs_wxClipboardIsOpen
; 
  99         wxLogDebug(wxT("Can not open clipboard without a main window.")); 
 105 bool wxCloseClipboard() 
 107     wxCHECK_MSG( gs_wxClipboardIsOpen
, false, wxT("clipboard is not opened") ); 
 109     gs_wxClipboardIsOpen 
= false; 
 111     if ( ::CloseClipboard() == 0 ) 
 113         wxLogSysError(_("Failed to close the clipboard.")); 
 121 bool wxEmptyClipboard() 
 123     if ( ::EmptyClipboard() == 0 ) 
 125         wxLogSysError(_("Failed to empty the clipboard.")); 
 133 bool wxIsClipboardOpened() 
 135   return gs_wxClipboardIsOpen
; 
 138 bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat
) 
 140    wxDataFormat::NativeFormat cf 
= dataFormat
.GetFormatId(); 
 142     if ( ::IsClipboardFormatAvailable(cf
) ) 
 144         // ok from the first try 
 148     // for several standard formats, we can convert from some other ones too 
 151         // for bitmaps, DIBs will also do 
 153             return ::IsClipboardFormatAvailable(CF_DIB
) != 0; 
 155 #if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) 
 156         case CF_METAFILEPICT
: 
 157             return ::IsClipboardFormatAvailable(CF_ENHMETAFILE
) != 0; 
 158 #endif // wxUSE_ENH_METAFILE 
 166 bool wxSetClipboardData(wxDataFormat dataFormat
, 
 168                         int width
, int height
) 
 170     HANDLE handle 
= 0; // return value of SetClipboardData 
 176                 wxBitmap 
*bitmap 
= (wxBitmap 
*)data
; 
 178                 HDC hdcMem 
= CreateCompatibleDC((HDC
) NULL
); 
 179                 HDC hdcSrc 
= CreateCompatibleDC((HDC
) NULL
); 
 180                 HBITMAP old 
= (HBITMAP
) 
 181                     ::SelectObject(hdcSrc
, (HBITMAP
)bitmap
->GetHBITMAP()); 
 182                 HBITMAP hBitmap 
= CreateCompatibleBitmap(hdcSrc
, 
 184                                                          bitmap
->GetHeight()); 
 187                     SelectObject(hdcSrc
, old
); 
 193                 HBITMAP old1 
= (HBITMAP
) SelectObject(hdcMem
, hBitmap
); 
 194                 BitBlt(hdcMem
, 0, 0, bitmap
->GetWidth(), bitmap
->GetHeight(), 
 195                        hdcSrc
, 0, 0, SRCCOPY
); 
 197                 // Select new bitmap out of memory DC 
 198                 SelectObject(hdcMem
, old1
); 
 201                 handle 
= ::SetClipboardData(CF_BITMAP
, hBitmap
); 
 204                 SelectObject(hdcSrc
, old
); 
 213                 wxBitmap 
*bitmap 
= (wxBitmap 
*)data
; 
 215                 if ( bitmap 
&& bitmap
->Ok() ) 
 220                         handle 
= ::SetClipboardData(CF_DIB
, dib
.Detach()); 
 227     // VZ: I'm told that this code works, but it doesn't seem to work for me 
 228     //     and, anyhow, I'd be highly surprised if it did. So I leave it here 
 229     //     but IMNSHO it is completely broken. 
 230 #if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) && !defined(__WXWINCE__) 
 233                 wxMetafile 
*wxMF 
= (wxMetafile 
*)data
; 
 234                 HANDLE data 
= GlobalAlloc(GHND
, sizeof(METAFILEPICT
) + 1); 
 235                 METAFILEPICT 
*mf 
= (METAFILEPICT 
*)GlobalLock(data
); 
 237                 mf
->mm 
= wxMF
->GetWindowsMappingMode(); 
 240                 mf
->hMF 
= (HMETAFILE
) wxMF
->GetHMETAFILE(); 
 242                 wxMF
->SetHMETAFILE((WXHANDLE
) NULL
); 
 244                 handle 
= SetClipboardData(CF_METAFILEPICT
, data
); 
 247 #endif // wxUSE_METAFILE 
 249 #if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) 
 250         case wxDF_ENHMETAFILE
: 
 252                 wxEnhMetaFile 
*emf 
= (wxEnhMetaFile 
*)data
; 
 253                 wxEnhMetaFile emfCopy 
= *emf
; 
 255                 handle 
= SetClipboardData(CF_ENHMETAFILE
, 
 256                                           (void *)emfCopy
.GetHENHMETAFILE()); 
 259 #endif // wxUSE_ENH_METAFILE 
 267                 wxLogError(_("Unsupported clipboard format.")); 
 272             dataFormat 
= wxDF_TEXT
; 
 277                 char *s 
= (char *)data
; 
 279                 width 
= strlen(s
) + 1; 
 281                 DWORD l 
= (width 
* height
); 
 282                 HANDLE hGlobalMemory 
= GlobalAlloc(GHND
, l
); 
 285                     LPSTR lpGlobalMemory 
= (LPSTR
)GlobalLock(hGlobalMemory
); 
 287                     memcpy(lpGlobalMemory
, s
, l
); 
 289                     GlobalUnlock(hGlobalMemory
); 
 292                 handle 
= SetClipboardData(dataFormat
, hGlobalMemory
); 
 295             // Only tested with Visual C++ 6.0 so far 
 296 #if defined(__VISUALC__) 
 299                 char* html 
= (char *)data
; 
 301                 // Create temporary buffer for HTML header... 
 302                 char *buf 
= new char [400 + strlen(html
)]; 
 303                 if(!buf
) return false; 
 305                 // Get clipboard id for HTML format... 
 307                 if(!cfid
) cfid 
= RegisterClipboardFormat(wxT("HTML Format")); 
 309                 // Create a template string for the HTML header... 
 312                     "StartHTML:00000000\r\n" 
 313                     "EndHTML:00000000\r\n" 
 314                     "StartFragment:00000000\r\n" 
 315                     "EndFragment:00000000\r\n" 
 317                     "<!--StartFragment -->\r\n"); 
 319                 // Append the HTML... 
 322                 // Finish up the HTML format... 
 324                     "<!--EndFragment-->\r\n" 
 328                 // Now go back, calculate all the lengths, and write out the 
 329                 // necessary header information. Note, wsprintf() truncates the 
 330                 // string when you overwrite it so you follow up with code to replace 
 331                 // the 0 appended at the end with a '\r'... 
 332                 char *ptr 
= strstr(buf
, "StartHTML"); 
 333                 sprintf(ptr
+10, "%08u", strstr(buf
, "<html>") - buf
); 
 336                 ptr 
= strstr(buf
, "EndHTML"); 
 337                 sprintf(ptr
+8, "%08u", strlen(buf
)); 
 340                 ptr 
= strstr(buf
, "StartFragment"); 
 341                 sprintf(ptr
+14, "%08u", strstr(buf
, "<!--StartFrag") - buf
); 
 344                 ptr 
= strstr(buf
, "EndFragment"); 
 345                 sprintf(ptr
+12, "%08u", strstr(buf
, "<!--EndFrag") - buf
); 
 348                 // Now you have everything in place ready to put on the 
 351                 // Allocate global memory for transfer... 
 352                 HGLOBAL hText 
= GlobalAlloc(GMEM_MOVEABLE 
|GMEM_DDESHARE
, strlen(buf
)+4); 
 354                 // Put your string in the global memory... 
 355                 ptr 
= (char *)GlobalLock(hText
); 
 359                 handle 
= ::SetClipboardData(cfid
, hText
); 
 373         wxLogSysError(_("Failed to set clipboard data.")); 
 381 void *wxGetClipboardData(wxDataFormat dataFormat
, long *len
) 
 385     switch ( dataFormat 
) 
 391                 HBITMAP hBitmap 
= (HBITMAP
) GetClipboardData(CF_BITMAP
); 
 395                 HDC hdcMem 
= CreateCompatibleDC((HDC
) NULL
); 
 396                 HDC hdcSrc 
= CreateCompatibleDC((HDC
) NULL
); 
 398                 HBITMAP old 
= (HBITMAP
) ::SelectObject(hdcSrc
, hBitmap
); 
 399                 GetObject(hBitmap
, sizeof(BITMAP
), (LPSTR
)&bm
); 
 401                 HBITMAP hNewBitmap 
= CreateBitmapIndirect(&bm
); 
 405                     SelectObject(hdcSrc
, old
); 
 411                 HBITMAP old1 
= (HBITMAP
) SelectObject(hdcMem
, hNewBitmap
); 
 412                 BitBlt(hdcMem
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, 
 413                        hdcSrc
, 0, 0, SRCCOPY
); 
 415                 // Select new bitmap out of memory DC 
 416                 SelectObject(hdcMem
, old1
); 
 419                 SelectObject(hdcSrc
, old
); 
 423                 // Create and return a new wxBitmap 
 424                 wxBitmap 
*wxBM 
= new wxBitmap
; 
 425                 wxBM
->SetHBITMAP((WXHBITMAP
) hNewBitmap
); 
 426                 wxBM
->SetWidth(bm
.bmWidth
); 
 427                 wxBM
->SetHeight(bm
.bmHeight
); 
 428                 wxBM
->SetDepth(bm
.bmPlanes
); 
 439             wxLogError(_("Unsupported clipboard format.")); 
 443             dataFormat 
= wxDF_TEXT
; 
 448                 HANDLE hGlobalMemory 
= ::GetClipboardData(dataFormat
); 
 452                 DWORD hsize 
= ::GlobalSize(hGlobalMemory
); 
 456                 char *s 
= new char[hsize
]; 
 460                 LPSTR lpGlobalMemory 
= (LPSTR
) GlobalLock(hGlobalMemory
); 
 462                 memcpy(s
, lpGlobalMemory
, hsize
); 
 464                 GlobalUnlock(hGlobalMemory
); 
 472                 HANDLE hGlobalMemory 
= ::GetClipboardData(dataFormat
); 
 473                 if ( !hGlobalMemory 
) 
 476                 DWORD size 
= ::GlobalSize(hGlobalMemory
); 
 480                 void *buf 
= malloc(size
); 
 484                 LPSTR lpGlobalMemory 
= (LPSTR
) GlobalLock(hGlobalMemory
); 
 486                 memcpy(buf
, lpGlobalMemory
, size
); 
 488                 GlobalUnlock(hGlobalMemory
); 
 497         wxLogSysError(_("Failed to retrieve data from the clipboard.")); 
 503 wxDataFormat 
wxEnumClipboardFormats(wxDataFormat dataFormat
) 
 505   return (wxDataFormat::NativeFormat
)::EnumClipboardFormats(dataFormat
); 
 508 int wxRegisterClipboardFormat(wxChar 
*formatName
) 
 510   return ::RegisterClipboardFormat(formatName
); 
 513 bool wxGetClipboardFormatName(wxDataFormat dataFormat
, 
 517   return ::GetClipboardFormatName((int)dataFormat
, formatName
, maxCount
) > 0; 
 520 // --------------------------------------------------------------------------- 
 522 // --------------------------------------------------------------------------- 
 524 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
, wxObject
) 
 526 wxClipboard::wxClipboard() 
 528 #if wxUSE_OLE_CLIPBOARD 
 532     m_lastDataObject 
= NULL
; 
 536 wxClipboard::~wxClipboard() 
 538     if ( m_lastDataObject 
) 
 543 #if wxUSE_OLE_CLIPBOARD 
 548 void wxClipboard::Clear() 
 550 #if wxUSE_OLE_CLIPBOARD 
 551     if (m_lastDataObject
) 
 553         // don't touch data set by other applications 
 554         HRESULT hr 
= OleIsCurrentClipboard(m_lastDataObject
); 
 557             hr 
= OleSetClipboard(NULL
); 
 560         wxLogApiError(wxT("OleSetClipboard(NULL)"), hr
); 
 563         m_lastDataObject 
= NULL
; 
 565 #endif // wxUSE_OLE_CLIPBOARD 
 568 bool wxClipboard::Flush() 
 570 #if wxUSE_OLE_CLIPBOARD 
 571     if (m_lastDataObject
) 
 573         // don't touch data set by other applications 
 574         HRESULT hr 
= OleIsCurrentClipboard(m_lastDataObject
); 
 575         m_lastDataObject 
= NULL
; 
 578             hr 
= OleFlushClipboard(); 
 581         wxLogApiError(wxT("OleFlushClipboard"), hr
); 
 589 #else // !wxUSE_OLE_CLIPBOARD 
 591 #endif // wxUSE_OLE_CLIPBOARD/!wxUSE_OLE_CLIPBOARD 
 594 bool wxClipboard::Open() 
 596     // OLE opens clipboard for us 
 598 #if wxUSE_OLE_CLIPBOARD 
 601     return wxOpenClipboard(); 
 605 bool wxClipboard::IsOpened() const 
 607 #if wxUSE_OLE_CLIPBOARD 
 610     return wxIsClipboardOpened(); 
 614 bool wxClipboard::SetData( wxDataObject 
*data 
) 
 616 #if !wxUSE_OLE_CLIPBOARD 
 617     (void)wxEmptyClipboard(); 
 618 #endif // wxUSE_OLE_CLIPBOARD 
 621         return AddData(data
); 
 626 bool wxClipboard::AddData( wxDataObject 
*data 
) 
 628     wxCHECK_MSG( data
, false, wxT("data is invalid") ); 
 630 #if wxUSE_OLE_CLIPBOARD 
 631     HRESULT hr 
= OleSetClipboard(data
->GetInterface()); 
 634         wxLogSysError(hr
, _("Failed to put data on the clipboard")); 
 636         // don't free anything in this case 
 641     // we have to call either OleSetClipboard(NULL) or OleFlushClipboard() when 
 642     // using OLE clipboard when the app terminates - by default, we call 
 643     // OleSetClipboard(NULL) which won't waste RAM, but the app can call 
 644     // wxClipboard::Flush() to change this 
 645     m_lastDataObject 
= data
->GetInterface(); 
 647     // we have a problem here because we should delete wxDataObject, but we 
 648     // can't do it because IDataObject which we just gave to the clipboard 
 649     // would try to use it when it will need the data. IDataObject is ref 
 650     // counted and so doesn't suffer from such problem, so we release it now 
 651     // and tell it to delete wxDataObject when it is deleted itself. 
 652     data
->SetAutoDelete(); 
 656     wxCHECK_MSG( wxIsClipboardOpened(), false, wxT("clipboard not open") ); 
 658     wxDataFormat format 
= data
->GetPreferredFormat(); 
 665             wxTextDataObject
* textDataObject 
= (wxTextDataObject
*) data
; 
 666             wxString 
str(textDataObject
->GetText()); 
 667             return wxSetClipboardData(format
, str
.c_str()); 
 673             wxBitmapDataObject
* bitmapDataObject 
= (wxBitmapDataObject
*) data
; 
 674             wxBitmap 
bitmap(bitmapDataObject
->GetBitmap()); 
 675             return wxSetClipboardData(data
->GetPreferredFormat(), &bitmap
); 
 683             wxLogError(wxT("Not implemented because wxMetafileDataObject does not contain width and height values.")); 
 686             wxMetafileDataObject
* metaFileDataObject 
= 
 687                 (wxMetafileDataObject
*) data
; 
 688             wxMetafile metaFile 
= metaFileDataObject
->GetMetafile(); 
 689             return wxSetClipboardData(wxDF_METAFILE
, &metaFile
, 
 690                                       metaFileDataObject
->GetWidth(), 
 691                                       metaFileDataObject
->GetHeight()); 
 694 #endif // wxUSE_METAFILE 
 698 // This didn't compile, of course 
 699 //            return wxSetClipboardData(data); 
 701             wxLogError(wxT("Not implemented.")); 
 705 #else // !wxUSE_DATAOBJ 
 707 #endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ 
 710 void wxClipboard::Close() 
 713     // OLE closes clipboard for us 
 714 #if !wxUSE_OLE_CLIPBOARD 
 719 bool wxClipboard::IsSupported( const wxDataFormat
& format 
) 
 721     return wxIsClipboardFormatAvailable(format
); 
 724 bool wxClipboard::GetData( wxDataObject
& data 
) 
 726 #if wxUSE_OLE_CLIPBOARD 
 727     IDataObject 
*pDataObject 
= NULL
; 
 728     HRESULT hr 
= OleGetClipboard(&pDataObject
); 
 729     if ( FAILED(hr
) || !pDataObject 
) 
 731         wxLogSysError(hr
, _("Failed to get data from the clipboard")); 
 736     // build the list of supported formats 
 737     size_t nFormats 
= data
.GetFormatCount(wxDataObject::Set
); 
 739     wxDataFormat 
*formats
; 
 742         // the most common case 
 747         // bad luck, need to alloc mem 
 748         formats 
= new wxDataFormat
[nFormats
]; 
 751     data
.GetAllFormats(formats
, wxDataObject::Set
); 
 753     // get the data for the given formats 
 758     // enumerate all explicit formats on the clipboard. 
 759     // note that this does not include implicit / synthetic (automatically 
 760     // converted) formats. 
 762     // get the format enumerator 
 763     IEnumFORMATETC 
*pEnumFormatEtc 
= NULL
; 
 764     hr 
= pDataObject
->EnumFormatEtc(DATADIR_GET
, &pEnumFormatEtc
); 
 765     if ( FAILED(hr
) || !pEnumFormatEtc 
) 
 768                       _("Failed to retrieve the supported clipboard formats")); 
 772         // ask for the supported formats and see if there are any we support 
 776             hr 
= pEnumFormatEtc
->Next(1, &formatEtc
, &nCount
); 
 778             // don't use FAILED() because S_FALSE would pass it 
 785             cf 
= formatEtc
.cfFormat
; 
 787             wxLogTrace(wxTRACE_OleCalls
, 
 788                        wxT("Object on the clipboard supports format %s."), 
 789                        wxDataObject::GetFormatName(cf
)); 
 792         pEnumFormatEtc
->Release(); 
 797     // stop at the first valid format found on the clipboard 
 798     for ( size_t n 
= 0; !result 
&& (n 
< nFormats
); n
++ ) 
 800         // convert to NativeFormat Id 
 801         cf 
= formats
[n
].GetFormatId(); 
 803         // if the format is not available, try the next one 
 804         // this test includes implicit / sythetic formats 
 805         if ( !::IsClipboardFormatAvailable(cf
) ) 
 808         formatEtc
.cfFormat 
= cf
; 
 809         formatEtc
.ptd      
= NULL
; 
 810         formatEtc
.dwAspect 
= DVASPECT_CONTENT
; 
 811         formatEtc
.lindex   
= -1; 
 813         // use the appropriate tymed 
 814         switch ( formatEtc
.cfFormat 
) 
 817                 formatEtc
.tymed 
= TYMED_GDI
; 
 821             case CF_METAFILEPICT
: 
 822                 formatEtc
.tymed 
= TYMED_MFPICT
; 
 826                 formatEtc
.tymed 
= TYMED_ENHMF
; 
 831                 formatEtc
.tymed 
= TYMED_HGLOBAL
; 
 835         hr 
= pDataObject
->GetData(&formatEtc
, &medium
); 
 838             // try other tymed for GDI objects 
 839             if ( formatEtc
.cfFormat 
== CF_BITMAP 
) 
 841                 formatEtc
.tymed 
= TYMED_HGLOBAL
; 
 842                 hr 
= pDataObject
->GetData(&formatEtc
, &medium
); 
 848             // pass the data to the data object 
 849             hr 
= data
.GetInterface()->SetData(&formatEtc
, &medium
, true); 
 852                 wxLogDebug(wxT("Failed to set data in wxIDataObject")); 
 854                 // IDataObject only takes the ownership of data if it 
 855                 // successfully got it - which is not the case here 
 856                 ReleaseStgMedium(&medium
); 
 863         //else: unsupported tymed? 
 866     if ( formats 
!= &format 
) 
 870     //else: we didn't allocate any memory 
 872     // clean up and return 
 873     pDataObject
->Release(); 
 877     wxCHECK_MSG( wxIsClipboardOpened(), false, wxT("clipboard not open") ); 
 879     wxDataFormat format 
= data
.GetPreferredFormat(); 
 885             wxTextDataObject
& textDataObject 
= (wxTextDataObject 
&)data
; 
 886             char* s 
= (char*)wxGetClipboardData(format
); 
 890             textDataObject
.SetText(wxString::FromAscii(s
)); 
 899             wxBitmapDataObject
& bitmapDataObject 
= (wxBitmapDataObject 
&)data
; 
 900             wxBitmap
* bitmap 
= (wxBitmap 
*)wxGetClipboardData(data
.GetPreferredFormat()); 
 904             bitmapDataObject
.SetBitmap(*bitmap
); 
 912             wxMetafileDataObject
& metaFileDataObject 
= (wxMetafileDataObject 
&)data
; 
 913             wxMetafile
* metaFile 
= (wxMetafile 
*)wxGetClipboardData(wxDF_METAFILE
); 
 917             metaFileDataObject
.SetMetafile(*metaFile
); 
 922 #endif // wxUSE_METAFILE 
 925 #else // !wxUSE_DATAOBJ 
 926     wxFAIL_MSG( wxT("no clipboard implementation") ); 
 928 #endif // wxUSE_OLE_CLIPBOARD/wxUSE_DATAOBJ 
 931 #endif // wxUSE_CLIPBOARD