]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/clipbrd.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Clipboard functionality 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "clipbrd.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  38     #include "wx/object.h" 
  42     #include "wx/bitmap.h" 
  48     #include "wx/metafile.h" 
  52 #include "wx/clipbrd.h" 
  56 #include "wx/msw/private.h" 
  59 #include "wx/msw/dib.h" 
  62 // wxDataObject is tied to OLE/drag and drop implementation, therefore so are 
  63 // the functions using wxDataObject in wxClipboard 
  64 //#define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP 
  67     #include "wx/dataobj.h" 
  70 #if wxUSE_OLE && !defined(__WXWINCE__) 
  72     #define wxUSE_OLE_CLIPBOARD 1 
  73 #else // !wxUSE_DATAOBJ 
  74     // use Win clipboard API 
  75     #define wxUSE_OLE_CLIPBOARD 0 
  78 #if wxUSE_OLE_CLIPBOARD 
  80 #endif // wxUSE_OLE_CLIPBOARD 
  82 // =========================================================================== 
  84 // =========================================================================== 
  86 // --------------------------------------------------------------------------- 
  87 // old-style clipboard functions using Windows API 
  88 // --------------------------------------------------------------------------- 
  90 static bool gs_wxClipboardIsOpen 
= FALSE
; 
  92 bool wxOpenClipboard() 
  94     wxCHECK_MSG( !gs_wxClipboardIsOpen
, TRUE
, wxT("clipboard already opened.") ); 
  96     wxWindow 
*win 
= wxTheApp
->GetTopWindow(); 
  99         gs_wxClipboardIsOpen 
= ::OpenClipboard((HWND
)win
->GetHWND()) != 0; 
 101         if ( !gs_wxClipboardIsOpen 
) 
 102             wxLogSysError(_("Failed to open the clipboard.")); 
 104         return gs_wxClipboardIsOpen
; 
 108         wxLogDebug(wxT("Can not open clipboard without a main window.")); 
 114 bool wxCloseClipboard() 
 116     wxCHECK_MSG( gs_wxClipboardIsOpen
, FALSE
, wxT("clipboard is not opened") ); 
 118     gs_wxClipboardIsOpen 
= FALSE
; 
 120     if ( ::CloseClipboard() == 0 ) 
 122         wxLogSysError(_("Failed to close the clipboard.")); 
 130 bool wxEmptyClipboard() 
 132     if ( ::EmptyClipboard() == 0 ) 
 134         wxLogSysError(_("Failed to empty the clipboard.")); 
 142 bool wxIsClipboardOpened() 
 144   return gs_wxClipboardIsOpen
; 
 147 bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat
) 
 149    wxDataFormat::NativeFormat cf 
= dataFormat
.GetFormatId(); 
 151     if ( ::IsClipboardFormatAvailable(cf
) ) 
 153         // ok from the first try 
 157     // for several standard formats, we can convert from some other ones too 
 160         // for bitmaps, DIBs will also do 
 162             return ::IsClipboardFormatAvailable(CF_DIB
) != 0; 
 164 #if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) 
 165         case CF_METAFILEPICT
: 
 166             return ::IsClipboardFormatAvailable(CF_ENHMETAFILE
) != 0; 
 167 #endif // wxUSE_ENH_METAFILE 
 175 bool wxSetClipboardData(wxDataFormat dataFormat
, 
 177                         int width
, int height
) 
 179     HANDLE handle 
= 0; // return value of SetClipboardData 
 185                 wxBitmap 
*bitmap 
= (wxBitmap 
*)data
; 
 187                 HDC hdcMem 
= CreateCompatibleDC((HDC
) NULL
); 
 188                 HDC hdcSrc 
= CreateCompatibleDC((HDC
) NULL
); 
 189                 HBITMAP old 
= (HBITMAP
) 
 190                     ::SelectObject(hdcSrc
, (HBITMAP
)bitmap
->GetHBITMAP()); 
 191                 HBITMAP hBitmap 
= CreateCompatibleBitmap(hdcSrc
, 
 193                                                          bitmap
->GetHeight()); 
 196                     SelectObject(hdcSrc
, old
); 
 202                 HBITMAP old1 
= (HBITMAP
) SelectObject(hdcMem
, hBitmap
); 
 203                 BitBlt(hdcMem
, 0, 0, bitmap
->GetWidth(), bitmap
->GetHeight(), 
 204                        hdcSrc
, 0, 0, SRCCOPY
); 
 206                 // Select new bitmap out of memory DC 
 207                 SelectObject(hdcMem
, old1
); 
 210                 handle 
= ::SetClipboardData(CF_BITMAP
, hBitmap
); 
 213                 SelectObject(hdcSrc
, old
); 
 222                 wxBitmap 
*bitmap 
= (wxBitmap 
*)data
; 
 224                 if ( bitmap 
&& bitmap
->Ok() ) 
 229                         handle 
= ::SetClipboardData(CF_DIB
, dib
.Detach()); 
 236     // VZ: I'm told that this code works, but it doesn't seem to work for me 
 237     //     and, anyhow, I'd be highly surprised if it did. So I leave it here 
 238     //     but IMNSHO it is completely broken. 
 239 #if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) && !defined(__WXWINCE__) 
 242                 wxMetafile 
*wxMF 
= (wxMetafile 
*)data
; 
 243                 HANDLE data 
= GlobalAlloc(GHND
, sizeof(METAFILEPICT
) + 1); 
 244                 METAFILEPICT 
*mf 
= (METAFILEPICT 
*)GlobalLock(data
); 
 246                 mf
->mm 
= wxMF
->GetWindowsMappingMode(); 
 249                 mf
->hMF 
= (HMETAFILE
) wxMF
->GetHMETAFILE(); 
 251                 wxMF
->SetHMETAFILE((WXHANDLE
) NULL
); 
 253                 handle 
= SetClipboardData(CF_METAFILEPICT
, data
); 
 256 #endif // wxUSE_METAFILE 
 258 #if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) 
 259         case wxDF_ENHMETAFILE
: 
 261                 wxEnhMetaFile 
*emf 
= (wxEnhMetaFile 
*)data
; 
 262                 wxEnhMetaFile emfCopy 
= *emf
; 
 264                 handle 
= SetClipboardData(CF_ENHMETAFILE
, 
 265                                           (void *)emfCopy
.GetHENHMETAFILE()); 
 268 #endif // wxUSE_ENH_METAFILE 
 276                 wxLogError(_("Unsupported clipboard format.")); 
 281             dataFormat 
= wxDF_TEXT
; 
 286                 char *s 
= (char *)data
; 
 288                 width 
= strlen(s
) + 1; 
 290                 DWORD l 
= (width 
* height
); 
 291                 HANDLE hGlobalMemory 
= GlobalAlloc(GHND
, l
); 
 294                     LPSTR lpGlobalMemory 
= (LPSTR
)GlobalLock(hGlobalMemory
); 
 296                     memcpy(lpGlobalMemory
, s
, l
); 
 298                     GlobalUnlock(hGlobalMemory
); 
 301                 handle 
= SetClipboardData(dataFormat
, hGlobalMemory
); 
 304             // Only tested with non-Unicode, Visual C++ 6.0 so far 
 305 #if defined(__VISUALC__) && !defined(UNICODE) 
 308                 char* html 
= (char *)data
; 
 310                 // Create temporary buffer for HTML header... 
 311                 char *buf 
= new char [400 + strlen(html
)]; 
 312                 if(!buf
) return FALSE
; 
 314                 // Get clipboard id for HTML format... 
 316                 if(!cfid
) cfid 
= RegisterClipboardFormat(wxT("HTML Format")); 
 318                 // Create a template string for the HTML header... 
 321                     "StartHTML:00000000\r\n" 
 322                     "EndHTML:00000000\r\n" 
 323                     "StartFragment:00000000\r\n" 
 324                     "EndFragment:00000000\r\n" 
 326                     "<!--StartFragment -->\r\n"); 
 328                 // Append the HTML... 
 331                 // Finish up the HTML format... 
 333                     "<!--EndFragment-->\r\n" 
 337                 // Now go back, calculate all the lengths, and write out the 
 338                 // necessary header information. Note, wsprintf() truncates the 
 339                 // string when you overwrite it so you follow up with code to replace 
 340                 // the 0 appended at the end with a '\r'... 
 341                 char *ptr 
= strstr(buf
, "StartHTML"); 
 342                 wsprintf(ptr
+10, "%08u", strstr(buf
, "<html>") - buf
); 
 345                 ptr 
= strstr(buf
, "EndHTML"); 
 346                 wsprintf(ptr
+8, "%08u", strlen(buf
)); 
 349                 ptr 
= strstr(buf
, "StartFragment"); 
 350                 wsprintf(ptr
+14, "%08u", strstr(buf
, "<!--StartFrag") - buf
); 
 353                 ptr 
= strstr(buf
, "EndFragment"); 
 354                 wsprintf(ptr
+12, "%08u", strstr(buf
, "<!--EndFrag") - buf
); 
 357                 // Now you have everything in place ready to put on the 
 360                 // Allocate global memory for transfer... 
 361                 HGLOBAL hText 
= GlobalAlloc(GMEM_MOVEABLE 
|GMEM_DDESHARE
, strlen(buf
)+4); 
 363                 // Put your string in the global memory... 
 364                 ptr 
= (char *)GlobalLock(hText
); 
 368                 handle 
= ::SetClipboardData(cfid
, hText
); 
 382         wxLogSysError(_("Failed to set clipboard data.")); 
 390 void *wxGetClipboardData(wxDataFormat dataFormat
, long *len
) 
 394     switch ( dataFormat 
) 
 400                 HBITMAP hBitmap 
= (HBITMAP
) GetClipboardData(CF_BITMAP
); 
 404                 HDC hdcMem 
= CreateCompatibleDC((HDC
) NULL
); 
 405                 HDC hdcSrc 
= CreateCompatibleDC((HDC
) NULL
); 
 407                 HBITMAP old 
= (HBITMAP
) ::SelectObject(hdcSrc
, hBitmap
); 
 408                 GetObject(hBitmap
, sizeof(BITMAP
), (LPSTR
)&bm
); 
 410                 HBITMAP hNewBitmap 
= CreateBitmapIndirect(&bm
); 
 414                     SelectObject(hdcSrc
, old
); 
 420                 HBITMAP old1 
= (HBITMAP
) SelectObject(hdcMem
, hNewBitmap
); 
 421                 BitBlt(hdcMem
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, 
 422                        hdcSrc
, 0, 0, SRCCOPY
); 
 424                 // Select new bitmap out of memory DC 
 425                 SelectObject(hdcMem
, old1
); 
 428                 SelectObject(hdcSrc
, old
); 
 432                 // Create and return a new wxBitmap 
 433                 wxBitmap 
*wxBM 
= new wxBitmap
; 
 434                 wxBM
->SetHBITMAP((WXHBITMAP
) hNewBitmap
); 
 435                 wxBM
->SetWidth(bm
.bmWidth
); 
 436                 wxBM
->SetHeight(bm
.bmHeight
); 
 437                 wxBM
->SetDepth(bm
.bmPlanes
); 
 448             wxLogError(_("Unsupported clipboard format.")); 
 452             dataFormat 
= wxDF_TEXT
; 
 457                 HANDLE hGlobalMemory 
= ::GetClipboardData(dataFormat
); 
 461                 DWORD hsize 
= ::GlobalSize(hGlobalMemory
); 
 465                 char *s 
= new char[hsize
]; 
 469                 LPSTR lpGlobalMemory 
= (LPSTR
) GlobalLock(hGlobalMemory
); 
 471                 memcpy(s
, lpGlobalMemory
, hsize
); 
 473                 GlobalUnlock(hGlobalMemory
); 
 481                 HANDLE hGlobalMemory 
= ::GetClipboardData(dataFormat
); 
 482                 if ( !hGlobalMemory 
) 
 485                 DWORD size 
= ::GlobalSize(hGlobalMemory
); 
 489                 void *buf 
= malloc(size
); 
 493                 LPSTR lpGlobalMemory 
= (LPSTR
) GlobalLock(hGlobalMemory
); 
 495                 memcpy(buf
, lpGlobalMemory
, size
); 
 497                 GlobalUnlock(hGlobalMemory
); 
 506         wxLogSysError(_("Failed to retrieve data from the clipboard.")); 
 512 wxDataFormat 
wxEnumClipboardFormats(wxDataFormat dataFormat
) 
 514   return (wxDataFormat::NativeFormat
)::EnumClipboardFormats(dataFormat
); 
 517 int wxRegisterClipboardFormat(wxChar 
*formatName
) 
 519   return ::RegisterClipboardFormat(formatName
); 
 522 bool wxGetClipboardFormatName(wxDataFormat dataFormat
, 
 526   return ::GetClipboardFormatName((int)dataFormat
, formatName
, maxCount
) > 0; 
 529 // --------------------------------------------------------------------------- 
 531 // --------------------------------------------------------------------------- 
 533 IMPLEMENT_DYNAMIC_CLASS(wxClipboard
, wxObject
) 
 535 wxClipboard::wxClipboard() 
 537     m_clearOnExit 
= FALSE
; 
 541 wxClipboard::~wxClipboard() 
 549 void wxClipboard::Clear() 
 551 #if wxUSE_OLE_CLIPBOARD 
 552     if ( FAILED(OleSetClipboard(NULL
)) ) 
 554         wxLogLastError(wxT("OleSetClipboard(NULL)")); 
 559 bool wxClipboard::Flush() 
 561 #if wxUSE_OLE_CLIPBOARD 
 562     if ( FAILED(OleFlushClipboard()) ) 
 564         wxLogLastError(wxT("OleFlushClipboard")); 
 570         m_clearOnExit 
= FALSE
; 
 574 #else // !wxUSE_OLE_CLIPBOARD 
 576 #endif // wxUSE_OLE_CLIPBOARD/!wxUSE_OLE_CLIPBOARD 
 579 bool wxClipboard::Open() 
 581     // OLE opens clipboard for us 
 583 #if wxUSE_OLE_CLIPBOARD 
 586     return wxOpenClipboard(); 
 590 bool wxClipboard::IsOpened() const 
 592 #if wxUSE_OLE_CLIPBOARD 
 595     return wxIsClipboardOpened(); 
 599 bool wxClipboard::SetData( wxDataObject 
*data 
) 
 601 #if !wxUSE_OLE_CLIPBOARD 
 602     (void)wxEmptyClipboard(); 
 603 #endif // wxUSE_OLE_CLIPBOARD 
 606         return AddData(data
); 
 611 bool wxClipboard::AddData( wxDataObject 
*data 
) 
 613     wxCHECK_MSG( data
, FALSE
, wxT("data is invalid") ); 
 615 #if wxUSE_OLE_CLIPBOARD 
 616     HRESULT hr 
= OleSetClipboard(data
->GetInterface()); 
 619         wxLogSysError(hr
, _("Failed to put data on the clipboard")); 
 621         // don't free anything in this case 
 626     // we have a problem here because we should delete wxDataObject, but we 
 627     // can't do it because IDataObject which we just gave to the clipboard 
 628     // would try to use it when it will need the data. IDataObject is ref 
 629     // counted and so doesn't suffer from such problem, so we release it now 
 630     // and tell it to delete wxDataObject when it is deleted itself. 
 631     data
->SetAutoDelete(); 
 633     // we have to call either OleSetClipboard(NULL) or OleFlushClipboard() when 
 634     // using OLE clipboard when the app terminates - by default, we call 
 635     // OleSetClipboard(NULL) which won't waste RAM, but the app can call 
 636     // wxClipboard::Flush() to chaneg this 
 637     m_clearOnExit 
= TRUE
; 
 641     wxCHECK_MSG( wxIsClipboardOpened(), FALSE
, wxT("clipboard not open") ); 
 643     wxDataFormat format 
= data
->GetPreferredFormat(); 
 650             wxTextDataObject
* textDataObject 
= (wxTextDataObject
*) data
; 
 651             wxString 
str(textDataObject
->GetText()); 
 652             return wxSetClipboardData(format
, str
.c_str()); 
 658             wxBitmapDataObject
* bitmapDataObject 
= (wxBitmapDataObject
*) data
; 
 659             wxBitmap 
bitmap(bitmapDataObject
->GetBitmap()); 
 660             return wxSetClipboardData(data
->GetPreferredFormat(), &bitmap
); 
 668             wxLogError("Not implemented because wxMetafileDataObject does not contain width and height values."); 
 671             wxMetafileDataObject
* metaFileDataObject 
= 
 672                 (wxMetafileDataObject
*) data
; 
 673             wxMetafile metaFile 
= metaFileDataObject
->GetMetafile(); 
 674             return wxSetClipboardData(wxDF_METAFILE
, &metaFile
, 
 675                                       metaFileDataObject
->GetWidth(), 
 676                                       metaFileDataObject
->GetHeight()); 
 679 #endif // wxUSE_METAFILE 
 683 // This didn't compile, of course 
 684 //            return wxSetClipboardData(data); 
 686             wxLogError(wxT("Not implemented.")); 
 690 #else // !wxUSE_DATAOBJ 
 692 #endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ 
 695 void wxClipboard::Close() 
 698     // OLE closes clipboard for us 
 699 #if !wxUSE_OLE_CLIPBOARD 
 704 bool wxClipboard::IsSupported( wxDataFormat format 
) 
 706     return wxIsClipboardFormatAvailable(format
); 
 709 bool wxClipboard::GetData( wxDataObject
& data 
) 
 711 #if wxUSE_OLE_CLIPBOARD 
 712     IDataObject 
*pDataObject 
= NULL
; 
 713     HRESULT hr 
= OleGetClipboard(&pDataObject
); 
 714     if ( FAILED(hr
) || !pDataObject 
) 
 716         wxLogSysError(hr
, _("Failed to get data from the clipboard")); 
 721     // build the list of supported formats 
 722     size_t nFormats 
= data
.GetFormatCount(wxDataObject::Set
); 
 724     wxDataFormat 
*formats
; 
 727         // the most common case 
 732         // bad luck, need to alloc mem 
 733         formats 
= new wxDataFormat
[nFormats
]; 
 736     data
.GetAllFormats(formats
, wxDataObject::Set
); 
 738     // get the data for the given formats 
 743     // enumerate all explicit formats on the clipboard. 
 744     // note that this does not include implicit / synthetic (automatically 
 745     // converted) formats. 
 747     // get the format enumerator 
 748     IEnumFORMATETC 
*pEnumFormatEtc 
= NULL
; 
 749     hr 
= pDataObject
->EnumFormatEtc(DATADIR_GET
, &pEnumFormatEtc
); 
 750     if ( FAILED(hr
) || !pEnumFormatEtc 
) 
 753                       _("Failed to retrieve the supported clipboard formats")); 
 757         // ask for the supported formats and see if there are any we support 
 761             hr 
= pEnumFormatEtc
->Next(1, &formatEtc
, &nCount
); 
 763             // don't use FAILED() because S_FALSE would pass it 
 770             cf 
= formatEtc
.cfFormat
; 
 772             wxLogTrace(wxTRACE_OleCalls
, 
 773                        wxT("Object on the clipboard supports format %s."), 
 774                        wxDataObject::GetFormatName(cf
)); 
 777         pEnumFormatEtc
->Release(); 
 782     // stop at the first valid format found on the clipboard 
 783     for ( size_t n 
= 0; !result 
&& (n 
< nFormats
); n
++ ) 
 785         // convert to NativeFormat Id 
 786         cf 
= formats
[n
].GetFormatId(); 
 788         // if the format is not available, try the next one 
 789         // this test includes implicit / sythetic formats 
 790         if ( !::IsClipboardFormatAvailable(cf
) ) 
 793         formatEtc
.cfFormat 
= cf
; 
 794         formatEtc
.ptd      
= NULL
; 
 795         formatEtc
.dwAspect 
= DVASPECT_CONTENT
; 
 796         formatEtc
.lindex   
= -1; 
 798         // use the appropriate tymed 
 799         switch ( formatEtc
.cfFormat 
) 
 802                 formatEtc
.tymed 
= TYMED_GDI
; 
 806             case CF_METAFILEPICT
: 
 807                 formatEtc
.tymed 
= TYMED_MFPICT
; 
 811                 formatEtc
.tymed 
= TYMED_ENHMF
; 
 816                 formatEtc
.tymed 
= TYMED_HGLOBAL
; 
 820         hr 
= pDataObject
->GetData(&formatEtc
, &medium
); 
 823             // try other tymed for GDI objects 
 824             if ( formatEtc
.cfFormat 
== CF_BITMAP 
) 
 826                 formatEtc
.tymed 
= TYMED_HGLOBAL
; 
 827                 hr 
= pDataObject
->GetData(&formatEtc
, &medium
); 
 833             // pass the data to the data object 
 834             hr 
= data
.GetInterface()->SetData(&formatEtc
, &medium
, TRUE
); 
 837                 wxLogDebug(wxT("Failed to set data in wxIDataObject")); 
 839                 // IDataObject only takes the ownership of data if it 
 840                 // successfully got it - which is not the case here 
 841                 ReleaseStgMedium(&medium
); 
 848         //else: unsupported tymed? 
 851     if ( formats 
!= &format 
) 
 855     //else: we didn't allocate any memory 
 857     // clean up and return 
 858     pDataObject
->Release(); 
 862     wxCHECK_MSG( wxIsClipboardOpened(), FALSE
, wxT("clipboard not open") ); 
 864     wxDataFormat format 
= data
.GetPreferredFormat(); 
 870             wxTextDataObject
& textDataObject 
= (wxTextDataObject 
&)data
; 
 871             char* s 
= (char*)wxGetClipboardData(format
); 
 875             textDataObject
.SetText(wxString::FromAscii(s
)); 
 884             wxBitmapDataObject
& bitmapDataObject 
= (wxBitmapDataObject 
&)data
; 
 885             wxBitmap
* bitmap 
= (wxBitmap 
*)wxGetClipboardData(data
.GetPreferredFormat()); 
 889             bitmapDataObject
.SetBitmap(*bitmap
); 
 897             wxMetafileDataObject
& metaFileDataObject 
= (wxMetafileDataObject 
&)data
; 
 898             wxMetafile
* metaFile 
= (wxMetafile 
*)wxGetClipboardData(wxDF_METAFILE
); 
 902             metaFileDataObject
.SetMetafile(*metaFile
); 
 907 #endif // wxUSE_METAFILE 
 910 #else // !wxUSE_DATAOBJ 
 911     wxFAIL_MSG( wxT("no clipboard implementation") ); 
 913 #endif // wxUSE_OLE_CLIPBOARD/wxUSE_DATAOBJ 
 916 #endif // wxUSE_CLIPBOARD