2015-10-26 33 views
1

在調用VirtualStringGrid -> CopyToClipBoard之前,我可以將網格作爲選項卡式文本粘貼到記事本中,或者在粘貼到Excel或Outlook時作爲完全格式化的網格(標題和顏色以及邊框)粘貼。TVirtualStringGrid CopyToClipboard問題Embarcadero Seattle C++

但是,我從使用VirtualTreeView V6.2從Embarcadero XE8移動到RAD Seattle時遇到了CopyToClipboard問題:如果目標應用程序是某種文本編輯器,我只能粘貼爲文本。粘貼到任何接受RTF或HTML的「富」應用程序都會導致錯誤。

我試着調用ContentToXXX方法(請參閱下面的代碼)文本導出正常。 Html已導出,但生成的Data2Export字符串包含HTML頁面上的整個代碼,並且無法粘貼到Outlook中。 對ContentToRTF的任何調用都會導致崩潰。

我搜索了這種問題,但我沒有發現任何相關的東西。

void __fastcall TForm::ExportGrid(void) 
{ 
// old code that used to work fine 
// VST->CopyToClipboard(); 

    Virtualtrees::TVSTTextSourceType exportSrcType = tstAll; 

    OpenClipboard(Handle); 
    EmptyClipboard(); 

    std::string Data2Export = ""; 
    HGLOBAL hg; 

    // tabbed text 
    Data2Export = AnsiString(VST->ContentToText(exportSrcType, "\t")).c_str(); 
    hg = GlobalAlloc(GMEM_MOVEABLE, Data2Export.size() + 1); 

    if (!hg) 
    { 
    CloseClipboard(); 
    return; 
    } 

    memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.size() + 1); 
    GlobalUnlock(hg); 
    SetClipboardData(CF_TEXT, hg); 
    GlobalFree(hg); 

    // html 
    Data2Export = AnsiString(VST->ContentToHTML(exportSrcType)).c_str(); 
    hg = GlobalAlloc(GMEM_MOVEABLE, Data2Export.size() + 1); 

    if (!hg) 
    { 
    CloseClipboard(); 
    return; 
    } 

    memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.size() + 1); 
    GlobalUnlock(hg); 
    SetClipboardData(CF_HTML, hg); 
    GlobalFree(hg); 

    // RTF 
    Data2Export = AnsiString(VST->ContentToRTF(exportSrcType).c_str()).c_str(); 
    hg  = GlobalAlloc(GMEM_MOVEABLE, Data2Export.size() + 1); 

    if (!hg) 
    { 
    CloseClipboard(); 
    return; 
    } 

    memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.size() + 1); 
    GlobalUnlock(hg); 
    SetClipboardData(CF_TEXT, hg); 
    GlobalFree(hg); 

    CloseClipboard(); 
} 

有關如何解決或解決此問題的任何想法?

代碼有問題嗎?

PD:開發平臺是Win8和Win10,VirtualStringTree ClipboardFormats都設置爲true。

回答

1

您在每次致電SetClipboardData()後致電GlobalFree()。除非SetClipboardData()失敗,否則你不能這樣做。該文件是對那件事很清楚:

SetClipboardData function

如果SetClipboardData成功,該系統擁有由HMEM參數標識的對象。 所有權已轉移到系統後,應用程序可能無法寫入或釋放數據,但可以鎖定和讀取數據,直到調用CloseClipboard函數。 (在剪貼板關閉之前,內存必須解鎖。)如果hMem參數標識內存對象,則該對象必須已使用具有GMEM_MOVEABLE標誌的函數進行分配。

此外,您使用相同的CF_TEXT格式將文本和RTF數據塊保存到剪貼板。您的RTF數據應該使用CF_RTF格式。

試試這個:

#include <richedit.h> 

void __fastcall TForm::ExportGrid(void) 
{ 
    // old code that used to work fine 
    // VST->CopyToClipboard(); 

    Virtualtrees::TVSTTextSourceType exportSrcType = tstAll; 

    if (!OpenClipboard(Handle)) return; 
    try 
    { 
     EmptyClipboard(); 

     AnsiString Data2Export; 
     HGLOBAL hg; 

     // tabbed text 
     Data2Export = VST->ContentToText(exportSrcType, "\t"); 
     hg = GlobalAlloc(GMEM_MOVEABLE, Data2Export.size() + 1); 
     if (hg) 
     { 
      memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.Length() + 1); 
      GlobalUnlock(hg); 
      if (!SetClipboardData(CF_TEXT, hg)) // or maybe CF_CSV instead... 
       GlobalFree(hg); 
     } 

     // html 
     Data2Export = VST->ContentToHTML(exportSrcType); 
     hg = GlobalAlloc(GMEM_MOVEABLE, Data2Export.Length() + 1); 
     if (hg) 
     { 
      memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.Length() + 1); 
      GlobalUnlock(hg); 

      if (!SetClipboardData(CF_HTML, hg)) 
       GlobalFree(hg); 
     } 

     // RTF 
     Data2Export = VST->ContentToRTF(exportSrcType); 
     hg = GlobalAlloc(GMEM_MOVEABLE, Data2Export.Length() + 1); 
     if (hg) 
     { 
      memcpy(GlobalLock(hg), Data2Export.c_str(), Data2Export.Length() + 1); 
      GlobalUnlock(hg); 

      if (!SetClipboardData(CF_VRTF, hg)) 
       GlobalFree(hg); 

     } 
    } 
    __finally 
    { 
     CloseClipboard(); 
    } 
} 

如果你看一下源代碼VirtualTreeView的CopyToClipboard()方法,它採用了非常不同的實現比上面的代碼。它將樹數據檢索到代表VirtualTreeView的ClipboardFormats屬性中列出的剪貼板格式的IDataObject COM對象(TVTDataObject)以及VirtualTreeView的OnGetUserClipboardFormats事件提供的任何其他格式。這包括文本,HTML,RTF和CSV。然後它調用OleSetClipboard()將該COM對象放在剪貼板上。如果任何應用程序使用GetClipboardData()而不是OleGetClipboard(),則Windows會根據需要自動提取數據。所以也許在v6.2中已經打破了TVTDataObject的實現。您應該聯繫JAM Software(VirtualTreeView的當前維護人員)並提交一份關於該問題的錯誤報告。

+0

嗨,雷米,我錯過了SetClipboardData技巧。然而,僅僅調用'VST-> ContentToRTF(TVSTTextSourceType :: tstAll)'會導致訪問衝突。我會將CopyToClipboard問題報告給Jam Software。謝謝你的幫助! –

+0

僅供參考這裏是在版本6.2.1中公佈的錯誤報告和修復:[link](https://github.com/Virtual-TreeView/Virtual-TreeView/issues/588) –