c++ - TVirtualStringGrid CopyToClipboard 问题 Embarcadero Seattle C++

标签 c++ c++builder virtualtreeview tvirtualstringtree

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

但是,我在使用 CopyToClipboard 时遇到了问题自从我使用 VirtualTreeView V6.2 从 Embarcadero XE8 转移到 RAD Seattle 后:如果目标应用程序是某种文本编辑器,我只能粘贴为文本。粘贴到任何类型的接受 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。

最佳答案

您在每次调用 SetClipboardData() 之后调用 GlobalFree()。除非 SetClipboardData() 失败,否则您不得这样做。关于这个问题,文档非常清楚:

SetClipboardData function

If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.

此外,您还使用相同的 CF_TEXT 格式将文本和 RTF 数据 block 保存到剪贴板。您的 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 的 OnGetUserClipboardFormats 事件。这包括文本、HTML、RTF 和 CSV。然后调用 OleSetClipboard()将该 COM 对象放在剪贴板上。如果任何应用程序使用 GetClipboardData() 而不是 OleGetClipboard() , Windows 会根据需要自动提取数据。所以可能 TVTDataObject 的实现在 v6.2 中被破坏了。你应该联系JAM Software (VirtualTreeView 的当前维护者)并就此提交错误报告。

关于c++ - TVirtualStringGrid CopyToClipboard 问题 Embarcadero Seattle C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33341986/

相关文章:

c++ - 为什么这个计算在 boost::thread 和 std::thread 中给出不同的结果?

delphi - 虚拟字符串树 4.8.7 HeaderDblClick 事件没有功能?

delphi - VirtualTreeView 的 Firemonkey 版本

c++ - 可选功能参数 : Use default arguments (NULL) or overload the function?

delphi - 在DLL中打开的表单显示在任务管理器中,如何隐藏?

c++ - 如何使用 boost thread win32-mt-s 构建 boost(与 mingw 交叉编译)

c++ - 在 C++ Builder 和 VC++ 中使用 std::string 的区别

delphi - 如何同步滚动 2 个不同高度的 TVirtualStringTree 控件?

c++ - 当我尝试在 C++ 中反转字符串时,我得到了一堆额外的字符

c++ - CUDA9.2 及更高版本中模板默认参数 Unresolved external 函数错误