在Delphi中使用Windows 10管道时出现中文文本。如何用英语制作? [英] I'm getting Chinese Text when using Windows 10 pipes in Delphi. How do I make it in English?
本文介绍了在Delphi中使用Windows 10管道时出现中文文本。如何用英语制作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
使用Windows 10管道尝试在Delphi中读取和写入命令提示符时出现中文文本。我如何用英语制作?
I'm getting Chinese Text when using Windows 10 pipes in trying to read and write to the command prompt in Delphi. How do I make it in English?
。,我不得不修改一些变量来满足编译器的需要。将一些整数更改为基数,等等。这只是输出乱码!
The information from Communicate With Command Prompt Through Delphi is outdated for Delphi 10.3 and I had to modify a few variables to meet the compiler's wants. Changed a few integers to cardinals, etc. It's just outputting gibberish!
这是我根据上面的链接尝试创建的组件的代码:
Here is the code for the component I'm trying to create based on the above link:
unit gtCommandPrompt;
interface
uses
System.SysUtils, System.Classes, Windows;
type
TTmonitorUpdate = procedure(OutPut: String) of object;
TTmonitor = class(TThread) // pipe monitoring thread for console output
private
iThreadSleep: Cardinal;
TextString: String;
FTTmonitorUpdate: TTmonitorUpdate;
procedure UpdateComponent;
protected
procedure Execute; override;
public
property OnUpdateComponent: TTmonitorUpdate read FTTmonitorUpdate write FTTmonitorUpdate;
end;
TOnReadCommandPrompt = procedure(OutPut: String) of object;
TOnWriteCommandPrompt = procedure(OutPut: String) of object;
TOnError = procedure(OutPut: String) of object;
TCommandPrompt = class(TComponent)
private
{ Private declarations }
ThreadDone: Boolean;
FThreadSleep: Cardinal;
FComponentThread: TTmonitor;
FOnError: TOnError;
FOnReadCommandPrompt : TOnReadCommandPrompt;
FOnWriteCommandPrompt : TOnWriteCommandPrompt;
procedure OnThreadUpdate(OutPut: String);
protected
{ Protected declarations }
public
{ Public declarations }
procedure Start();
procedure Stop();
procedure cmdWriteln(text: String);
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
property ThreadSleep: Cardinal read FThreadSleep write FThreadSleep default 40;
property OnReadCommandPrompt: TOnReadCommandPrompt read FOnReadCommandPrompt write FOnReadCommandPrompt;
property OnWriteCommandPrompt: TOnWriteCommandPrompt read FOnWriteCommandPrompt write FOnWriteCommandPrompt;
property OnError: TOnError read FOnError write FOnError;
Destructor Destroy; override;
end;
procedure Register;
var
InputPipeRead, InputPipeWrite: THandle;
OutputPipeRead, OutputPipeWrite: THandle;
ErrorPipeRead, ErrorPipeWrite: THandle;
ProcessInfo : TProcessInformation;
implementation
procedure Register;
begin
RegisterComponents('gtDelphi', [TCommandPrompt]);
end;
constructor TCommandPrompt.Create(AOwner: TComponent);
begin
inherited;
ThreadDone := true;
FThreadSleep := 40;
end;
procedure WritePipeOut(OutputPipe: THandle; InString: string);
// writes Instring to the pipe handle described by OutputPipe
var
byteswritten: Cardinal;
begin
// most console programs require CR/LF after their input.
InString := InString + #13#10;
WriteFile(OutputPipe, Instring[1], Length(Instring), byteswritten, nil);
end;
function ReadPipeInput(InputPipe: THandle; var BytesRem: Cardinal): String;
{
reads console output from InputPipe. Returns the input in function
result. Returns bytes of remaining information to BytesRem
}
var
TextBuffer: array[1..32767] of char;
TextString: String;
BytesRead: Cardinal;
PipeSize: Cardinal;
begin
Result := '';
BytesRead := 0;
PipeSize := Sizeof(TextBuffer);
// check if there is something to read in pipe
PeekNamedPipe(InputPipe, nil, PipeSize, @BytesRead, @PipeSize, @BytesRem);
if bytesread > 0 then
begin
ReadFile(InputPipe, TextBuffer, pipesize, bytesread, nil);
// a requirement for Windows OS system components
OemToChar(@TextBuffer, @TextBuffer);
TextString := String(TextBuffer);
SetLength(TextString, BytesRead);
Result := TextString;
end;
end;
procedure TTmonitor.Execute;
{ monitor thread execution for console output. This must be threaded.
checks the error and output pipes for information every 40 ms, pulls the
data in and updates the memo on the form with the output }
var
BytesRem: Cardinal;
begin
while not Terminated do
begin
// read regular output stream and put on screen.
TextString := ReadPipeInput(OutputPipeRead, BytesRem);
if TextString <> '' then
Synchronize(UpdateComponent);
// now read error stream and put that on screen.
TextString := ReadPipeInput(ErrorPipeRead, BytesRem);
if TextString <> '' then
Synchronize(UpdateComponent);
sleep(iThreadSleep);
end;
end;
procedure TTmonitor.UpdateComponent;
// synchronize procedure for monitor thread
begin
if assigned(FTTmonitorUpdate) = true then FTTmonitorUpdate(TextString);
end;
procedure TCommandPrompt.OnThreadUpdate(OutPut: String);
// synchronize procedure for monitor thread
begin
if assigned(FOnReadCommandPrompt) = true then FOnReadCommandPrompt(OutPut);
end;
Destructor TCommandPrompt.Destroy;
begin
WritePipeOut(InputPipeWrite, 'EXIT'); // quit the CMD we started
FComponentThread.Terminate;
// close process handles
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
// close pipe handles
CloseHandle(InputPipeRead);
CloseHandle(InputPipeWrite);
CloseHandle(OutputPipeRead);
CloseHandle(OutputPipeWrite);
CloseHandle(ErrorPipeRead);
CloseHandle(ErrorPipeWrite);
// Always call the parent destructor after running your own code
inherited;
end;
procedure TCommandPrompt.cmdWriteln(text: String);
begin
WritePipeOut(InputPipeWrite, text);
if assigned(FOnWriteCommandPrompt) = true then FOnWriteCommandPrompt(text);
end;
procedure TCommandPrompt.Stop();
begin
FComponentThread.Terminate;
ThreadDone := true;
end;
procedure TCommandPrompt.Start();
{ upon form creation, this calls the command-interpreter, sets up the three
pipes to catch input and output, and starts a thread to monitor and show
the output of the command-interpreter }
var
DosApp: String;
DosSize: Byte; // was integer
Security : TSecurityAttributes;
start : TStartUpInfo;
begin
if ThreadDone = false then
begin
if assigned(FOnError) then FOnError('Start Error: Thread already running!');
exit;
end;
//CommandText.Clear;
// get COMSPEC variable, this is the path of the command-interpreter
SetLength(Dosapp, 255);
DosSize := GetEnvironmentVariable('COMSPEC', @DosApp[1], 255);
SetLength(Dosapp, DosSize);
// create pipes
With Security do
begin
nlength := SizeOf(TSecurityAttributes) ;
binherithandle := true;
lpsecuritydescriptor := nil;
end;
CreatePipe(InputPipeRead, InputPipeWrite, @Security, 0);
CreatePipe(OutputPipeRead, OutputPipeWrite, @Security, 0);
CreatePipe(ErrorPipeRead, ErrorPipeWrite, @Security, 0);
// start command-interpreter
FillChar(Start,Sizeof(Start),#0) ;
start.cb := SizeOf(start) ;
start.hStdInput := InputPipeRead;
start.hStdOutput := OutputPipeWrite;
start.hStdError := ErrorPipeWrite;
start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
if CreateProcess(nil, PChar(DosApp), @Security, @Security, true,
CREATE_NEW_CONSOLE or SYNCHRONIZE,
nil, nil, start, ProcessInfo) then
begin
FComponentThread := TTmonitor.Create(true); // don't start yet monitor thread
FComponentThread.Priority := tpHigher;
FComponentThread.iThreadSleep := 40;
FComponentThread.FreeOnTerminate := true;
FComponentThread.OnUpdateComponent := OnThreadUpdate;
ThreadDone := false;
FComponentThread.Start; // start thread;
end;
end;
end.
推荐答案
感谢 whosrdaddy !
这是现在可以使用的更新代码:
Here is the updated code that now works:
unit gtCommandPrompt;
interface
uses
System.SysUtils, System.Classes, Windows;
type
TTmonitorUpdate = procedure(OutPut: AnsiString) of object;
TTmonitor = class(TThread) // pipe monitoring thread for console output
private
iThreadSleep: Cardinal;
TextString: AnsiString;
FTTmonitorUpdate: TTmonitorUpdate;
procedure UpdateComponent;
protected
procedure Execute; override;
public
property OnUpdateComponent: TTmonitorUpdate read FTTmonitorUpdate write FTTmonitorUpdate;
end;
TOnReadCommandPrompt = procedure(OutPut: AnsiString) of object;
TOnWriteCommandPrompt = procedure(OutPut: AnsiString) of object;
TOnError = procedure(OutPut: AnsiString) of object;
TCommandPrompt = class(TComponent)
private
{ Private declarations }
ThreadDone: Boolean;
FThreadSleep: Cardinal;
FComponentThread: TTmonitor;
FOnError: TOnError;
FOnReadCommandPrompt : TOnReadCommandPrompt;
FOnWriteCommandPrompt : TOnWriteCommandPrompt;
procedure OnThreadUpdate(OutPut: AnsiString);
protected
{ Protected declarations }
public
{ Public declarations }
procedure Start();
procedure Stop();
procedure cmdWriteln(text: AnsiString);
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
property ThreadSleep: Cardinal read FThreadSleep write FThreadSleep default 40;
property OnReadCommandPrompt: TOnReadCommandPrompt read FOnReadCommandPrompt write FOnReadCommandPrompt;
property OnWriteCommandPrompt: TOnWriteCommandPrompt read FOnWriteCommandPrompt write FOnWriteCommandPrompt;
property OnError: TOnError read FOnError write FOnError;
Destructor Destroy; override;
end;
procedure Register;
var
InputPipeRead, InputPipeWrite: THandle;
OutputPipeRead, OutputPipeWrite: THandle;
ErrorPipeRead, ErrorPipeWrite: THandle;
ProcessInfo : TProcessInformation;
implementation
procedure Register;
begin
RegisterComponents('gtDelphi', [TCommandPrompt]);
end;
constructor TCommandPrompt.Create(AOwner: TComponent);
begin
inherited;
ThreadDone := true;
FThreadSleep := 40;
end;
procedure WritePipeOut(OutputPipe: THandle; InString: AnsiString);
// writes Instring to the pipe handle described by OutputPipe
var
byteswritten: Cardinal;
begin
// most console programs require CR/LF after their input.
InString := InString + #13#10;
WriteFile(OutputPipe, Instring[1], Length(Instring), byteswritten, nil);
end;
function ReadPipeInput(InputPipe: THandle; var BytesRem: Cardinal): AnsiString;
{
reads console output from InputPipe. Returns the input in function
result. Returns bytes of remaining information to BytesRem
}
var
cTextBuffer: array[1..32767] of AnsiChar;
sTextString: AnsiString;
cBytesRead: Cardinal;
cPipeSize: Cardinal;
begin
Result := '';
cBytesRead := 0;
cPipeSize := Sizeof(cTextBuffer);
// check if there is something to read in pipe
PeekNamedPipe(InputPipe, nil, cPipeSize, @cBytesRead, @cPipeSize, @BytesRem);
if cBytesRead > 0 then
begin
ReadFile(InputPipe, cTextBuffer, cPipeSize, cBytesRead, nil);
// a requirement for Windows OS system components
OemToCharA(@cTextBuffer, @cTextBuffer);
sTextString := AnsiString(cTextBuffer);
SetLength(sTextString, cBytesRead);
Result := sTextString;
end;
end;
procedure TTmonitor.Execute;
{ monitor thread execution for console output. This must be threaded.
checks the error and output pipes for information every 40 ms, pulls the
data in and updates the memo on the form with the output }
var
BytesRem: Cardinal;
begin
while not Terminated do
begin
// read regular output stream and put on screen.
TextString := ReadPipeInput(OutputPipeRead, BytesRem);
if TextString <> '' then
Synchronize(UpdateComponent);
// now read error stream and put that on screen.
TextString := ReadPipeInput(ErrorPipeRead, BytesRem);
if TextString <> '' then
Synchronize(UpdateComponent);
sleep(iThreadSleep);
end;
end;
procedure TTmonitor.UpdateComponent;
// synchronize procedure for monitor thread
begin
if assigned(FTTmonitorUpdate) = true then
begin
try
FTTmonitorUpdate(TextString);
finally
end;
end;
end;
procedure TCommandPrompt.OnThreadUpdate(OutPut: AnsiString);
// synchronize procedure for monitor thread
begin
if assigned(FOnReadCommandPrompt) = true then
try
FOnReadCommandPrompt(OutPut);
finally
end;
end;
Destructor TCommandPrompt.Destroy;
begin
WritePipeOut(InputPipeWrite, 'EXIT'); // quit the CMD we started
FComponentThread.Terminate;
// close process handles
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
// close pipe handles
CloseHandle(InputPipeRead);
CloseHandle(InputPipeWrite);
CloseHandle(OutputPipeRead);
CloseHandle(OutputPipeWrite);
CloseHandle(ErrorPipeRead);
CloseHandle(ErrorPipeWrite);
// Always call the parent destructor after running your own code
inherited;
end;
procedure TCommandPrompt.cmdWriteln(text: AnsiString);
begin
WritePipeOut(InputPipeWrite, text);
if assigned(FOnWriteCommandPrompt) = true then
try
FOnWriteCommandPrompt(text);
finally
end;
end;
procedure TCommandPrompt.Stop();
begin
FComponentThread.Terminate;
ThreadDone := true;
end;
procedure TCommandPrompt.Start();
{ upon form creation, this calls the command-interpreter, sets up the three
pipes to catch input and output, and starts a thread to monitor and show
the output of the command-interpreter }
var
DosApp: String;
DosSize: Byte; // was integer
Security : TSecurityAttributes;
start : TStartUpInfo;
begin
if ThreadDone = false then
begin
if assigned(FOnError) then
try
FOnError('Start Error: Thread already running!');
finally
end;
exit;
end;
//CommandText.Clear;
// get COMSPEC variable, this is the path of the command-interpreter
SetLength(Dosapp, 255);
DosSize := GetEnvironmentVariable('COMSPEC', @DosApp[1], 255);
SetLength(Dosapp, DosSize);
// create pipes
With Security do
begin
nlength := SizeOf(TSecurityAttributes) ;
binherithandle := true;
lpsecuritydescriptor := nil;
end;
CreatePipe(InputPipeRead, InputPipeWrite, @Security, 0);
CreatePipe(OutputPipeRead, OutputPipeWrite, @Security, 0);
CreatePipe(ErrorPipeRead, ErrorPipeWrite, @Security, 0);
// start command-interpreter
FillChar(Start,Sizeof(Start),#0) ;
start.cb := SizeOf(start) ;
start.hStdInput := InputPipeRead;
start.hStdOutput := OutputPipeWrite;
start.hStdError := ErrorPipeWrite;
start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
start.wShowWindow := SW_HIDE;
if CreateProcess(nil, PChar(DosApp), @Security, @Security, true,
CREATE_NEW_CONSOLE or SYNCHRONIZE,
nil, nil, start, ProcessInfo) then
begin
FComponentThread := TTmonitor.Create(true); // don't start yet monitor thread
FComponentThread.Priority := tpHigher;
FComponentThread.iThreadSleep := 40;
FComponentThread.FreeOnTerminate := true;
FComponentThread.OnUpdateComponent := OnThreadUpdate;
ThreadDone := false;
FComponentThread.Start; // start thread;
end;
end;
end.
这篇关于在Delphi中使用Windows 10管道时出现中文文本。如何用英语制作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文