function CreateThread( lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; {入口函数的参数} dwCreationFlags: DWORD; var lpThreadId: DWORD ): THandle; stdcall;
线程入口函数的参数是个无类型指针(Pointer), 用它可以指定任何数据; 本例是把鼠标点击窗体的坐标传递给线程的入口函数, 每次点击窗体都会创建一个线程.
运行效果图:

代码文件:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); end; var Form1: TForm1; implementation {$R *.dfm} var pt: TPoint; {这个坐标点将会已指针的方式传递给线程, 它应该是全局的} function MyThreadFun(p: Pointer): Integer; stdcall; var i: Integer; pt2: TPoint; {因为指针参数给的点随时都在变, 需用线程的局部变量存起来} begin pt2 := PPoint(p)^; {转换} for i := 0 to 1000000 do begin with Form1.Canvas do begin Lock; TextOut(pt2.X, pt2.Y, IntToStr(i)); Unlock; end; end; Result := 0; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ID: DWORD; begin pt := Point(X, Y); CreateThread(nil, 0, @MyThreadFun, @pt, 0, ID); {下面这种写法更好理解, 其实不必, 因为 PPoint 会自动转换为 Pointer 的} //CreateThread(nil, 0, @MyThreadFun, Pointer(@pt), 0, ID); end; end.
窗体文件:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 128 ClientWidth = 229 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnMouseUp = FormMouseUp PixelsPerInch = 96 TextHeight = 13 end
这个例子还有不严谨的地方: 当一个线程 Lock 窗体的 Canvas 时, 其他线程在等待; 线程在等待时, 其中的计数也还在增加. 这也就是说: 现在并没有去处理线程的同步; 同步是多线程中最重要的课题, 快到了.
另外有个小技巧: 线程函数的参数是个 32 位(4个字节)的指针, 仅就本例来讲, 可以让它的 "高16位" 和 "低16位" 分别携带 X 和 Y; 这样就不需要哪个全局的 pt 变量了.
其实在 Windows 的消息中就是这样传递坐标的, 在 Windows 的消息中一般高字节是 Y、低字节是 X; 咱们这么来吧, 这样还可以使用给消息准备的一些方便的函数.
重写本例代码(当然运行效果和窗体文件都是一样的):
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); end; var Form1: TForm1; implementation {$R *.dfm} function MyThreadFun(p: Pointer): Integer; stdcall; var i: Integer; x,y: Word; begin x := LoWord(Integer(p)); y := HiWord(Integer(p)); {如果不使用 LoWord、HiWord 函数可以像下面这样: } //x := Integer(p); //y := Integer(p) shr 16; for i := 0 to 1000000 do begin with Form1.Canvas do begin Lock; TextOut(x, y, IntToStr(i)); Unlock; end; end; Result := 0; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ID: DWORD; num: Integer; begin num := MakeLong(X, Y); {如果不使用 MekeLong、MakeWParam、MakeLParam、MakeResult 等函数, 可以像下面这样: } //num := Y shl 16 + X; CreateThread(nil, 0, @MyThreadFun, Ptr(num), 0, ID); {上面的 Ptr 是专门将一个数字转换为指针的函数, 当然也可以这样: } //CreateThread(nil, 0, @MyThreadFun, Pointer(num), 0, ID); end; end.
分类:
Delphi 与 多线程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2008-02-11 WinAPI: GetCurrentPositionEx - 获取当前的画笔位置
2008-02-11 WinAPI: GetLogicalDriveStrings - 获取系统中存在的逻辑驱动器字符串
2008-02-11 StrCopy、StrCat、StrPas
2008-02-11 WinAPI: GetLogicalDrives - 判断系统中存在的逻辑驱动器
2008-02-11 WinAPI: GetVolumeInformation - 读取文件系统信息
2008-02-11 WinAPI: GetDriveType - 获取磁盘类型
2008-02-11 WinAPI: GetDiskFreeSpaceEx - 获取磁盘容量信息