1,183
社区成员
发帖
与我相关
我的任务
分享
//这是主线程中的一段代码
var
H: THandle;
begin
//之前已经Create了这个线程
H := GetFileThread.Handle;
//为了方便测试,在线程中加入了Sleep(5000)
GetFileThread.Terminate;
//到这里还是正确的,即:5秒后ShowMessage出0
//如果将第3个参数改为False则会立即得到结果,这显然不正确
ShowMessage(IntToStr(MsgWaitForMultipleObjects(1, H, True, INFINITE,
QS_ALLINPUT) - WAIT_OBJECT_0));
end;
var
StartupInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := StartF_UsesTDHandles or STARTF_USESHOWWINDOW;
lpTitle := nil;
wShowWindow := SW_Show;
end;
if not CreateProcess(PChar(ExtractFilePath(ParamStr(0)) + ClientExeName), nil,
nil, nil, True, HIGH_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo)
then
begin
Application.MessageBox('无法启动客户端', '找不到客户端程序', MB_ICONERROR);
end;
end;
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
WM_EXECUTE = WM_USER + 5000;
type
TMyThread = class(TThread)
protected
procedure Execute(); override;
public
constructor Create();
end;
TForm1 = class(TForm)
btn1: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure btn1Click(Sender: TObject);
private
FMyThread: TMyThread;
procedure RunExe(var Msg: TMessage); message WM_EXECUTE;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
ClientExeName = 'notepad.exe';
procedure TForm1.btn1Click(Sender: TObject);
begin
FMyThread := TMyThread.Create;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FMyThread.Free; //请仔细看TThread.Destroy(重点WaitFor)
ShowMessage('线程已经执行完毕');
end;
{ TMyThread }
constructor TMyThread.Create;
begin
inherited Create(False);
end;
procedure TMyThread.Execute;
begin
PostMessage(Form1.Handle, WM_EXECUTE, 0, 0);
end;
procedure TForm1.RunExe(var Msg: TMessage);
var
StartupInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := StartF_UsesTDHandles or STARTF_USESHOWWINDOW;
lpTitle := nil;
wShowWindow := SW_Show;
end;
if not CreateProcess(PChar(ExtractFilePath(ParamStr(0)) + ClientExeName), nil,
nil, nil, True, DETACHED_PROCESS, nil, nil, StartupInfo, ProcessInfo) then
Application.MessageBox('无法启动客户端', '找不到客户端程序', MB_ICONERROR);
Self.Close;
end;
end.
MyThread1.Terminate;
while not MyThread1.Finished do
Application.ProcessMessages;
非常感谢pathletboy的帮助
unit UnitMyThread;
interface
uses
System.Classes, System.SysUtils, Winapi.Messages, Winapi.Windows;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
constructor Create;
end;
implementation
{ TMyThread }
uses UnitMain;
constructor TMyThread.Create;
begin
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TMyThread.Execute;
begin
PostMessage(FormMain.Handle, WM_USER + 5000, 0, 0);
end;
end.
unit UnitMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TFormMain = class(TForm)
btn1: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
procedure RunExe(var Msg: TMessage); message WM_USER + 5000;
public
{ Public declarations }
end;
var
FormMain: TFormMain;
implementation
{$R *.dfm}
uses UnitMyThread;
const
ClientExeName = 'Hash.exe';
var
MyThread1: TMyThread;
H: array [0 .. 0] of THandle;
procedure TFormMain.btn1Click(Sender: TObject);
begin
MyThread1 := TMyThread.Create;
H[0] := MyThread1.Handle;
end;
procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyThread1.Terminate;
ShowMessage(IntToStr(MsgWaitForMultipleObjects(1, H, True, INFINITE,
QS_ALLINPUT) - WAIT_OBJECT_0));
end;
procedure TFormMain.RunExe(var Msg: TMessage);
var
StartupInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := StartF_UsesTDHandles or STARTF_USESHOWWINDOW;
lpTitle := nil;
wShowWindow := SW_Show;
end;
if not CreateProcess(PChar(ExtractFilePath(ParamStr(0)) + ClientExeName), nil,
nil, nil, True, DETACHED_PROCESS, nil, nil, StartupInfo, ProcessInfo) then
Application.MessageBox('无法启动客户端', '找不到客户端程序', MB_ICONERROR);
FormMain.Close;
end;
end.
真是麻烦了,求指教bWaitAll [in]
If this parameter is TRUE, the function returns when the states of all objects in the pHandles array have been set to signaled and an input event has been received. If this parameter is FALSE, the function returns when the state of any one of the objects is set to signaled or an input event has been received. In this case, the return value indicates the object whose state caused the function to return.
你一个等待对象的话,True和False是没有区别的。
B:
这种情况可以自定义消息使用PostMessage。
unit UnitMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TFormMain = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormMain: TFormMain;
I: Integer;
implementation
{$R *.dfm}
uses UnitMyThread;
const
ClientExeName = 'Hash.exe';
var
MyThread1: TMyThread;
H: array [0 .. 0] of THandle;
procedure TFormMain.FormCreate(Sender: TObject);
var
StartupInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin
MyThread1 := TMyThread.Create;
H[0] := MyThread1.Handle;
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := StartF_UsesTDHandles or STARTF_USESHOWWINDOW;
lpTitle := nil;
wShowWindow := SW_Show;
end;;
if not CreateProcess(PChar(ExtractFilePath(ParamStr(0)) + ClientExeName), nil,
nil, nil, True, DETACHED_PROCESS, nil, nil, StartupInfo, ProcessInfo) then
begin
Application.MessageBox('无法启动客户端', '找不到客户端程序', MB_ICONERROR);
end;
end;
procedure TFormMain.btn1Click(Sender: TObject);
begin
MyThread1.Terminate;
ShowMessage(IntToStr(MsgWaitForMultipleObjects(1, H, True, INFINITE,
QS_ALLINPUT) - WAIT_OBJECT_0));
ShowMessage(IntToStr(I));
end;
end.
unit UnitMyThread;
interface
uses
System.Classes, System.SysUtils;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
constructor Create;
end;
implementation
{ TMyThread }
uses UnitMain;
constructor TMyThread.Create;
begin
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TMyThread.Execute;
var
I: Integer;
begin
I := 0;
while not Terminated do
begin
Sleep(100);
Inc(I);
end;
Sleep(2000);
UnitMain.I := I;
end;
end.
果然是这样的,【CreateProcess】、【MsgWaitForMultipleObjects】与【线程】之间的冲突也没有了
还有2个问题:
A:
但这样写才行:MsgWaitForMultipleObjects(1, H, True, INFINITE,QS_ALLINPUT)
百度到其它的写法(第3个参数是False):MsgWaitForMultipleObjects(1, H, False, INFINITE,QS_ALLINPUT)是不行的,难道
这种是错误的?
B:那么如果线程中要更新界面,主线程中又要用MsgWaitForMultipleObjects判断线程的结束,应该如何处理呢?
非常感谢
unit UnitMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TFormMain = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormMain: TFormMain;
implementation
{$R *.dfm}
uses UnitMyThread;
const
ClientExeName='Hash.exe';
var
MyThread1:TMyThread;
H:array[0..0] of THandle;
procedure TFormMain.FormCreate(Sender: TObject);
var
StartupInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin
MyThread1:=TMyThread.Create;
H[0]:=MyThread1.Handle;
{FillChar(StartupInfo, SizeOf(StartupInfo), 0);
with StartupInfo do
begin
cb := SizeOf(StartupInfo);
dwFlags := StartF_UsesTDHandles or STARTF_USESHOWWINDOW;
lpTitle := nil;
wShowWindow := SW_Show;
end;;
if not CreateProcess(PChar(ExtractFilePath(ParamStr(0)) + ClientExeName), nil,
nil, nil, True, DETACHED_PROCESS, nil, nil, StartupInfo, ProcessInfo) then
begin
Application.MessageBox('无法启动客户端', '找不到客户端程序', MB_ICONERROR);
end;}
end;
procedure TFormMain.btn1Click(Sender: TObject);
begin
MyThread1.Terminate;
//MsgWaitForMultipleObjects 完全不起作用了
ShowMessage(IntToStr(MsgWaitForMultipleObjects(1,H,True,INFINITE,QS_ALLINPUT)-WAIT_OBJECT_0));
end;
end.
unit UnitMyThread;
interface
uses
System.Classes,System.SysUtils
;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
public
constructor Create;
end;
implementation
{ TMyThread }
uses UnitMain;
constructor TMyThread.Create;
begin
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TMyThread.Execute;
var
I:Integer;
begin
I:=0;
while not Terminated do
begin
Sleep(100);
Inc(I);
Synchronize(
procedure
begin
FormMain.Caption:=IntToStr(I);
end);
end;
Sleep(2000);
end;
end.
var
H:THandle;
begin
H:=GetFileThread.Handle;
GetFileThread.Terminate;
WaitForSingleObject(H,INFINITE);
ShowMessage('Finish');
end;
尽管H是局部变量在此代码段优先级最高,没什么问题
为了防止意外,还是将它改为其它名字,如THTH,结果仍然相同
WaitForSingleObject和MsgWaitForMultipleObjects均会受到CreateProcess的干扰procedure TThread.Terminate;
begin
FTerminated := True;
end;
如果在你的线程函数中没有处理这个变量跳出函数,那么对于你来说这句是没有任何作用的。
一般典型的线程实现是这样的
procedure TMyThread.Execute;
begin
while not Terminated do
begin
//balabala
end;
end;
当Terminate被执行后Terminated即为True,此时循环体会跳出循环,当然,前提是balabala中的代码不能阻塞。