TClipboard
empties the clipboard the first time you use a TClipboard
method to put data on the clipboard (TClipboard.Assign()
, TClipboard.SetBuffer()
, TClipboard.SetAsHandle()
, etc) after calling Open()
. TClipboard
expects you to use only its methods for accessing the clipboard, so your use of SetClpboardData()
directly to store your string data is bypassing TClipboard
's internal logic, thus your call to Assign()
is seen as the first clipboard write and TClipboard
wipes out any data you stored with SetClipboardData()
.
To avoid that, you have a few choices:
Assign()
your image to the clipboard first, then save your string items withSetClipboardData()
afterwards.don't use
Assign()
at all. UseTPicture.SaveToClipboardFormat()
directly and then callSetClipboardData()
.don't use
SetClipboardData()
directly unlessUSEVCLCLIPBOARD
is not defined. UseTClipboard.SetAsHandle()
instead.
I would suggest #3. Let TClipboard
do all of the work:
var
CF_HTML: UINT = 0;
// TClipboard.SetBuffer() allows a format and an arbitrary buffer
// to be specified and handles the global memory allocation.
// However, it is protected, so using an accessor class to reach it.
//
// TClipboard.AsText and TClipboard.SetTextBuf() always use
// CF_(UNICODE)TEXT, and TClipboard.SetAsHandle() requires manual
// allocation...
//
type
TClipboardAccess = class(TClipboard)
end;
procedure CopyHTMLAndImageToClipBoard(const str, APngFile: AnsiString; const htmlStr: AnsiString = '');
var
TmpHtmlStr: AnsiString;
ThisImage: TPicture;
begin
Clipboard.Open;
try
//most descriptive first as per api docs
TmpHtmlStr := FormatHTMLClipboardHeader(htmlStr);
TClipboardAccess(Clipboard).SetBuffer(CF_HTML, PAnsiChar(TmpHtmlStr)^, Length(TmpHtmlStr) + 1);
TClipboardAccess(Clipboard).SetBuffer(CF_TEXT, PAnsiChar(Str)^, Length(Str) + 1);
ThisImage := TPicture.Create;
try
ThisImage.LoadFromFile(APngFile);
Clipboard.Assign(ThisImage);
finally
ThisImage.Free;
end;
finally
Clipboard.Close;
end;
end;
initialization
CF_HTML := RegisterClipboardFormat('HTML Format');
If you really need to support {$IFNDEF USEVCLCLIPBOARD}
then you cannot use TClipboard
at all, eg:
var
CF_HTML: UINT = 0;
{$IFDEF USEVCLCLIPBOARD}
// TClipboard.SetBuffer() allows a format and an arbitrary buffer
// to be specified and handles the global memory allocation.
// However, it is protected, so using an accessor class to reach it.
//
// TClipboard.AsText and TClipboard.SetTextBuf() always use
// CF_(UNICODE)TEXT, and TClipboard.SetAsHandle() requires manual
// allocation...
//
type
TClipboardAccess = class(TClipboard)
end;
{$ENDIF}
procedure CopyHTMLAndImageToClipBoard(const str, APngFile: AnsiString; const htmlStr: AnsiString = '');
var
ThisImage: TPicture;
{$IFNDEF USEVCLCLIPBOARD}
ImgData: THandle;
ImgFormat: Word;
ImgPalette: HPALETTE;
{$ENDIF}
procedure SetAsText(Format: UINT; const S: AnsiString);
{$IFNDEF USEVCLCLIPBOARD}
var
gMem: HGLOBAL;
lp: PAnsiChar;
{$ENDIF}
begin
{$IFDEF USEVCLCLIPBOARD}
TClipboardAccess(Clipboard).SetBuffer(Format, PAnsiChar(S)^, Length(S) + 1);
{$ELSE}
//an extra "1" for the null terminator
gMem := GlobalAlloc(GMEM_DDESHARE + GMEM_MOVEABLE, Length(S) + 1);
Win32Check(gmem <> 0);
try
{Succeeded, now read the stream contents into the memory the pointer points at}
lp := GlobalLock(gMem);
Win32Check(lp <> nil);
try
CopyMemory(lp, PAnsiChar(S), Length(S) + 1);
finally
GlobalUnlock(gMem);
end;
except
GlobalFree(gMem);
raise;
end;
SetClipboardData(Format, gMem);
{$ENDIF}
end;
begin
{$IFDEF USEVCLCLIPBOARD}
Clipboard.Open;
{$ELSE}
Win32Check(OpenClipBoard(0));
{$ENDIF}
try
//most descriptive first as per api docs
SetAsText(CF_HTML, FormatHTMLClipboardHeader(htmlStr));
SetAsText(CF_TEXT, Str);
ThisImage := TPicture.Create;
try
ThisImage.LoadFromFile(APngFile);
{$IFDEF USEVCLCLIPBOARD}
Clipboard.Assign(ThisImage);
{$ELSE}
ImgPalette := 0;
ThisImage.SaveToClipboardFormat(ImgFormat, ImgData, ImgPalette);
SetClipboardData(ImgFormat, ImgData);
if ImgPalette <> 0 then
SetClipboardData(CF_PALETTE, ImgPalette);
{$ENDIF}
finally
ThisImage.Free;
end;
finally
{$IFDEF USEVCLCLIPBOARD}
Clipboard.Close;
{$ELSE}
Win32Check(CloseClipBoard);
{$ENDIF}
end;
end;
initialization
CF_HTML := RegisterClipboardFormat('HTML Format');