UltraEdit剪贴板内容有时无法直接粘贴的原因

很久之前就发现有这么个问题,用UltraEdit编辑器(以下简称UE)复制或剪切文本后,有时无法直接粘贴到我用Delphi7写的程序里,但如果先粘贴到记事本再从记事本复制粘贴是可以的,特别是在通过远程桌面粘贴时这个问题更是严重,出现几率很高。时间长了,终于发现一个规律,就是编辑UTF8或UNICODE编码的有中文的文件时特别容易出现,普通ANSI编码或纯英文的内容粘贴倒是OK的。但具体为何会这样却不太清楚,总不能说我们的程序连记事本粘贴这种基本要求都达不到吧,今天有空便决定分析一下其中的原因。

首先打开Delphi建立一个测试工程,放了个按钮,在点击时将剪贴板的文本取出来显示: 

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Clipboard.HasFormat(CF_TEXT) then
    ShowMessage(Clipboard.AsText);
end;


然后用UE打开一个UTF8编码含中文的HTML文件,复制一段内容如下:

<tr>
  <td>标题</td>
  <td><input class="input" type="text" name="P_标题" id="P_标题" value=""/></td>
</tr>


然后点击程序的测试按钮,结果显示的是一个空的消息框:

UltraEdit剪贴板内容有时无法直接粘贴的原因_第1张图片

也就是说,程序能检测到剪贴板里有文本,但取文本格式的数据却取不到,导致粘贴失败。问题可能出在UE往剪贴板里放的数据格式不对。本身来说,UTF8的格式并不会完全无法取读,顶多是中文变乱码,但英文应该能读出来的,因此剪贴板里肯定不是UTF8格式数据。考虑到UE经常把UTF8格式的文件当UNICODE处理,于是我尝试以UNICODE方式提取数据:

procedure TForm1.Button1Click(Sender: TObject);
var
  Data: THandle;
begin
  if Clipboard.HasFormat(CF_TEXT) then
  begin
    Clipboard.Open;
    Data := GetClipboardData(CF_TEXT);
    try
      ShowMessage(PWideChar(GlobalLock(Data)));
    finally
      GlobalUnlock(Data);
      Clipboard.Close;
    end;
  end;
end;

但结果出来的是一堆乱码,说明里面存放的也不是UNICODE。
问题似乎找不着原因了,但我很快跟踪发现,剪贴板是CF_TEXT数据只是第一个字节是0,中间的数据是对的,中文也转成GBK编码了,高兴了一会,以为把指针移一下就能解决了,但很快又发现最后的数据缺了几个字节。究其原因,可能是因为有中文,导致编码转换时长度被截短了。

于是决定要分析下剪贴板内容。以前写过一个剪贴板内容分析的程序,但年代久远,找了很久没找着,反正原理也不复杂,于是又重新写了一个。运行起来一分析,终于发现原因,原来这种情况下UE放到剪贴板里的数据有好几种,不知为何其中放CF_TEXT格式的内容是错误的,它第一个字节被替换成0了,结尾处又丢了几个字节的数据:

UltraEdit剪贴板内容有时无法直接粘贴的原因_第2张图片

但它放的CF_UNICODETEXT格式是正确的,一个字都不少,也没有增加0:

UltraEdit剪贴板内容有时无法直接粘贴的原因_第3张图片

因此我只要修改下代码,判断无法取到CF_TEXT,而同时又有CF_UNICODETEXT的情况下,直接去取CF_UNICODETEXT:

procedure TForm1.Button1Click(Sender: TObject);
var
  Data: THandle;
  p: Pointer;
  ws: WideString;
begin
  if Clipboard.AsText <> '' then
    MemoTxt.SelText := Clipboard.AsText
  else if Clipboard.HasFormat(CF_UNICODETEXT) then
  begin
    Clipboard.Open;
    Data := GetClipboardData(CF_UNICODETEXT);
    try
      if Data <> 0 then
      begin
        p := GlobalLock(Data);
        ws := PWideChar(p);
        MemoTxt.SelText := ws;
      end;
    finally
      if Data <> 0 then GlobalUnlock(Data);
      Clipboard.Close;
    end;
  end;
end;


至此问题基本解决,记事本能粘贴则我的程序也能。

小结:由于Delphi7的VCL本身不支持Unicode,因此在粘贴UE的UTF8或UNICODE格式数据时会出现问题;虽然不清楚UE为何会放错的数据到剪贴板,但直接取UNICODE内容能解决问题,达到我们想要的结果。

 

你可能感兴趣的:(html,测试,Class,input,Delphi)