TVirtualStringGrid CopyToClipboard发布Embarcadero Seattle C ++

时间:2015-10-26 09:08:14

标签: c++ c++builder virtualtreeview tvirtualstringtree

在调用VirtualStringGrid -> CopyToClipBoard之前,我可以将网格粘贴到记事本中的标签文本或粘贴到Excel或Outlook时作为完全格式化的网格(标题和颜色和边框)。

但是,自从使用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 个答案:

答案 0 :(得分:1)

每次致电GlobalFree()后,您都在致电SetClipboardData()。除非SetClipboardData()失败,否则你不能这样做。关于此事的文件非常明确:

SetClipboardData function

  

如果SetClipboardData成功,则系统拥有hMem参数标识的对象。 一旦所有权转移到系统后,应用程序可能无法写入或释放数据,但它可以锁定和读取数据,直到调用CloseClipboard函数。 (在剪贴板关闭之前必须解锁内存。)如果hMem参数标识了一个内存对象,则必须使用带有GMEM_MOVEABLE标志的函数分配该对象。

此外,您使用相同的CF_TEXT格式将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()方法的源代码,它使用的实现与上面的代码完全不同。它将树数据检索到IDataObject COM对象(TVTDataObject)中,该对象表示VirtualTreeView ClipboardFormats属性中列出的剪贴板格式,以及VirtualTreeView提供的任何其他格式&#39 ; s OnGetUserClipboardFormats事件。这包括文本,HTML,RTF和CSV。然后调用OleSetClipboard()将该COM对象放在剪贴板上。如果任何应用程序使用GetClipboardData()而不是OleGetClipboard(),Windows会根据需要自动提取数据。所以也许在v6.2中已经打破了TVTDataObject的实现。您应该联系JAM Software(VirtualTreeView的当前维护者)并提交相关的错误报告。