如何修复Delphi XE3迁移错误?

4
我正在将我的 Delphi 5 应用程序迁移到 Delphi XE3,编译时出现了一些错误。请问有谁能帮我解决这些问题?提前感谢您的帮助。
1. 我在 XE3 中找不到函数 OemToChar 的定义。当我 Ctrl+Click 该函数时,会显示消息 Unable to locate 'WinAPI.Windows.pas'。我无法打开任何 Delphi 组件文件。系统上的 windows.pas 文件位于哪里?或者如何解决此问题?
2. 以下函数中,第 p1, p2 行出现 Incompatible Types: 'PAnsiChar' and 'PWideChar' 错误: OemToChar(p1, p2)
function OemToAnsi(const Str: string): string;
var
  p1,
  p2: PChar;
begin
  p1 := PChar(Str);
  p2 := StrNew(p1);
  OemToChar(p1, p2);
  Result := StrPas(p2);
  StrDispose(p2);
end;
  1. 在以下代码中出现错误'Low Bound Exceeds High Bound'

function StrToRichText(const Str: string): string;
var
  i: integer;
begin
  Result := '';
  for i := 1 to Length(Str) do
  begin
    case Str[i] of
      #128 .. #255 :
        Result := Result + '\''' + LowerCase(IntToHex(Ord(Str[i]), 2));
      '\','{','}':
        Result := Result + '\' + Str[i];
    else
      Result := Result + Str[i];
    end;
  end;
end;
3个回答

7
您的 OemToAnsi 函数应该像这样:
function OemToAnsi(const Str: AnsiString): AnsiString;
begin
  SetLength(Result, Length(Str));
  OemToCharA(PAnsiChar(Str), PAnsiChar(Result));
end;

也许你需要更好的解决方案

function OemToWide(const Str: AnsiString): string;
begin
  SetLength(Result, Length(Str));
  OemToChar(PAnsiChar(Str), PChar(Result));
end;

关于你的 StrToRichText,看起来比较困难。它明显只接受 ANSI 编码的输入。如果你想继续使用 ANSI 编码,只需更改声明为:
function StrToRichText(const Str: AnsiString): AnsiString;

RTF使用7位ASCII编码。如果要让该函数与Unicode输入一起工作,则需要转义任何序数>= 128的字符。例如,有关转义的说明可以在维基百科Rich Text Format页面中找到。我会把这留给您自己做!


在您进一步深入之前,您需要阅读Marco Cantù的白皮书:Delphi和Unicode


谢谢David。所有的错误都已经解决了。我一定会仔细阅读那篇论文的。 - Nalu

4
  1. 'OemToChar()' is declared in 'Winapi.Windows.pas', just like the IDE says. Make sure your uses clause includes Winapi.Windows, or that Winapi is inluded in your Project's "Unit Scope Names" field in the Project Options if the uses clause includes 'Windows' instead (which it likely does since you are migrating).

  2. In D2009+, OemToChar() maps to OemToCharW() now, not to OemToCharA() anymore. The first parameter of both functions is a PAnsiChar. In D2009+, PChar maps to PWideChar now, not to PAnsiChar anymore, so you need to re-write your code accordingly, eg:

    function OemToAnsi(const Str: AnsiString): string;
    var
      S: String;
    begin
      SetLength(S, Length(Str));
      OemToChar(PAnsiChar(Str), PChar(S));
      Result := PChar(S);
    end;
    

    However, you should re-think why you still need to deal with OEM strings in the first place. They don't make as much sense in a Unicode world, and they are rarely even used in an Ansi world.

  3. Another case where you need to re-write the code to account for Char=WideChar now, since character ranges are much larger than Ansi character ranges. You I would use ordinals instead (you should also take UTF-16 surrogates into account properly, but I will leave that as an exercise for you), eg:

    function StrToRichText(const Str: string): string;
    var
      i: integer;
    begin
      Result := '';
      for i := 1 to Length(Str) do
      begin            
        case Ord(Str[i]) of
          128..255:
            Result := Result + '\''' + LowerCase(IntToHex(Ord(Str[i]), 2));
          Ord('\'), Ord('{'), Ord('}'):
            Result := Result + '\' + Str[i];
        else
          Result := Result + Str[i];
        end;
      end;
    end;
    

结果 := PChar(S) 是否需要?输出是否可以比输入短? - David Heffernan
Winapi已经包含在项目选项的“单元作用域名称”字段中,但我仍然无法打开任何文件。:( 是否需要特定的环境设置? - Nalu
1
看起来IDE的库路径没有正确配置。 - Remy Lebeau
有人能帮我设置这些路径吗?我应该提到哪个路径? - Nalu
我知道这已经过时了,但最近我把一个项目从D2009转换到XE3,尽管在项目选项中单元作用域名称看起来是正确的,但它无法编译。我不得不在文本编辑器中打开项目文件,手动将DCC_UnitSearchPath指令移到正确的PropertyGroup中,然后它就可以工作了...以防其他人遇到这个问题。 - Tony

1
关于Unicode,你已经得到了解答。在谷歌上也有很多相关文章。
我还建议您阅读有关类助手和记录助手的内容 - 这可能有助于您重新引入某些已过时的库函数,并延迟对代码库的重新工作。
这也可能有助于您覆盖错误,例如:
var r: TRect;
 ....
  with r do begin
 ....
     B := IntersetRect( A1, A2 );
 ....
  end;

关于 OemToChar - 我建议您最好使用方便的包装器,这些包装器在 Delphi 5 的 RxLib 中提供,然后您可以迁移到 Jedi Code Library,这样您的代码就不会有那个问题了。
但是现在您已经使用 XEn - 您可以完全不需要它。
http://docwiki.embarcadero.com/Libraries/XE2/en/System.SetCodePage
 var sa, so: RawByteString;
 ....
     sa := source; SetCodePage(sa, GetACP(), true);
     so := sa;     SetCodePage(so, GetOEMCP(), true);

类似的代码在我的项目中也能够工作,我用它来解析旧二进制数据。

如果你只关心一个特定的地区设置,那么你可能可以将其硬编码。

 var sa: AnsiString[1251]; so: AnsiString[866]; su: UnicodeString;
 ....
     sa := source; 
 ....
     su := sa; // Win32: MultiByteToWideCharBuf - official Microsoft way
     so := su; // Win32: WideCharToMultiByteBuf - official Microsoft way
 ....
     so := sa;  // double conversion in one step
     // did not tested, but should work accorrding to doc.   
     // looks like obsolete Win16 OemToChar
     // and like codepage-to-codepage direct transcoding
     //     routines from JCL.SF.NET

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接