如何在delphi 2009中将RTF字符串复制到剪贴板?

发布于 2024-07-21 19:21:36 字数 1448 浏览 5 评论 0原文

这是我在 2009 年之前在 Delphi 中运行的代码? 它只是最终在 SetAsHandle 上引发堆错误。 如果我将其更改为按照原始方式使用 AnsiString,即

procedure RTFtoClipboard(txt: string; rtf: AnsiString);

不会

Data := GlobalAlloc(GHND or GMEM_SHARE, Length(rtf)*SizeOf(AnsiChar) + 1);

出现错误,但剪贴板是空的。

完整代码:

unit uClipbrd;

interface

procedure RTFtoClipboard(txt: string; rtf: string);

implementation

uses
  Clipbrd, Windows, SysUtils, uStdDialogs;
VAR
  CF_RTF : Word = 0;

//------------------------------------------------------------------------------
procedure RTFtoClipboard(txt: string; rtf: string);
var
  Data: Cardinal;
begin
  with Clipboard do
  begin
    Data := GlobalAlloc(GHND or GMEM_SHARE, Length(rtf)*SizeOf(Char) + 1);
    if Data <> 0 then
      try
        StrPCopy(GlobalLock(Data), rtf);
        GlobalUnlock(Data);
        Open;
        try
          AsText := txt;
          SetAsHandle(CF_RTF, Data);
        finally
          Close;
        end;
      except
        GlobalFree(Data);
        ErrorDlg('Unable to copy the selected RTF text');
      end
    else
      ErrorDlg('Global Alloc failed during Copy to Clipboard!');
  end;
end;

initialization
  CF_RTF := RegisterClipboardFormat('Rich Text Format');
  if CF_RTF = 0 then
    raise Exception.Create('Unable to register the Rich Text clipboard format!');
end.

Here is my code that was working in Delphi pre 2009? It just either ends up throwing up a heap error on SetAsHandle.
If I change it to use AnsiString as per original, i.e.

procedure RTFtoClipboard(txt: string; rtf: AnsiString);

and

Data := GlobalAlloc(GHND or GMEM_SHARE, Length(rtf)*SizeOf(AnsiChar) + 1);

then there is no error but the clipboard is empty.

Full code:

unit uClipbrd;

interface

procedure RTFtoClipboard(txt: string; rtf: string);

implementation

uses
  Clipbrd, Windows, SysUtils, uStdDialogs;
VAR
  CF_RTF : Word = 0;

//------------------------------------------------------------------------------
procedure RTFtoClipboard(txt: string; rtf: string);
var
  Data: Cardinal;
begin
  with Clipboard do
  begin
    Data := GlobalAlloc(GHND or GMEM_SHARE, Length(rtf)*SizeOf(Char) + 1);
    if Data <> 0 then
      try
        StrPCopy(GlobalLock(Data), rtf);
        GlobalUnlock(Data);
        Open;
        try
          AsText := txt;
          SetAsHandle(CF_RTF, Data);
        finally
          Close;
        end;
      except
        GlobalFree(Data);
        ErrorDlg('Unable to copy the selected RTF text');
      end
    else
      ErrorDlg('Global Alloc failed during Copy to Clipboard!');
  end;
end;

initialization
  CF_RTF := RegisterClipboardFormat('Rich Text Format');
  if CF_RTF = 0 then
    raise Exception.Create('Unable to register the Rich Text clipboard format!');
end.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

贪了杯 2024-07-28 19:21:36

引用维基百科

RTF 是一种 8 位格式。 这会将其限制为 ASCII,但 RTF 可以通过转义序列对 ASCII 之外的字符进行编码。 字符转义有两种类型:代码页转义和Unicode 转义。 在代码页转义中,撇号后面的两个十六进制数字用于表示从 Windows 代码页获取的字符。 例如,如果存在指定 Windows-1256 的控制代码,则序列 \'c8 将编码阿拉伯字母 beh (â)。

如果需要 Unicode 转义,则使用控制字 \u,后跟给出 Unicode 代码点编号的 16 位有符号十进制整数。 为了使不支持 Unicode 的程序受益,后面必须跟上指定代码页中该字符的最接近的表示形式。 例如,\u1576? 将给出阿拉伯字母 beh,指定不支持 Unicode 的旧程序应将其呈现为问号。

因此,使用 AnsiString 的想法很好,但您还需要用 Unicode 转义符替换所有非 ASCII 且不属于当前 Ansi Windows 代码页的字符。 理想情况下,这应该是另一个函数。 将数据写入剪贴板的代码可以保持不变,唯一的更改是使用 Ansi 字符串类型。

To quote Wikipedia:

RTF is an 8-bit format. That would limit it to ASCII, but RTF can encode characters beyond ASCII by escape sequences. The character escapes are of two types: code page escapes and Unicode escapes. In a code page escape, two hexadecimal digits following an apostrophe are used for denoting a character taken from a Windows code page. For example, if control codes specifying Windows-1256 are present, the sequence \'c8 will encode the Arabic letter beh (ب).

If a Unicode escape is required, the control word \u is used, followed by a 16-bit signed decimal integer giving the Unicode codepoint number. For the benefit of programs without Unicode support, this must be followed by the nearest representation of this character in the specified code page. For example, \u1576? would give the Arabic letter beh, specifying that older programs which do not have Unicode support should render it as a question mark instead.

So your idea of using AnsiString is good, but you would also need to replace all characters that are not ASCII and are not part of the current Ansi Windows codepage with the Unicode escapes. This should ideally be another function. Your code to write the data to the clipboard could remain the same, with the only change to use the Ansi string type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文