从Console读取Unicode / ANSI

时间:2012-06-13 23:16:22

标签: delphi unicode cmd delphi-7

我用它来读取cmd(Windows Shell)中的宽字符串。

var
 pBuffer       : array [0..250] of WideChar;
 aBuffer       : array [0..250] of Char;
 RealUnicode   : Integer;
 ExtendedAscii : Integer;
begin
 RealUnicode   := 2;
 ExtendedAscii := 1;
 // ... pipes etc...
 CreateProcessW(nil, pwidechar(ComSpec + ' /U'), nil, nil, TRUE, (CREATE_NEW_CONSOLE or CREATE_BREAKAWAY_FROM_JOB), nil, nil, StartupInfo, ProcessInfo);
 // ...
 while true do begin
  sleep (10); // Reduce CPU Usage
  GetExitCodeProcess(ProcessInfo.hProcess, ExitCode);
  if ExitCode <> STILL_ACTIVE then Break;
  FillChar(pBuffer,SizeOf(PBuffer), #0);
  ReadFile(hoRead, pBuffer[0], 250, BytesRead, nil);    
  if BytesRead > 0 then begin
   if (IsTextUnicode(@pBuffer, BytesRead, @RealUNICODE) or IsTextUnicode(@pBuffer, BytesRead, @ExtendedAscii) then begin
    MessagBoxW(0,dbuffer,'',0);
   end else begin
    FillChar    (aBuffer,SizeOf(aBuffer ), #0);
    CopyMemory  (@aBuffer , @pBuffer, BytesRead * 2);
    MessageBoxA (0, aBuffer, '', 0);
   end;
  end;
 end;
end;

这个片段的效果非常好。它确保如果ansi字符串/字符被写入控制台(例如 - ping.exe),它将在以后获得ANSI输出。 不幸的是,有一点小故障。我使用ping.exe,它可以正常工作,直到它返回到Unicode部分。这实际上很难解释,但我希望你们知道我的意思。 谢谢你的帮助。

编辑: 当ping.exe完成时,片段由于某种原因返回空字符串。尽管阅读比较&gt; 0

EDIT2: enter image description here

说明: 我用CreateProcesW启动cmd,设置管道等,然后读取第一个缓冲区字节(用Unicode)。然后我输入ipconfig并切换回ANSI。然后它读取字节,它们是空的ANSI字符串。之后,“程序”(不是cmd)有时会崩溃。

EDIT3: 我在这里有一个例子(带有源代码和二进制文件)。它是用delphi7和tntcontrols编译的。如果你没有tntcontrols只需在表单中放一个备忘录(名称:Memo1)。并将widestrings更改为字符串和/或尝试使用messageboxW进行调试。 http://dl.dropbox.com/u/349314/UNICODE%20Shell%20Example.rar 这个例子不关心ansi输入!

1 个答案:

答案 0 :(得分:1)

控制台无法正确显示所有Unicode字符。这是因为控制台窗口限制。控制台进程的输出采用OEM编码(或DOS编码),而不是ANSI。

您可以通过将输出重定向到文件来检查它。通常,如果文件包含非英文字符,则该文件无法在记事本中正确显示。

当您使用cmd.exe运行/u时,可以预期它会将Unicode字符写入管道。在这种情况下,您应始终将输出视为Unicode。


您可以通过调用Wide-version来创建进程。但这并不意味着启动过程使用Unicode函数来执行输出。此外,由于Windows 2000所有Ansi版本的Windows API函数都是围绕Wide版本的包装器:

  1. Ansi-function使用默认代码页将输入参数中的所有文本转换为Wide-strings。
  2. 然后它调用宽版本。
  3. 将结果(如果有)从Wide-转换为Ansi并返回。
  4. 然而,对于控制台窗口来说,情况并非如此。程序通常需要将其Unicode标记转换为OEM编码(DOS编码),然后将结果写入stdout。仅在这种情况下,控制台窗口才会正确显示它。