C ++ Builder — проблема с CopyToClipboard в TVirtualStringGrid Переполнение стека в Сиэтле Embarcadero

Ранее после звонка VirtualStringGrid -> CopyToClipBoardЯ мог вставить сетку как текст с вкладками в блокноте или как полностью отформатированную сетку (заголовки, цвет и границы) при вставке в Excel или Outlook.

Однако у меня возникли проблемы с CopyToClipboard с тех пор как я перешел с Embarcadero XE8 на RAD Seattle с VirtualTreeView V6.2: я могу вставить текст, только если целевое приложение представляет собой текстовый редактор. Вставка в любое «богатое» приложение, принимающее 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: платформа dev — это Win8 и Win10, а для форматов буфера обмена VirtualStringTree задано значение true.

1

Решение

Ты звонишь GlobalFree() после каждого звонка SetClipboardData(), ВЫ НЕ ДОЛЖНЫ ДЕЛАТЬ, ЧТО SetClipboardData() выходит из строя. Документация очень ясна по этому вопросу:

Функция SetClipboardData

Если SetClipboardData завершается успешно, система владеет объектом, идентифицированным параметром hMem. Приложение не может записывать или освобождать данные после передачи права собственности в систему., но он может блокировать и читать данные, пока не будет вызвана функция CloseClipboard. (Память должна быть разблокирована до закрытия буфера обмена.) Если параметр hMem идентифицирует объект памяти, объект должен быть выделен с использованием функции с флагом GMEM_MOVEABLE.

Кроме того, вы сохраняете блоки данных Text и RTF в буфер обмена, используя те же CF_TEXT формат. Ваши данные 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) и подать отчет об ошибке об этом.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]