通过调用平台服务得到的接口IFMXExtendedClipboardService使用FireMonkey跨平台复制数据到剪贴板:
var
Svc : IFMXExtendedClipboardService;
begin
if not TPlatformServices.Current.SupportsPlatformService(IFMXExtendedClipboardService, Svc) then
Exit; // Not clipboard supported
// Code using the interface
此接口具有从剪贴板复制/获取文本/图像的方法:SetText、GetText、SetImage、GetImage。
对于其他类型的数据,用户必须注册数据格式,然后向剪贴板写入/读取数据:RegisterCustomFormat,IsCustomFormatRegistered,UnregisterCustomFormat,HasCustomFormat,GetCustomFormat,SetCustomFormat .
在您的问题中,您说您想将 HTML 格式的数据复制到剪贴板。这可以翻译为注册 HTML 格式,使用您的数据创建一个流并调用 SetCustomFormat 传递格式和流。
任何格式都可以通过上述接口方法使用和传输到剪贴板/从剪贴板传输。下面的代码获取流stream 并使用ClipFormat 将其内容复制到剪贴板:
if TPlatformServices.Current.SupportsPlatformService(
IFMXExtendedClipboardService, Svc) then begin
if not Svc.IsCustomFormatRegistered(ClipFormat) then
Svc.RegisterCustomFormat(ClipFormat);
Svc.SetCustomFormat(ClipFormat, Stream);
end;
一种格式只能注册一次,因此调用IsCustomFormatRegistered 以防止多次调用RegisterCustomFormat。
格式的名称是一个简单的字符串,可以是任何东西。复制和粘贴应用程序必须就格式名称和数据格式(数据写入流的方式)达成一致。
由于样式的原因,编写 HTML 格式的数据可能很困难。由于样式的原因,仅获取完整 HTML 文档的简单副本可能无法正确呈现它。
如果您通过剪贴板在两个应用程序之间传输数据,您可以做任何您想做的事情。但是在您的应用程序和另一个应用程序(您在问题中提到 Microsoft Word)之间传输数据要困难得多。
在 Microsoft 产品和 Windows 平台上的所有其他产品中,剪贴板中的 HTML 格式描述为here。
您在问题中给出的示例格式正确后如下所示:
Version:0.9
StartHTML:00000144
EndHTML:00000218
StartFragment:00000167
EndFragment:00000205
StartSelection:00000167
EndSelection:00000205
<!DOCTYPE><HTML><BODY><P>This is a <b>bold</b> html line</P></BODY></HTML>
实际字符串如上,每行末尾有一个CRLF。格式名称为“HTML 格式”。
你看到句子This is a <b>bold</b> html line必须被HTML标签包围以形成一个有效的完整的HTML文档,并且前面有一个由许多keyword:value对组成的标题。如果是字符串,则这些值是偏移的。关键字是不言自明的。该字符串是 UTF8,如果您使用 HTML 实体来表示特殊字符,则可以将其简化为 ANSI。
我写了一个函数来构建整个字符串:
function FormatHtmlForClipboard(const HtmlSrc : UTF8String) : UTF8String;
const
Header = 'Version:0.9' + #13#10 +
'StartHTML:00000000' + #13#10 +
'EndHTML:00000000' + #13#10 +
'StartFragment:00000000' + #13#10 +
'EndFragment:00000000' + #13#10 +
'StartSelection:00000000' + #13#10 +
'EndSelection:00000000' + #13#10;
var
BodyStart : Integer;
BodyEnd : Integer;
HdrLen : Integer;
begin
Result := Header;
BodyStart := Pos('<BODY>', String(HtmlSrc));
if BodyStart <= 0 then
raise Exception.Create('<BODY> tag not found');
Inc(BodyStart, 6);
BodyEnd := Pos('</BODY>', String(HtmlSrc));
if BodyEnd <= 0 then
raise Exception.Create('</BODY> tag not found');
HdrLen := Length(Header) - 1;
WriteNumberIntoString(HdrLen, 'StartHTML:', Result);
WriteNumberIntoString(HdrLen + Length(HtmlSrc), 'EndHTML:', Result);
WriteNumberIntoString(HdrLen + BodyStart, 'StartFragment:', Result);
WriteNumberIntoString(HdrLen + BodyEnd, 'EndFragment:', Result);
WriteNumberIntoString(HdrLen + BodyStart, 'StartSelection:', Result);
WriteNumberIntoString(HdrLen + BodyEnd, 'EndSelection:', Result);
Result := Result + HtmlSrc;
end;
procedure WriteNumberIntoString(
N : Integer;
const At : UTF8String;
var S : UTF8String);
var
I : Integer;
V : UTF8String;
begin
I := Pos(At, S);
if I <= 0 then
Exit;
I := I + Length(At);
V := UTF8String(Format('%08.8d', [N]));
Move(V[1], S[I], Length(V));
end;
综上所述,将 HTML 格式的数据复制到剪贴板的函数如下所示:
procedure CopyHtmlToClipboard(const HtmlSrc : UTF8String);
var
Svc : IFMXExtendedClipboardService;
Stream : TStringStream;
HtmlData : UTF8String;
const
ClipFormat = 'HTML format'; // This is what Windows expect
// Maybe other platform want something else
begin
HtmlData := FormatHtmlForClipboard(HtmlSrc);
Stream := TStringStream.Create(HtmlData);
if TPlatformServices.Current.SupportsPlatformService(
IFMXExtendedClipboardService, Svc) then begin
if not Svc.IsCustomFormatRegistered(ClipFormat) then
Svc.RegisterCustomFormat(ClipFormat);
Svc.SetCustomFormat(ClipFormat, Stream);
end;
end;
你应该像这样使用函数:
procedure TForm1.Button1Click(Sender: TObject);
begin
CopyHtmlToClipboard(
'<!DOCTYPE><HTML><BODY><P>' +
'This is a <b>bold</b> html line' + //<== Your actual HTML text
'</P></BODY></HTML>');
end;