//////////////////////////////////////////////////// // // // ThreadedTimer 1.2a // // // // Copyright (C) 1996, 2000 Carlos Barbosa // // email: delphi@carlosb.com // // Home Page: http://www.carlosb.com // // // // Portions (C) 2000, Andrew N. Driazgov // // email: andrey@asp.tstu.ru // // // // Last updated: November 24, 2000 // // // //////////////////////////////////////////////////// unit ThdTimer; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; const DEFAULT_INTERVAL = 1000; type TThreadedTimer = class; TTimerThread = class(TThread) private FOwner: TThreadedTimer; FInterval: Cardinal; FStop: THandle; protected procedure Execute; override; end; TThreadedTimer = class(TComponent) private FOnTimer: TNotifyEvent; FTimerThread: TTimerThread; FEnabled: Boolean; procedure DoTimer; procedure SetEnabled(Value: Boolean); function GetInterval: Cardinal; procedure SetInterval(Value: Cardinal); function GetThreadPriority: TThreadPriority; procedure SetThreadPriority(Value: TThreadPriority); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Enabled: Boolean read FEnabled write SetEnabled default False; property Interval: Cardinal read GetInterval write SetInterval default DEFAULT_INTERVAL; property OnTimer: TNotifyEvent read FOnTimer write FOnTimer; property ThreadPriority: TThreadPriority read GetThreadPriority write SetThreadPriority default tpNormal; end; procedure Register; implementation { TTimerThread } procedure TTimerThread.Execute; begin repeat if WaitForSingleObject(FStop, FInterval) = WAIT_TIMEOUT then Synchronize(FOwner.DoTimer); until Terminated; end; { TThreadedTimer } constructor TThreadedTimer.Create(AOwner: TComponent); begin inherited Create(AOwner); FTimerThread := TTimerThread.Create(True); with FTimerThread do begin FOwner := Self; FInterval := DEFAULT_INTERVAL; Priority := tpNormal; // Event is completely manipulated by TThreadedTimer object FStop := CreateEvent(nil, False, False, nil); end; end; destructor TThreadedTimer.Destroy; begin with FTimerThread do begin Terminate; // When this method is called we must be confident that the event handle was not closed SetEvent(FStop); if Suspended then Resume; WaitFor; CloseHandle(FStop); // Close event handle in the primary thread Free; end; inherited Destroy; end; procedure TThreadedTimer.DoTimer; begin // We have to check FEnabled in the primary thread // Otherwise we get AV when the program is closed if FEnabled and Assigned(FOnTimer) then FOnTimer(Self); end; procedure TThreadedTimer.SetEnabled(Value: Boolean); begin if Value <> FEnabled then begin FEnabled := Value; if FEnabled then begin if FTimerThread.FInterval > 0 then begin SetEvent(FTimerThread.FStop); FTimerThread.Resume; end; end else FTimerThread.Suspend; end; end; function TThreadedTimer.GetInterval: Cardinal; begin Result := FTimerThread.FInterval; end; procedure TThreadedTimer.SetInterval(Value: Cardinal); var PrevEnabled: Boolean; begin if Value <> FTimerThread.FInterval then begin // We must restore the previous state of the Enabled property PrevEnabled := FEnabled; Enabled := False; FTimerThread.FInterval := Value; Enabled := PrevEnabled; end; end; function TThreadedTimer.GetThreadPriority: TThreadPriority; begin Result := FTimerThread.Priority; end; procedure TThreadedTimer.SetThreadPriority(Value: TThreadPriority); begin FTimerThread.Priority := Value; end; procedure Register; begin RegisterComponents('System', [TThreadedTimer]); end; end.
unit thdTimer; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type TTimerStatus = (TS_ENABLE, TS_CHANGEINTERVAL, TS_DISABLE, TS_SETONTIMER); TThreadedTimer = class; TTimerThread = class; PTimerThread = ^TTimerThread; TTimerThread = class(TThread) OwnerTimer: TThreadedTimer; Interval: DWord; Enabled : Boolean; Status : TTimerStatus; constructor Create(CreateSuspended: Boolean); procedure Execute; override; destructor Destroy; override; procedure DoTimer; end; TThreadedTimer = class(TComponent) private FEnabled: Boolean; FInterval: DWord; FOnTimer: TNotifyEvent; FTimerThread: TTimerThread; FThreadPriority: TThreadPriority; protected procedure UpdateTimer; procedure SetEnabled(Value: Boolean); procedure SetInterval(Value: DWord); procedure SetOnTimer(Value: TNotifyEvent); procedure Timer; dynamic; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Enabled: Boolean read FEnabled write SetEnabled default True; property Interval: DWord read FInterval write SetInterval default 1000; property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer; end; implementation uses Unit1; procedure WakeupDownThrdproc(const evenFlag: Integer); stdcall; begin Form1.lbl1.Caption:=Format('鼠标键盘已经有 %d 秒没有使用', [(LastInput)div 1000]); end; procedure TTimerThread.Execute; begin inherited; while not Terminated do begin SleepEx(Interval, True); if (not Terminated) and (Status = TS_ENABLE) then Synchronize(DoTimer); if Status <> TS_ENABLE then begin case Status of TS_CHANGEINTERVAL: begin Status := TS_ENABLE; SleepEx(0,True); end; TS_DISABLE: begin Status := TS_ENABLE; SleepEx(0, True); if not Terminated then Suspend; end; TS_SETONTIMER: begin Status := TS_ENABLE; end else Status := TS_ENABLE; end; end; end; end; procedure TTimerThread.DoTimer; begin OwnerTimer.Timer; end; constructor TThreadedTimer.Create(AOwner: TComponent); begin inherited Create(AOwner); FInterval := 1000; FThreadPriority := tpNormal; FTimerThread := TTimerThread.Create(true); FTimerThread.OwnerTimer := self; end; destructor TThreadedTimer.Destroy; begin inherited Destroy; FTimerThread.Terminate; QueueUserAPC(@WakeupDownThrdproc, FTimerThread.Handle, DWORD(FTimerThread)); FTimerThread.Free; end; procedure TThreadedTimer.UpdateTimer; begin if (FEnabled = False) then begin FTimerThread.OwnerTimer := Self; FTimerThread.Interval := FInterval; FTimerThread.Priority := FThreadPriority; FTimerThread.Resume; end; if (FEnabled = True) then begin QueueUserAPC(@WakeupDownThrdproc, FTimerThread.Handle, DWORD(FTimerThread)); end; end; procedure TThreadedTimer.SetEnabled(Value: Boolean); begin if Value <> FEnabled then begin FEnabled := Value; if Value then begin FTimerThread.Status := TS_ENABLE; FTimerThread.Resume; end else begin FTimerThread.Status := TS_DISABLE; QueueUserAPC(@WakeupDownThrdproc, FTimerThread.Handle, DWORD(FTimerThread)); end; end; end; procedure TThreadedTimer.SetInterval(Value: DWord); begin if Value <> FInterval then begin if (not Enabled) then begin FInterval := Value; FTimerThread.Interval := FInterval; end else begin FInterval := Value; FTimerThread.Interval := FInterval; FTimerThread.Status := TS_CHANGEINTERVAL; QueueUserAPC(@WakeupDownThrdproc, FTimerThread.Handle, DWORD(FTimerThread)); end; end; end; procedure TThreadedTimer.SetOnTimer(Value: TNotifyEvent); begin FOnTimer := Value; end; procedure TThreadedTimer.Timer; begin if Assigned(FOnTimer) then FOnTimer(Self); //在这里放置的代码,是不是也属于多线程机制 end; destructor TTimerThread.Destroy; begin inherited; end; constructor TTimerThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); Interval := 1000; Enabled := False; Status := TS_DISABLE; end; end.
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SvcMgr; const WM_MyMessage = WM_USER + 100; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; TMsgThread = class(TThread) private Atom1: atom; FMyString: string; procedure ShowString; public constructor Create(CreateSuspended: Boolean); overload; destructor Destroy; override; procedure ProcessRequests(WaitForMessage: Boolean); protected procedure Execute; override; end; //http://topic.csdn.net/t/20030218/17/1440830.html 在线程中怎样处理消息 //can zhao SvcMgr.pas zhong de TServiceThread //另类远程线程插入法 http://www.blogcn.com/user17/fmtwld/blog/4441223.html TMsgThread2 = class(TThread) private atomF4: atom; CanTerminated: Boolean; FMyString: string; procedure ShowString; procedure NotificationWndProc(var Message: TMessage); public MHandle: HWnd; constructor Create(CreateSuspended: Boolean); overload; destructor Destroy; override; protected procedure Execute; override; end; var Form1: TForm1; TestThread: TMsgThread; TestThread2: TMsgThread2; implementation {$R *.dfm} procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin PostMessage(TestThread2.MHandle, WM_CLOSE, 0, 0); sleep(300); end; procedure TForm1.Button1Click(Sender: TObject); begin if assigned(TestThread) then PostThreadMessage(TestThread.ThreadID, WM_QUIT, 0, 0); end; procedure TForm1.Button2Click(Sender: TObject); begin if assigned(TestThread) then PostThreadMessage(TestThread.ThreadID, WM_MyMessage, 0, 0); end; procedure TForm1.Button3Click(Sender: TObject); begin if assigned(TestThread2) then PostMessage(TestThread2.MHandle, WM_CLOSE, 0, 0); end; procedure TForm1.FormCreate(Sender: TObject); begin TestThread := TMsgThread.Create(False); TestThread2 := TMsgThread2.Create(False); end; procedure TForm1.FormDestroy(Sender: TObject); begin if assigned(TestThread) then begin TestThread.Terminate; if TestThread.Suspended then TestThread.Suspend; TestThread.WaitFor; FreeAndNil(TestThread); end; if assigned(TestThread2) then begin TestThread2.Terminate; if TestThread2.Suspended then TestThread2.Suspend; TestThread2.WaitFor; FreeAndNil(TestThread2); end; end; { TMsgThread } constructor TMsgThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); end; destructor TMsgThread.Destroy; begin inherited; end; procedure TMsgThread.Execute; var msg: TMsg; begin Atom1:=globalfindatom('HotKeyIDhzh'); if Atom1=0 then Atom1 := GlobalAddAtom('HotKeyIDhzh'); RegisterHotKey(0, Atom1, MOD_CONTROL, ord('B')); //RegisterHotKey(Handle, atomF4, 0, vk_F4); FMyString := 'Thread Started!'; Synchronize(ShowString); PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); { Create message queue } //ProcessRequests(True); ProcessRequests(False); UnRegisterHotKey(0, Atom1); //取消热键 GlobalDeleteAtom(Atom1); end; {procedure TMsgThread.Execute; var Msg: TMsg; DMsg: TMessage; begin FMyString := 'Thread Started!'; Synchronize(ShowString); while (not Terminated) do begin if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin if (Msg.message = WM_QUIT) then begin FMyString := 'Thread QuIT'; Synchronize(ShowString); Terminate; end; if (Msg.message = WM_MyMessage) then begin FMyString := 'Thread Get a USER Message!'; Synchronize(ShowString); end; if (Msg.message = WM_HOTKEY) then begin DMsg.Msg := Msg.message; DMsg.wParam := Msg.wParam; DMsg.lParam := Msg.lParam; DMsg.Result := 0; //if (DMsg.LParamLo = MOD_CONTROL) and (DMsg.LParamHi = ord('B')) then begin FMyString := 'TMsgThread Get Ctrl R!'; Synchronize(ShowString); end; end; end; end; end;} procedure TMsgThread.ProcessRequests(WaitForMessage: Boolean); var msg: TMsg; DMsg: TMessage; Rslt: Boolean; begin while not Terminated do begin //FillChar(msg, sizeof(msg), #0); if WaitForMessage then Rslt := GetMessage(msg, 0, 0, 0) else Rslt := PeekMessage(msg, 0, 0, 0, PM_REMOVE); if not Rslt then // Some Meesage will PM_REMOVE Fail begin //FMyString := 'PeekMessage none!'; //Synchronize(ShowString); //break; continue; end; if Rslt and (msg.hwnd = 0) then { Thread message } begin if (Msg.message = WM_QUIT) then begin FMyString := 'Thread QuIT'; Synchronize(ShowString); Terminate; end else if (Msg.message = WM_MyMessage) then begin FMyString := 'Thread Get a USER Message!'; Synchronize(ShowString); end else if (Msg.message = WM_HOTKEY) then begin DMsg.Msg := Msg.message; DMsg.wParam := Msg.wParam; DMsg.lParam := Msg.lParam; DMsg.Result := 0; if (DMsg.LParamLo = MOD_CONTROL) and (DMsg.LParamHi = ord('B')) then begin FMyString := 'TMsgThread Get Ctrl B!'; Synchronize(ShowString); end; end else DispatchMessage(msg); end else DispatchMessage(msg); end; end; procedure TMsgThread.ShowString; begin Form1.Memo1.Lines.Add(FMyString); end; { TMsgThread2 } constructor TMsgThread2.Create(CreateSuspended: Boolean); begin CanTerminated := False; MHandle := Classes.AllocateHWnd(NotificationWndProc); atomF4 := GlobalAddAtom('hot_key2'); //RegisterHotKey(Mhandle, atomF4, 0, vk_F4); RegisterHotKey(Mhandle, atomF4, MOD_CONTROL, ord('R')); inherited Create(CreateSuspended); end; destructor TMsgThread2.Destroy; begin UnRegisterHotKey(Mhandle, atomF4); //取消热键 GlobalDeleteAtom(atomF4); //释放id if MHandle <> 0 then Classes.DeallocateHWnd(MHandle); inherited; end; procedure TMsgThread2.Execute; begin while (not CanTerminated) do begin Sleep(300); end; end; procedure TMsgThread2.NotificationWndProc(var Message: TMessage); begin if Message.Msg = WM_CLOSE then begin CanTerminated := True; if CanTerminated then begin FMyString := 'Thread2 QuIT'; Synchronize(ShowString); end; end; if Message.Msg = WM_HOTKEY then if (Message.LParamLo = MOD_CONTROL) and (Message.LParamHi = 82) then begin FMyString := 'TMsgThread2 Get Ctrl R!'; Synchronize(ShowString); end; end; procedure TMsgThread2.ShowString; begin if assigned(Form1) and assigned(Form1.Memo1) then Form1.Memo1.Lines.Add(FMyString); end; end.
unit Unit1; interface { Reduce EXE size by disabling as much of RTTI as possible (delphi 2009/2010) } {$IF CompilerVersion >= 21.0} {$WEAKLINKRTTI ON} {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])} {$IFEND} uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Web.Win.Sockets; type TForm1 = class(TForm) tcpclnt1: TTcpClient; btn1: TButton; mmo1: TMemo; tcpsrvr1: TTcpServer; btn2: TButton; procedure btn1Click(Sender: TObject); procedure tcpclnt1Connect(Sender: TObject); procedure tcpclnt1Receive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer); procedure tcpsrvr1Accept(Sender: TObject; ClientSocket: TCustomIpClient); procedure tcpsrvr1GetThread(Sender: TObject; var ClientSocketThread: TClientSocketThread); procedure btn2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; TServerThread=class(TClientSocketThread) private s:string; protected procedure SyncProc;override; end; { TServerThread } var Form1: TForm1; implementation {$R *.dfm} procedure TServerThread.SyncProc; begin Form1.mmo1.Lines.Add(formatdatetime('mm-dd hh:mm:ss :',now)+s); end; procedure TForm1.btn1Click(Sender: TObject); begin if not tcpclnt1.Active then begin tcpclnt1.RemoteHost :='127.0.0.1'; tcpclnt1.RemotePort:='6700'; tcpclnt1.Active:=True; end; mmo1.Lines.Add('Send data'); tcpclnt1.Sendln('testdata'); end; procedure TForm1.btn2Click(Sender: TObject); begin tcpsrvr1.LocalHost:='127.0.0.1'; tcpsrvr1.LocalPort:='6700'; tcpsrvr1.Active:=True; end; procedure TForm1.tcpclnt1Connect(Sender: TObject); begin mmo1.Lines.Add('连接服务器'); end; procedure TForm1.tcpclnt1Receive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer); begin mmo1.Lines.Add(StrPas(Buf)); end; procedure TForm1.tcpsrvr1Accept(Sender: TObject; ClientSocket: TCustomIpClient); var T:TServerThread; buf:array [0..256] of Char; count:integer; begin T:=TServerThread(ClientSocket.GetThreadObject); //获取该线程的对象句柄 T.s :=clientsocket.RemoteHost +'已连接'; T.ExecuteSyncProc; //添加已连接的日志 while not T.Terminated and clientsocket.Connected do begin //该线程未中止和客户端未中止连接时执行 if ClientSocket.WaitForData(0) then begin //如果客户端发送数据 count:=8;// ClientSocket.BytesSent; ClientSocket.ReceiveBuf(buf,count); t.s:=StrPas(buf);// ClientSocket.Receiveln(); //接收数据 ClientSocket.Sendln('Re:'+t.s); //回复客户端 if t.s='QUIT' then ClientSocket.Disconnect //如果是退出指令,则断开连接 else T.SyncProc; //否则添加日志 end; end; t.s :=clientsocket.RemoteHost +'已断开'; //添加断开客户端的日志 T.ExecuteSyncProc; mmo1.Lines.Add('有用户连接'); end; procedure TForm1.tcpsrvr1GetThread(Sender: TObject; var ClientSocketThread: TClientSocketThread); begin mmo1.Lines.Add('重载获取数据线程'); ClientSocketThread:=TServerThread.Create(tcpsrvr1.ServerSocketThread); end; end.
(**************************** Unit : clsMenuEngine Author : Departure Url : ic0de.org ****************************) unit clsMenuEngine; interface uses Windows, SysUtils, Variants, D3DX9, Direct3D9, DXTypes; type TItems = packed record strName: PAnsiChar; bOn : Boolean; bShowCheck: Boolean; end; Type TMenuEngine = Class Private pD3Ddev: Direct3D9.IDirect3DDevice9; fMenuFont: D3DX9.ID3DXFont; bVisable: Boolean; iMenuX, iMenuY, iMenuW, iMenuH, iMenuItems: Integer; dwMenuBgColor, dwMenuBorderColor, dwCrossHairColor, dwTextColor: Dword; Function GetDevice():IDirect3DDevice9; function GetFont(): ID3DXFont; procedure DrawRectangle(iXleft, iYtop, iWidth, iHight: Integer; Color: Dword); procedure DrawRectangleAlpha(iXleft, iYtop, iWidth, iHight: Integer; Color: Dword); procedure DrawBorder(); procedure DrawBorderAlpha(); procedure DrawCheck( Color: Dword; x, y: Integer); procedure DrawDash( Color: Dword; x, y: Integer); procedure DrawPlus(Color: Dword; x, y: Integer); procedure DrawBox(); procedure DrawBoxAlpha(); procedure DrawText(const iLeft, iTop: Integer; szText: PAnsiChar); Public aItems: Array of TItems; Constructor Create( Left, Top, Width, Hight, Items: Integer; BGColor, BDColor, TXTColor: Dword); Destructor Destroy(); Override; Procedure Render(); Procedure Reset(Const pDevice: IDirect3DDevice9); procedure DrawXhair(); procedure MenuItemAdd( iIndex: Integer; szText: PAnsiChar; bOnOff: Boolean; bShowOnOff: Boolean = True); Property Direct3DDevice: Direct3D9.IDirect3DDevice9 read pD3Ddev write pD3Ddev; Property MenuLeft: Integer read iMenuX write iMenuX; Property MenuTop: Integer read iMenuY write iMenuY; Property MenuWidth: Integer read iMenuW write iMenuW; Property MenuHight: Integer read iMenuH write iMenuH; Property MenuItems: Integer read iMenuItems write iMenuItems; Property BackGroundColor: Dword read dwMenuBgColor write dwMenuBgColor; Property BorderColor: Dword read dwMenuBorderColor write dwMenuBorderColor; Property TextColor: Dword read dwTextColor write dwTextColor; Property XHairColor: Dword read dwCrossHairColor write dwCrossHairColor; Property Menuvisable: Boolean read bVisable write bVisable; end; implementation { TMenuEngine } constructor TMenuEngine.Create( Left, Top, Width, Hight, Items: Integer; BGColor, BDColor, TXTColor: Dword); begin MenuLeft:= Left; MenuTop:= Top; MenuWidth:= Width; MenuHight:= Hight; BackGroundColor:= BGColor; BorderColor:= BDColor; TextColor:= TXTColor; MenuItems:= Items; SetLength(aItems,MenuItems); end; destructor TMenuEngine.Destroy; var i: Integer; begin inherited Destroy(); pD3Ddev:= Nil; fMenuFont:= Nil; end; procedure TMenuEngine.DrawBorder; begin DrawRectangle(iMenuX, (iMenuY + iMenuH - 1), iMenuW, 1, dwMenuBorderColor); DrawRectangle(iMenuX, iMenuY, 1, iMenuH, dwMenuBorderColor); DrawRectangle(iMenuX, iMenuY, iMenuW, 1, dwMenuBorderColor); DrawRectangle((iMenuX + iMenuW - 1), iMenuY, 1, iMenuH, dwMenuBorderColor); end; procedure TMenuEngine.DrawBorderAlpha; begin DrawRectangleAlpha(iMenuX, (iMenuY + iMenuH - 1), iMenuW, 1, dwMenuBorderColor); DrawRectangleAlpha(iMenuX, iMenuY, 1, iMenuH, dwMenuBorderColor); DrawRectangleAlpha(iMenuX, iMenuY, iMenuW, 1, dwMenuBorderColor); DrawRectangleAlpha((iMenuX + iMenuW - 1), iMenuY, 1, iMenuH, dwMenuBorderColor); end; procedure TMenuEngine.DrawBox; begin DrawRectangle(iMenuX, iMenuY, iMenuW, iMenuH, dwMenuBgColor); DrawBorder; end; procedure TMenuEngine.DrawBoxAlpha; begin DrawRectangleAlpha(iMenuX, iMenuY, iMenuW, iMenuH, dwMenuBgColor); DrawBorderAlpha; end; procedure TMenuEngine.DrawCheck(Color: Dword; x, y: Integer); begin DrawRectangle( x, y, 1, 3, Color ); DrawRectangle( x + 1, y + 1, 1, 3, Color ); DrawRectangle( x + 2, y + 2, 1, 3, Color ); DrawRectangle( x + 3, y + 1, 1, 3, Color ); DrawRectangle( x + 4, y, 1, 3, Color ); DrawRectangle( x + 5, y - 1, 1, 3, Color ); DrawRectangle( x + 6, y - 2, 1, 3, Color ); DrawRectangle( x + 7, y - 3, 1, 3, Color ); end; procedure TMenuEngine.DrawDash(Color: Dword; x, y: Integer); begin DrawRectangle( x , y , 8, 3, Color ); end; procedure TMenuEngine.DrawPlus(Color: Dword; x, y: Integer); begin DrawRectangle( x , y , 7, 1, Color ); DrawRectangle( x + 3 , y - 3 , 1, 7, Color ); end; procedure TMenuEngine.DrawRectangle(iXleft, iYtop, iWidth, iHight: Integer; Color: Dword); var d3dRectangle : D3DRECT; begin d3dRectangle.x1:= iXleft; d3dRectangle.y1:= iYtop; d3dRectangle.x2:= iXleft + iWidth; d3dRectangle.y2:= iYtop + iHight; Direct3DDevice.Clear(1,@d3dRectangle, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, Color, 0, 0); end; procedure TMenuEngine.DrawRectangleAlpha(iXleft, iYtop, iWidth, iHight: Integer; Color: Dword); type tStruct = packed record x, y, z, rhw: Single; Color: dWord; end; procedure AssignVertex(var Vertex: tStruct; x, y, z, rhw: Single; Color: Dword); begin Vertex.x:= x; Vertex.y:= y; Vertex.z:= z; Vertex.Color:= Color; end; var qV: array[0..3] of tStruct; begin AssignVertex(qV[0], iXLeft, iYtop + iHight, 0.0, 0.0, Color); AssignVertex(qV[1], iXLeft, iYtop, 0.0, 0.0, Color); AssignVertex(qV[2], iXLeft + iWidth, iYtop + iHight, 0.0, 0.0, Color); AssignVertex(qV[3], iXLeft + iWidth, iYtop, 0.0, 0.0, Color); Direct3DDevice.SetRenderState(D3DRS_ALPHABLENDENABLE,1); Direct3DDevice.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); Direct3DDevice.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); Direct3DDevice.SetRenderState(D3DRS_FOGENABLE, 0); Direct3DDevice.SetFVF(D3DFVF_XYZRHW or D3DFVF_DIFFUSE); Direct3DDevice.SetTexture(0, Nil); Direct3DDevice.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,qV,SizeOf(tStruct)); end; procedure TMenuEngine.DrawText(const iLeft, iTop: Integer; szText: PAnsiChar); var d3dRectangle : D3DRECT; begin d3dRectangle.x1:= ileft; d3dRectangle.y1:= itop; d3dRectangle.x2:= ileft + 130; d3dRectangle.y2:= itop + 10; fMenuFont.DrawTextA(nil, szText, -1, @d3dRectangle, 0{( DT_CALCRECT or DT_NOCLIP )}, dwTextColor); end; procedure TMenuEngine.DrawXhair; var viewP: D3DVIEWPORT9; ScreenCenterX,ScreenCenterY: DWORD; d3dRectangle1,d3dRectangle2: D3DRECT; begin // Get screen Direct3DDevice.GetViewport(viewP); ScreenCenterX:= ((viewP.Width div 2) - 1); ScreenCenterY:= ((viewP.Height div 2) - 1); //Set xhair params d3dRectangle1.x1:= ScreenCenterX-10; d3dRectangle1.y1:= ScreenCenterY; d3dRectangle1.x2:= ScreenCenterX+ 10; d3dRectangle1.y2:= ScreenCenterY+1; d3dRectangle2.x1:= ScreenCenterX; d3dRectangle2.y1:= ScreenCenterY-10; d3dRectangle2.x2:= ScreenCenterX+ 1; d3dRectangle2.y2:= ScreenCenterY+10; //Draw crosshair Direct3DDevice.Clear(1, @d3dRectangle1, D3DCLEAR_TARGET, XHairColor, 0, 0); Direct3DDevice.Clear(1, @d3dRectangle2, D3DCLEAR_TARGET, XHairColor, 0, 0); end; function TMenuEngine.GetDevice: IDirect3DDevice9; begin Result:= Direct3DDevice; end; function TMenuEngine.GetFont: ID3DXFont; begin Result:= fMenuFont; end; procedure TMenuEngine.MenuItemAdd(iIndex: Integer; szText: PAnsiChar; bOnOff: Boolean; bShowOnOff : Boolean = True); begin aItems[pred(iIndex)].strName:= szText; aItems[pred(iIndex)].bOn:= bOnOff; aItems[pred(iIndex)].bShowCheck:= bShowOnOff; end; procedure TMenuEngine.Render; var i: integer; begin if MenuVisable then begin if MenuHight = 0 then MenuHight:= ((11 * MenuItems)+ 9); DrawBoxAlpha; for i:= 1 to MenuItems do begin If aItems[pred(i)].bShowCheck then begin TextColor:= $FF6746A3; DrawText(MenuLeft + 5,(MenuTop + 5 + (i*11) - 11) , PChar(aItems[pred(i)].strName)); if i = 2 then DrawPlus(XHairColor, (MenuLeft + MenuWidth) - 12 , (MenuTop + 5 + (i*11) - 11) + 2) else Case aItems[pred(i)].bOn of True: DrawCheck($EE00FF00, (MenuLeft + MenuWidth) - 12 , (MenuTop + 5 + (i*11) - 11) + 2); False: DrawDash($EEFF0000, (MenuLeft + MenuWidth) - 12 , (MenuTop + 5 + (i*11) - 11) + 2); end; end else begin TextColor:= $FFCB7018; DrawText(MenuLeft + 5,(MenuTop + 5 + (i*11) - 11) , PChar(aItems[pred(i)].strName)); end; end; end; end; procedure TMenuEngine.Reset(Const pDevice: IDirect3DDevice9); begin if Direct3DDevice <> pDevice then begin Direct3DDevice:= pDevice; fMenuFont:= nil; if fMenuFont = nil then D3DXCreateFont(Direct3DDevice,10, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, 'Terminal', fMenuFont); end; end; end.
//****************************************************************************** // // 模块名 :发送字符串消息 // 版本号 :1.0 // 创建者 :AnderHejlsberg // 创建日期 :2011-9-16 // 修改者 : // 修改日期 : // Comment : // // //****************************************************************************** unit uSendStrMsg; interface uses Windows, Messages, SysUtils, Variants, Classes, Controls, SyncObjs, Math; type TShowMsgEvent = procedure(AMsg : string; APointer : Pointer) of object; TFreePointerEvent = procedure(APointer : Pointer) of object; TStringMsgObj = class(TThread) Private FShowMsg : TShowMsgEvent; FFreePointer : TFreePointerEvent; FCS : TCriticalSection; FMsgList : TStringList; hSemRequestCount : THandle; hThreadTerminated : THandle; FTerminated : Boolean; procedure DoShowMsg(AMsg : string; APointer : Pointer); procedure DoFreePointer(APointer : Pointer); //执行释放SendMsg参数APointer的事件 function GetMsg(var AObj : TObject) : string; function GetMsgCount : integer; Public constructor Create(OnShowMsg : TShowMsgEvent; OnFreePointer : TFreePointerEvent); destructor Destroy; Override; procedure SendMsg(AMsg : string; APointer : Pointer = nil); procedure Execute; Override; procedure Terminate(Force : Boolean = False); Published property MsgCount : integer Read GetMsgCount; property Terminated : Boolean Read FTerminated; end; implementation { TStringMsgObj } constructor TStringMsgObj.Create(OnShowMsg : TShowMsgEvent; OnFreePointer : TFreePointerEvent); begin inherited Create(True); FCS := TCriticalSection.Create; FMsgList := TStringList.Create; hSemRequestCount := CreateSemaphore(nil, 0, $7FFFFFFF, nil); hThreadTerminated := CreateEvent(nil, True, False, nil); FShowMsg := OnShowMsg; FFreePointer := OnFreePointer; FTerminated := False; Resume; end; destructor TStringMsgObj.Destroy; var AObj : TObject; AMsg : string; begin CloseHandle(hSemRequestCount); CloseHandle(hThreadTerminated); while True do begin AMsg := GetMsg(AObj); if AMsg = '' then Break; DoFreePointer(AObj); end; FMsgList.Free; FCS.Free; inherited; end; procedure TStringMsgObj.DoFreePointer(APointer : Pointer); begin if Assigned(FFreePointer) then FFreePointer(APointer); end; procedure TStringMsgObj.DoShowMsg(AMsg : string; APointer : Pointer); begin if Assigned(FShowMsg) then FShowMsg(AMsg, APointer); end; procedure TStringMsgObj.Execute; type THandleID = (hidRequest, hidTerminate); var Handles : array[THandleID] of THandle; AObj : TObject; AMsg : string; begin Handles[hidRequest] := hSemRequestCount; Handles[hidTerminate] := hThreadTerminated; while not Terminated do begin case WaitForMultipleObjects(Length(Handles), @Handles, False, INFINITE) of WAIT_OBJECT_0 + Ord(hidRequest) : begin AObj := nil; AMsg := GetMsg(AObj); if AMsg = '' then Break; DoShowMsg(AMsg, Pointer(AObj)); if AObj <> nil then DoFreePointer(AObj); end; WAIT_OBJECT_0 + Ord(hidTerminate) : begin Break; end; end; end; end; function TStringMsgObj.GetMsg(var AObj : TObject) : string; begin FCS.Enter; try Result := ''; AObj := nil; if FMsgList.Count > 0 then begin AObj := FMsgList.Objects[0]; Result := FMsgList[0]; FMsgList.Delete(0); end; finally FCS.Leave; end; end; function TStringMsgObj.GetMsgCount : integer; begin FCS.Enter; try Result := FMsgList.Count; finally FCS.Leave; end; end; procedure TStringMsgObj.SendMsg(AMsg : string; APointer : Pointer = nil); begin FCS.Enter; try FMsgList.AddObject(AMsg, TObject(APointer)); ReleaseSemaphore(hSemRequestCount, 1, nil); finally FCS.Leave; end; end; procedure TStringMsgObj.Terminate(Force : Boolean = False); begin inherited Terminate; if Force then begin TerminateThread(Handle, 0); Free end else begin FTerminated := True; SetEvent(hThreadTerminated); end; end; end.
unit FileMap; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Dialogs; type TFileMap = class(TComponent) private FMapHandle: THandle; //内存映射文件句柄 FMutexHandle: THandle; //互斥句柄 FMapName: string; //内存映射对象 FSynchMessage: string; //同步消息 FMapStrings: TStringList; //存储映射文件信息 FSize: DWord; //映射文件大小 FMessageID: DWord; //注册的消息号 FMapPointer: PChar; //映射文件的数据区指针 FLocked: Boolean; //锁定 FIsMapOpen: Boolean; //文件是否打开 FExistsAlready: Boolean; //是否已经建立过映射文件 FReading: Boolean; //是否正在读取内存文件数据 FAutoSynch: Boolean; //是否同步 FOnChange: TNotifyEvent; //当内存数据区内容改变时 FFormHandle: Hwnd; //存储本窗口的窗口句柄 FPNewWndHandler: Pointer; FPOldWndHandler: Pointer; procedure SetMapName(Value: string); procedure SetMapStrings(Value: TStringList); procedure SetSize(Value: DWord); procedure SetAutoSynch(Value: Boolean); procedure EnterCriticalSection; procedure LeaveCriticalSection; procedure MapStringsChange(Sender: TObject); procedure NewWndProc(var FMessage: TMessage); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure OpenMap; procedure CloseMap; procedure ReadMap; procedure WriteMap; property ExistsAlready: Boolean read FExistsAlready; property IsMapOpen: Boolean read FIsMapOpen; published property MaxSize: DWord read FSize write SetSize; property AutoSynchronize: Boolean read FAutoSynch write SetAutoSynch; property MapName: string read FMapName write SetMapName; property MapStrings: TStringList read FMapStrings write SetMapStrings; property OnChange: TNotifyEvent read FOnChange write FOnChange; end; implementation //构造函数 constructor TFileMap.Create(AOwner: TComponent); begin inherited Create(AOwner); FAutoSynch := True; FSize := 4096; FReading := False; FMapStrings := TStringList.Create; FMapStrings.OnChange := MapStringsChange; FMapName := 'Unique & Common name'; FSynchMessage := FMapName + 'Synch-Now'; if AOwner is TForm then begin FFormHandle := (AOwner as TForm).Handle; //得到窗口处理过程的地址 FPOldWndHandler := Ptr(GetWindowLong(FFormHandle, GWL_wNDPROC)); FPNewWndHandler := MakeObjectInstance(NewWndProc); if FPNewWndHandler = nil then raise Exception.Create('超出资源'); //设置窗口处理过程的新地址 SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPNewWndHandler)); end else raise Exception.Create('组件的所有者应该是TForm'); end; //析构函数 destructor TFileMap.Destroy; begin CloseMap; //还原Windows处理过程地址 SetWindowLong(FFormHandle, GWL_WNDPROC, Longint(FPOldWndHandler)); if FPNewWndHandler <> nil then FreeObjectInstance(FPNewWndHandler); //释放对象 FMapStrings.Free; FMapStrings := nil; inherited destroy; end; //打开文件映射,并映射到进程空间 procedure TFileMap.OpenMap; var TempMessage: array[0..255] of Char; begin if (FMapHandle = 0) and (FMapPointer = nil) then begin FExistsAlready := False; //创建文件映射对象 FMapHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, FSize, PChar(FMapName)); if (FMapHandle = INVALID_HANDLE_VALUE) or (FMapHandle = 0) then raise Exception.Create('创建文件映射对象失败!') else begin //判断是否已经建立文件映射了 if (FMapHandle <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then FExistsAlready := True; //如果已经建立的话,就设它为TRUE; //映射文件的使徒到进程的地址空间 FMapPointer := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0); if FMapPointer = nil then raise Exception.Create('映射文件的视图到进程的地址空间失败') else begin StrPCopy(TempMessage, FSynchMessage); //在WINDOWS中注册消息常量 FMessageID := RegisterWindowMessage(TempMessage); if FMessageID = 0 then raise Exception.Create('注册消息失败') end end; //创建互斥对象,在写文件映射空间时用到它,以保持数据同步 FMutexHandle := Windows.CreateMutex(nil, False, PChar(FMapName + '.Mtx')); if FMutexHandle = 0 then raise Exception.Create('创建互斥对象失败'); FIsMapOpen := True; if FExistsAlready then //判断内存文件映射是否已打开 ReadMap else WriteMap; end; end; //解除文件视图和内存映射空间的关系,并关闭文件映射 procedure TFileMap.CloseMap; begin if FIsMapOpen then begin //释放互斥对象 if FMutexHandle <> 0 then begin CloseHandle(FMutexHandle); FMutexHandle := 0; end; //关闭内存对象 if FMapPointer <> nil then begin //解除文件视图和内存映射空间的关系 UnMapViewOfFile(FMapPointer); FMapPointer := nil; end; if FMapHandle <> 0 then begin //并关闭文件映射 CloseHandle(FMapHandle); FMapHandle := 0; end; FIsMapOpen := False; end; end; //读取内存文件映射内容 procedure TFileMap.ReadMap; begin FReading := True; if (FMapPointer <> nil) then FMapStrings.SetText(FMapPointer); end; //向内存映射文件里写 procedure TFileMap.WriteMap; var StringsPointer: PChar; // HandleCounter: integer; // SendToHandle: HWnd; begin if FMapPointer <> nil then begin StringsPointer := FMapStrings.GetText; //进入互斥状态,防止其他线程进入同步区域代码 EnterCriticalSection; if StrLen(StringsPointer) + 1 <= FSize then System.Move(StringsPointer^, FMapPointer^, StrLen(StringsPointer) + 1) else raise Exception.Create('写字符串失败,字符串太大!'); //离开互斥状态 LeaveCriticalSection; //广播消息,表示内存映射文件内容已经修改 SendMessage(HWND_BROADCAST, FMessageID, FFormHandle, 0); //释放StringsPointer StrDispose(StringsPointer); end; end; //当MapStrings值改变时 procedure TFileMap.MapStringsChange(Sender: TObject); begin if FReading and Assigned(FOnChange) then FOnChange(Self) else if (not FReading) and FIsMapOpen and FAutoSynch then WriteMap; end; //设置MapName属性值 procedure TFileMap.SetMapName(Value: string); begin if (FMapName <> Value) and (FMapHandle = 0) and (Length(Value) < 246) then begin FMapName := Value; FSynchMessage := FMapName + 'Synch-Now'; end; end; //设置MapStrings属性值 procedure TFileMap.SetMapStrings(Value: TStringList); begin if Value.Text <> FMapStrings.Text then begin if Length(Value.Text) <= FSize then FMapStrings.Assign(Value) else raise Exception.Create('写入值太大'); end; end; //设置内存文件大小 procedure TFileMap.SetSize(Value: DWord); var StringsPointer: PChar; begin if (FSize <> Value) and (FMapHandle = 0) then begin StringsPointer := FMapStrings.GetText; if (Value < StrLen(StringsPointer) + 1) then FSize := StrLen(StringsPointer) + 1 else FSize := Value; if FSize < 32 then FSize := 32; StrDispose(StringsPointer); end; end; //设置是否同步 procedure TFileMap.SetAutoSynch(Value: Boolean); begin if FAutoSynch <> Value then begin FAutoSynch := Value; if FAutoSynch and FIsMapOpen then WriteMap; end; end; //进入互斥,使得被同步的代码不能被别的线程访问 procedure TFileMap.EnterCriticalSection; begin if (FMutexHandle <> 0) and not FLocked then begin FLocked := (WaitForSingleObject(FMutexHandle, INFINITE) = WAIT_OBJECT_0); end; end; //解除互斥关系,可以进入保护的同步代码区 procedure TFileMap.LeaveCriticalSection; begin if (FMutexHandle <> 0) and FLocked then begin ReleaseMutex(FMutexHandle); FLocked := False; end; end; //消息捕获过程 procedure TFileMap.NewWndProc(var FMessage: TMessage); begin with FMessage do begin if FIsMapOpen then //内存文件打开 {如果消息是FMessageID,且WParam不是FFormHandle,就调用 ReadMap去读取内存映射文件的内容,表示内存映射文件的 内容已变} if (Msg = FMessageID) and (WParam <> FFormHandle) then ReadMap; Result := CallWindowProc(FPOldWndHandler, FFormHandle, Msg, wParam, lParam); end; end; end. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,FileMap; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; CheckBox1: TCheckBox; CheckBox2: TCheckBox; CheckBox3: TCheckBox; procedure FormCreate(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure CheckBox1Click(Sender: TObject); procedure Memo1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Memo1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); private { Private declarations } //定义TFileMap对象 FileMap: TFileMap; //定义FileMapChange用于赋给FileMap的OnChange事件 procedure FileMapChange(Sender: TObject); procedure Check; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.Check; begin CheckBox2.Checked:=FileMap.ExistsAlready; CheckBox3.Checked:=FileMap.IsMapOpen; end; procedure TForm1.FileMapChange(Sender: TObject); begin memo1.Lines.Assign(FileMap.MapStrings); check; end; procedure TForm1.FormCreate(Sender: TObject); begin //创建FileMap FileMap:=TFileMap.Create(self); FileMap.OnChange:=FileMapchange; CheckBox1.Checked:=FileMap.AutoSynchronize; //如果内存对象还未创建,初始化FileMap里的内容 if not FileMap.ExistsAlready then begin memo1.Lines.LoadFromFile('readme.txt'); FileMap.MapStrings.Assign(memo1.Lines); end; end; procedure TForm1.Button4Click(Sender: TObject); begin FileMap.WriteMap; end; procedure TForm1.Button3Click(Sender: TObject); begin FileMap.ReadMap; end; procedure TForm1.Button5Click(Sender: TObject); begin memo1.Clear; FileMap.MapStrings.Clear; check; end; procedure TForm1.Button1Click(Sender: TObject); begin FileMap.MapName:='Delphi 7'; FileMap.OpenMap; check; end; procedure TForm1.Button2Click(Sender: TObject); begin FileMap.CloseMap; check; end; procedure TForm1.CheckBox1Click(Sender: TObject); begin FileMap.AutoSynchronize:=CheckBox1.checked; end; procedure TForm1.Memo1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FileMap.MapStrings.Assign(memo1.Lines); end; procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin FileMap.MapStrings.Assign(memo1.Lines); end; end. object Form1: TForm1 Left = 277 Top = 282 Width = 979 Height = 563 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object Memo1: TMemo Left = 56 Top = 40 Width = 209 Height = 369 Lines.Strings = ( 'Memo1') ScrollBars = ssVertical TabOrder = 0 OnKeyUp = Memo1KeyUp OnMouseDown = Memo1MouseDown end object Button1: TButton Left = 304 Top = 40 Width = 75 Height = 25 Caption = 'OpenMap' TabOrder = 1 OnClick = Button1Click end object Button2: TButton Left = 304 Top = 74 Width = 75 Height = 25 Caption = 'CloseMap' TabOrder = 2 OnClick = Button2Click end object Button3: TButton Left = 304 Top = 108 Width = 75 Height = 25 Caption = 'ReadMap' TabOrder = 3 OnClick = Button3Click end object Button4: TButton Left = 304 Top = 142 Width = 75 Height = 25 Caption = 'WriteMap' TabOrder = 4 OnClick = Button4Click end object Button5: TButton Left = 304 Top = 176 Width = 75 Height = 25 Caption = 'Clear' TabOrder = 5 OnClick = Button5Click end object CheckBox1: TCheckBox Left = 408 Top = 40 Width = 97 Height = 17 Caption = 'AutoSynchronize' TabOrder = 6 OnClick = CheckBox1Click end object CheckBox2: TCheckBox Left = 408 Top = 72 Width = 97 Height = 17 Caption = 'ExistsAlready' TabOrder = 7 end object CheckBox3: TCheckBox Left = 408 Top = 104 Width = 97 Height = 17 Caption = 'IsMapOpen' TabOrder = 8 end end
/////////////////////////////////////////////////////////////////////////////// //Base64 DEMO V1.0// //作者:ksaiy// //欢迎使用由ksaiy制作的Base64加密算法演示程序,此算法为标准的Base64算法,你可以 //根据的的自己需要进行变形。具体怎么操作可以登录我们的网站查询详细的资料。我们专 //门为软件开发者提供软件加密安全测试服务和软件加密解决方案,具体的可以参看我们的 //网站上的资料。我们的网站:http://www.ksaiy.com http://www.magicoa.com //技术支持:ksaiy@sina.com 在线QQ:40188696 UC:934155 //End // //注意:转载请保留以上信息。// /////////////////////////////////////////////////////////////////////////////// unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit1: TEdit; Edit2: TEdit; Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; function MimeEncodeString (const s: AnsiString): AnsiString; function MimeEncodeStringNoCRLF (const s: AnsiString): AnsiString; function MimeDecodeString (const s: AnsiString): AnsiString; procedure MimeEncodeStream (const InputStream: TStream; const OutputStream: TStream); procedure MimeEncodeStreamNoCRLF (const InputStream: TStream; const OutputStream: TStream); procedure MimeDecodeStream (const InputStream: TStream; const OutputStream: TStream); function MimeEncodedSize (const i: Cardinal): Cardinal; function MimeEncodedSizeNoCRLF (const i: Cardinal): Cardinal; function MimeDecodedSize (const i: Cardinal): Cardinal; procedure DecodeHttpBasicAuthentication (const BasicCredentials: AnsiString; out UserId, PassWord: AnsiString); procedure MimeEncode (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); procedure MimeEncodeNoCRLF (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); procedure MimeEncodeFullLines (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); function MimeDecode (const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer): Cardinal; function MimeDecodePartial (const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal; function MimeDecodePartialEnd (out OutputBuffer; const ByteBuffer: Cardinal; const ByteBufferSpace: Cardinal): Cardinal; procedure Base64Encode(InputFile, OutputFile: string); procedure Base64Decode(InputFile, OutputFile: string); //Download by http://www.codefans.net const MIME_ENCODED_LINE_BREAK = 76; MIME_DECODED_LINE_BREAK = MIME_ENCODED_LINE_BREAK div 4 * 3; BUFFER_SIZE = MIME_DECODED_LINE_BREAK * 3 * 4 * 16; MIME_ENCODE_TABLE : array[0..63] of Byte = ( 065, 066, 067, 068, 069, 070, 071, 072, // 00 - 07 073, 074, 075, 076, 077, 078, 079, 080, // 08 - 15 081, 082, 083, 084, 085, 086, 087, 088, // 16 - 23 089, 090, 097, 098, 099, 100, 101, 102, // 24 - 31 103, 104, 105, 106, 107, 108, 109, 110, // 32 - 39 111, 112, 113, 114, 115, 116, 117, 118, // 40 - 47 119, 120, 121, 122, 048, 049, 050, 051, // 48 - 55 052, 053, 054, 055, 056, 057, 043, 047); // 56 - 63 MIME_PAD_CHAR = Byte ('='); MIME_DECODE_TABLE : array[Byte] of Cardinal = ( 255, 255, 255, 255, 255, 255, 255, 255, // 00 - 07 255, 255, 255, 255, 255, 255, 255, 255, // 08 - 15 255, 255, 255, 255, 255, 255, 255, 255, // 16 - 23 255, 255, 255, 255, 255, 255, 255, 255, // 24 - 31 255, 255, 255, 255, 255, 255, 255, 255, // 32 - 39 255, 255, 255, 062, 255, 255, 255, 063, // 40 - 47 052, 053, 054, 055, 056, 057, 058, 059, // 48 - 55 060, 061, 255, 255, 255, 255, 255, 255, // 56 - 63 255, 000, 001, 002, 003, 004, 005, 006, // 64 - 71 007, 008, 009, 010, 011, 012, 013, 014, // 72 - 79 015, 016, 017, 018, 019, 020, 021, 022, // 80 - 87 023, 024, 025, 255, 255, 255, 255, 255, // 88 - 95 255, 026, 027, 028, 029, 030, 031, 032, // 96 - 103 033, 034, 035, 036, 037, 038, 039, 040, // 104 - 111 041, 042, 043, 044, 045, 046, 047, 048, // 112 - 119 049, 050, 051, 255, 255, 255, 255, 255, // 120 - 127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255); type PByte4 = ^TByte4; TByte4 = packed record b1: Byte; b2: Byte; b3: Byte; b4: Byte; end; PByte3 = ^TByte3; TByte3 = packed record b1: Byte; b2: Byte; b3: Byte; end; var Form1: TForm1; implementation {$R *.dfm} function MimeEncodeString (const s: AnsiString): AnsiString; var l : Cardinal; begin if Pointer (s) <> nil then begin l := Cardinal (Pointer (Cardinal (s) - 4)^); SetLength (Result, MimeEncodedSize (l)); MimeEncode (Pointer (s)^, l, Pointer (Result)^); end else Result := ''; end; function MimeEncodeStringNoCRLF (const s: AnsiString): AnsiString; var l : Cardinal; begin if Pointer (s) <> nil then begin l := Cardinal (Pointer (Cardinal (s) - 4)^); SetLength (Result, MimeEncodedSizeNoCRLF (l)); MimeEncodeNoCRLF (Pointer (s)^, l, Pointer (Result)^); end else Result := ''; end; function MimeDecodeString (const s: AnsiString): AnsiString; var ByteBuffer, ByteBufferSpace: Cardinal; l : Cardinal; begin if Pointer (s) <> nil then begin l := Cardinal (Pointer (Cardinal (s) - 4)^); SetLength (Result, (l + 3) div 4 * 3); ByteBuffer := 0; ByteBufferSpace := 4; l := MimeDecodePartial (Pointer (s)^, l, Pointer (Result)^, ByteBuffer, ByteBufferSpace); Inc (l, MimeDecodePartialEnd (Pointer (Cardinal (Result) + l)^, ByteBuffer, ByteBufferSpace)); SetLength (Result, l); end else Result := ''; end; procedure MimeEncodeStream (const InputStream: TStream; const OutputStream: TStream); var InputBuffer : array[0..BUFFER_SIZE - 1] of Byte; OutputBuffer : array[0.. (BUFFER_SIZE + 2) div 3 * 4 + BUFFER_SIZE div MIME_DECODED_LINE_BREAK * 2 - 1] of Byte; BytesRead : Cardinal; IDelta, ODelta : Cardinal; begin BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); while BytesRead = SizeOf (InputBuffer) do begin MimeEncodeFullLines (InputBuffer, SizeOf (InputBuffer), OutputBuffer); OutputStream.Write (OutputBuffer, SizeOf (OutputBuffer)); BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); end; MimeEncodeFullLines (InputBuffer, BytesRead, OutputBuffer); IDelta := BytesRead div MIME_DECODED_LINE_BREAK; // Number of lines processed. ODelta := IDelta * (MIME_ENCODED_LINE_BREAK + 2); IDelta := IDelta * MIME_DECODED_LINE_BREAK; MimeEncodeNoCRLF(Pointer(Cardinal (@InputBuffer) + IDelta)^, BytesRead - IDelta, Pointer (Cardinal (@OutputBuffer) + ODelta)^); OutputStream.Write (OutputBuffer, MimeEncodedSize (BytesRead)); end; procedure MimeEncodeStreamNoCRLF (const InputStream: TStream; const OutputStream: TStream); var InputBuffer : array[0..BUFFER_SIZE - 1] of Byte; OutputBuffer : array[0.. ((BUFFER_SIZE + 2) div 3) * 4 - 1] of Byte; BytesRead : Cardinal; begin BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); while BytesRead = SizeOf (InputBuffer) do begin MimeEncodeNoCRLF (InputBuffer, SizeOf (InputBuffer), OutputBuffer); OutputStream.Write (OutputBuffer, SizeOf (OutputBuffer)); BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); end; MimeEncodeNoCRLF (InputBuffer, BytesRead, OutputBuffer); OutputStream.Write (OutputBuffer, (BytesRead + 2) div 3 * 4); end; procedure MimeDecodeStream (const InputStream: TStream; const OutputStream: TStream); var ByteBuffer, ByteBufferSpace: Cardinal; InputBuffer : array[0..BUFFER_SIZE - 1] of Byte; OutputBuffer : array[0.. (BUFFER_SIZE + 3) div 4 * 3 - 1] of Byte; BytesRead : Cardinal; begin ByteBuffer := 0; ByteBufferSpace := 4; BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); while BytesRead > 0 do begin OutputStream.Write(OutputBuffer, MimeDecodePartial(InputBuffer, BytesRead, OutputBuffer, ByteBuffer, ByteBufferSpace)); BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer)); end; OutputStream.Write (OutputBuffer, MimeDecodePartialEnd (OutputBuffer, ByteBuffer, ByteBufferSpace)); end; procedure DecodeHttpBasicAuthentication (const BasicCredentials: AnsiString; out UserId, PassWord: AnsiString); label Fail; const LBasic = 6; { Length ('Basic ') } var DecodedPtr, p : PAnsiChar; i, l : Cardinal; begin p := Pointer (BasicCredentials); if p = nil then goto Fail; l := Cardinal (Pointer (p - 4)^); if l <= LBasic then goto Fail; Dec (l, LBasic); Inc (p, LBasic); GetMem (DecodedPtr, (l + 3) div 4 * 3 { MimeDecodedSize (l) }); l := MimeDecode (p^, l, DecodedPtr^); i := 0; p := DecodedPtr; while (l > 0) and (p[i] <> ':') do begin Inc (i); Dec (l); end; SetString (UserId, DecodedPtr, i); if l > 1 then SetString (PassWord, DecodedPtr + i + 1, l - 1) else PassWord := ''; FreeMem (DecodedPtr); Exit; Fail: UserId := ''; PassWord := ''; end; function MimeEncodedSize (const i: Cardinal): Cardinal; begin Result := (i + 2) div 3 * 4 + (i - 1) div MIME_DECODED_LINE_BREAK * 2; end; function MimeEncodedSizeNoCRLF (const i: Cardinal): Cardinal; begin Result := (i + 2) div 3 * 4; end; function MimeDecodedSize (const i: Cardinal): Cardinal; begin Result := (i + 3) div 4 * 3; end; procedure MimeEncode (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); var IDelta, ODelta : Cardinal; begin MimeEncodeFullLines (InputBuffer, InputByteCount, OutputBuffer); IDelta := InputByteCount div MIME_DECODED_LINE_BREAK; ODelta := IDelta * (MIME_ENCODED_LINE_BREAK + 2); IDelta := IDelta * MIME_DECODED_LINE_BREAK; MimeEncodeNoCRLF (Pointer (Cardinal (@InputBuffer) + IDelta)^, InputByteCount - IDelta, Pointer (Cardinal (@OutputBuffer) + ODelta)^); end; procedure MimeEncodeFullLines (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); var b, OuterLimit : Cardinal; InPtr, InnerLimit : ^Byte; OutPtr : PByte4; begin if InputByteCount = 0 then Exit; InPtr := @InputBuffer; OutPtr := @OutputBuffer; InnerLimit := InPtr; Inc (Cardinal (InnerLimit), MIME_DECODED_LINE_BREAK); OuterLimit := Cardinal (InPtr); Inc (OuterLimit, InputByteCount); while Cardinal (InnerLimit) <= OuterLimit do begin while InPtr <> InnerLimit do begin b := InPtr^; b := b shl 8; Inc (InPtr); b := b or InPtr^; b := b shl 8; Inc (InPtr); b := b or InPtr^; Inc (InPtr); OutPtr^.b4 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b3 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b2 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b1 := MIME_ENCODE_TABLE[b]; Inc (OutPtr); end; OutPtr^.b1 := 13; OutPtr^.b2 := 10; Inc (Cardinal (OutPtr), 2); Inc (InnerLimit, MIME_DECODED_LINE_BREAK); end; end; procedure MimeEncodeNoCRLF (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer); var b, OuterLimit : Cardinal; InPtr, InnerLimit : ^Byte; OutPtr : PByte4; begin if InputByteCount = 0 then Exit; InPtr := @InputBuffer; OutPtr := @OutputBuffer; OuterLimit := InputByteCount div 3 * 3; InnerLimit := @InputBuffer; Inc (Cardinal (InnerLimit), OuterLimit); while InPtr <> InnerLimit do begin b := InPtr^; b := b shl 8; Inc (InPtr); b := b or InPtr^; b := b shl 8; Inc (InPtr); b := b or InPtr^; Inc (InPtr); OutPtr^.b4 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b3 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b2 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr^.b1 := MIME_ENCODE_TABLE[b]; Inc (OutPtr); end; case InputByteCount - OuterLimit of 1: begin b := InPtr^; b := b shl 4; OutPtr.b2 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr.b1 := MIME_ENCODE_TABLE[b]; OutPtr.b3 := MIME_PAD_CHAR; OutPtr.b4 := MIME_PAD_CHAR; end; 2: begin b := InPtr^; Inc (InPtr); b := b shl 8; b := b or InPtr^; b := b shl 2; OutPtr.b3 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr.b2 := MIME_ENCODE_TABLE[b and $3F]; b := b shr 6; OutPtr.b1 := MIME_ENCODE_TABLE[b]; OutPtr.b4 := MIME_PAD_CHAR; { Pad remaining byte. } end; end; end; function MimeDecode (const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer): Cardinal; var ByteBuffer, ByteBufferSpace: Cardinal; begin ByteBuffer := 0; ByteBufferSpace := 4; Result := MimeDecodePartial(InputBuffer, InputBytesCount, OutputBuffer, ByteBuffer, ByteBufferSpace); Inc (Result, MimeDecodePartialEnd(Pointer (Cardinal(@OutputBuffer) + Result)^, ByteBuffer, ByteBufferSpace)); end; function MimeDecodePartial (const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal; var lByteBuffer, lByteBufferSpace, c: Cardinal; InPtr, OuterLimit : ^Byte; OutPtr : PByte3; begin if InputBytesCount > 0 then begin InPtr := @InputBuffer; Cardinal (OuterLimit) := Cardinal (InPtr) + InputBytesCount; OutPtr := @OutputBuffer; lByteBuffer := ByteBuffer; lByteBufferSpace := ByteBufferSpace; while InPtr <> OuterLimit do begin c := MIME_DECODE_TABLE[InPtr^]; Inc (InPtr); if c = $FF then Continue; lByteBuffer := lByteBuffer shl 6; lByteBuffer := lByteBuffer or c; Dec (lByteBufferSpace); if lByteBufferSpace <> 0 then Continue; OutPtr^.b3 := Byte (lByteBuffer); lByteBuffer := lByteBuffer shr 8; OutPtr^.b2 := Byte (lByteBuffer); lByteBuffer := lByteBuffer shr 8; OutPtr^.b1 := Byte (lByteBuffer); lByteBuffer := 0; Inc (OutPtr); lByteBufferSpace := 4; end; ByteBuffer := lByteBuffer; ByteBufferSpace := lByteBufferSpace; Result := Cardinal (OutPtr) - Cardinal (@OutputBuffer); end else Result := 0; end; function MimeDecodePartialEnd (out OutputBuffer; const ByteBuffer: Cardinal; const ByteBufferSpace: Cardinal): Cardinal; var lByteBuffer : Cardinal; begin case ByteBufferSpace of 1: begin lByteBuffer := ByteBuffer shr 2; PByte3 (@OutputBuffer)^.b2 := Byte (lByteBuffer); lByteBuffer := lByteBuffer shr 8; PByte3 (@OutputBuffer)^.b1 := Byte (lByteBuffer); Result := 2; end; 2: begin lByteBuffer := ByteBuffer shr 4; PByte3 (@OutputBuffer)^.b1 := Byte (lByteBuffer); Result := 1; end; else Result := 0; end; end; procedure Base64Encode(InputFile, OutputFile: string); var Ms: TMemoryStream; Ss: TStringStream; Str: string; List: TStringList; begin {Base64 encode} Ms := TMemoryStream.Create; try Ms.LoadFromFile(InputFile); Ss := TStringStream.Create(Str); try MimeEncodeStream(Ms, Ss); List := TStringList.Create; try List.Text := Ss.DataString; List.SaveToFile(OutputFile); finally List.Free; end; finally Ss.Free; end; finally Ms.Free; end; end; procedure Base64Decode(InputFile, OutputFile: string); var Ms: TMemoryStream; Ss: TStringStream; List: TStringList; begin {Base64 decode} List := TStringList.Create; try List.LoadFromFile(InputFile); Ss := TStringStream.Create(List.Text); try Ms := TMemoryStream.Create; try MimeDecodeStream(Ss, Ms); Ms.SaveToFile(OutputFile); finally Ms.Free; end; finally Ss.Free; end; finally List.Free; end; end; procedure TForm1.Button1Click(Sender: TObject); begin //function MimeEncodeString (const s: AnsiString): AnsiString;//加密字符串函数; //function MimeDecodeString (const s: AnsiString): AnsiString;//解密字符串函数; if MimeEncodeString(Edit1.Text)=Edit2.Text then ShowMessage('注册成功!') else ShowMessage('注册失败!'); /////////////////////////////////////////////////////////////////////////////// //Base64 DEMO V1.0// //作者:ksaiy// //欢迎使用由ksaiy制作的Base64加密算法演示程序,此算法为标准的Base64算法,你可以 //根据的的自己需要进行变形。具体怎么操作可以登录我们的网站查询详细的资料。我们专 //门为软件开发者提供软件加密安全测试服务和软件加密解决方案,具体的可以参看我们的 //网站上的资料。我们的网站:http://www.ksaiy.com http://www.magicoa.com //技术支持:ksaiy@sina.com 在线QQ:40188696 UC:934155 //End // //注意:转载请保留以上信息。// /////////////////////////////////////////////////////////////////////////////// end; procedure TForm1.Button2Click(Sender: TObject); begin Close; end; end.
//第1种花指令 procedure TForm1.Button1Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jb @label jnb @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第2种花指令 procedure TForm1.Button2Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm je @label jne @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第3种花指令 procedure TForm1.Button3Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jbe @label ja @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第4种花指令 procedure TForm1.Button4Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm js @label jns @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第5种花指令 procedure TForm1.Button5Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jpe @label jpo @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第6种花指令 procedure TForm1.Button6Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jl @label jge @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第7种花指令 procedure TForm1.Button7Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jle @label jg @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第8种花指令 procedure TForm1.Button8Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jz @label jnz @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第9种花指令 procedure TForm1.Button9Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm push ecx xor ecx,ecx jcxz @label db $E8 @label: pop ecx end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第10种花指令 procedure TForm1.Button10Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm jl @label1 @label2: jmp @label3 db $E8 @label1: jz @label2 @label3: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第11种花指令 procedure TForm1.Button11Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm call @label1 db $E8 jmp @label2 db $E8 @label1: pop eax jmp @label3 db $E8,$E8,$E8 @label3: inc eax jmp @label4 db $E8,$E8,$E8 @label4: jmp eax db $E8 @label2: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; //第12种花指令 procedure TForm1.Button12Click(Sender: TObject); var a,b:Integer; begin a:=20;b:=10; asm call @label1 db $E8,$E8 jmp @label4 @label1: pop eax jmp @label2 db $E8,$E8 @label2: add eax,2 jmp @label3 db $E8 @label3: push eax ret db $E8 @label4: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end;
var a,b:Integer; begin a:=20;b:=10; asm jo @label jno @label db $E8 @label: end; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end; var a,b:Integer; begin a:=20;b:=10; if a>b then Messagebox(Handle,'a>b','info',MB_OK); end;
unit rsrDownMan; interface uses SysUtils, Classes, StrUtils, DateUtils, Windows, Forms, Gauges, StdCtrls, IDHTTP, IdFTP, IdComponent; { 自动下载组件 by renshouren mail root@renshou.net QQ 114032666 2009.05.25 工作流程 通过 DownStart 过程,取FURLList下载列表中的第一条作为当前URL(FCurURL) 通过线程 THTTPGetHeadThread ,使用TIdHTTP 的HEAD方法,返回文件信息 启动工作线程 THTTPDownThread ,下载数据 工作时,可以通过 TDownWorkEvent 的workFileInfo参数获得正在下载文件的一些相关信息, 该信息类应当于加入下载列表时加入,在TAFileDownEndEvent用户代码中释放该类 2009.06.04 加入 FTP 下载,采用 PASV模式 } Const MAX_THREAD = 10; FIRST_THREAD_SIZE = 1024 * 100;//小于100K 的将使用单线程 type FTPWorkEndException = class (Exception); TDownFileType = (dfNorm, dfExe, dfList, dfMDB); TDownErrorEvent = procedure(Sender: TObject; const ErrMsg: string) of object; TDownEventMode = (deCreate, deConnected, deDisConnected, deWork, deWorkBegin, deWorkEnd, deDownEnd); TDownWorkEvent = procedure(Sender: TObject; const AWorkCount: Integer; workFileInfo{正在下载文件的一些附属信息}: TObject) of object; TGetHTTPHeadEvent = procedure(Sender: TObject; const ResponseText: string; Const ResponseCode: integer; var AutoDownNext: boolean) of object; TAFileDownEndEvent = procedure(Sender: TObject; stream: TMemoryStream; lastFileInfo{用户应该在响应此事件后释放本类}: TObject) of object; TGetFTPHeadEvent = procedure(Sender: TObject; Const CanResume: boolean; Size: int64; var AutoDownNext: boolean) of object; TIdHTTPResponseInfo = record //返回的HTTP信息 FCacheControl: String; //FRawHeaders: TIdHeaderList; FConnection: string; FContentEncoding: string; FContentLanguage: string; FContentLength: Integer; FContentRangeEnd: Cardinal; FContentRangeStart: Cardinal; FContentType: string; FContentVersion: string; //FCustomHeaders: TIdHeaderList; FDate: TDateTime; FExpires: TDateTime; FLastModified: TDateTime; FPragma: string; FHasContentLength: Boolean; FLocation :string; FServer :string; FResponseText :string; FResponseCode :Integer; FResponseVersion :TIdHTTPProtocolVersion; end; TDownServerInfo = record FHost :string; FPort :Integer; FUserName :string; FPassWord :string; FRemoteFile :string;//文件相对URL end; TDownThreadInfo = record nIndex :Integer;//线程编号 URL :string; nStart :Integer;//开始位置 nEnd :Integer; //结束位置 nByteCount :Integer;//下载块长度 end; { 下载类 基类, 包含纯虚方法,因此不能直接创建其实例 procedure BeginThread; virtual; abstract; //启动下载线程 } TBaseDownMan = class (TComponent) private FThreadCount :integer; MyThread :array [0..MAX_THREAD] of TThread; //最大 MAX_THREAD 个 线程 FOnError :TDownErrorEvent; //错误 FOnAFileEnd :TAFileDownEndEvent; //一个文件完成 FOnAllDownEnd :TNotifyEvent; //所有文件下载完成 FOnWork :TDownWorkEvent; //接收到数据 FStartTime :TDateTime; //下载开始时间 FTotalFileCount :Integer; //文件数 FCurFileCount :Integer; //当前第几个 FCurFileSize :int64; //当前文件大小 FDownTotalBytes :Int64; //所有文件已下载字节数 FTotalBytes :Int64; //所有下载任务需下载的字节数[由调用者作为参数提供] FGaugeTotal, FGaugeCur : TGauge; //进度条 FlbURL{显示当前下载文件的URL}, FlbSpeed{显示下载速度}, FlbFileCount: TLabel; FCurURL :string; //当前正在下载的URL FCurURLObject :TObject; //当前下载文件的一些附加信息,有可能为NIL FLocalFileName :string; //根据URL得到的本地文件名 FNeedSec :Integer;//推测剩余时间(秒) FDownServerInfo :TDownServerInfo; //服务器信息 FAutoSaveFile :Boolean; //是否在最后一线程完成后自动保存为本地文件 FAThreadDefaultSize :integer;//单个线程默认大小 FAverageSpeed :integer; //平均速度 K/秒 FWorkingThreadCount :Integer; //尚未完成下载任务的线程数,如果该值为0,则总下载任务完成 FThreadAWorkCount :Integer; //[当前文件]所有线程下载的字节数 FLastThreadAWorkCount :Integer; FThreadTotalCount :Integer; //总线程数 FStream :TMemoryStream; FFileType :TDownFileType; FURLList :TStringList; //需要下载的URL列表 procedure SetTotalBytes (Value: int64); procedure ResetGaugeTotal; //解决Gauge.MaxValue 的Max 值太小的问题 function GetFileNameByURL (URL: string): string; function RemoteFileToURL (rname: string): string; procedure ThreadOnTerminate (Sender: TObject); procedure IdHTTPOnRedirect(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod); procedure SetThreadCount (value: integer); procedure DoError (ErrMsg: string); procedure getHead; virtual; procedure downNext; virtual; procedure downData; virtual; procedure BeginThread; virtual; abstract; //启动下载线程 procedure GetDownServerInfo (Const URL: string ;var DSInfo: TDownServerInfo);{远程文件的相对路径} virtual; abstract;//从URL获得信息 protected property OnError: TDownErrorEvent read FOnError write FOnError; property OnAFileEnd: TAFileDownEndEvent read FOnAFileEnd write FOnAFileEnd; property OnAllDownEnd: TNotifyEvent read FOnAllDownEnd write FOnAllDownEnd; property OnWork: TDownWorkEvent read FOnWork write FOnWork; property GaugeTotal :TGauge read FGaugeTotal write FGaugeTotal; property GaugeCur :TGauge read FGaugeCur write FGaugeCur; property lbURL :TLabel read FlbURL write FlbURL; property lbSpeed :TLabel read FlbSpeed write FlbSpeed; property lbFileCount :TLabel read FlbFileCount write FlbFileCount; property AverageSpeed :integer read FAverageSpeed; property ThreadCount :Integer read FThreadCount write SetThreadCount Default 5; property AutoSaveFile :Boolean read FAutoSaveFile write FAutoSaveFile Default True; public procedure downStart; virtual; procedure downStop; virtual; procedure downPause; virtual; function AddURL (URL: string): Integer; overload; function AddURL (URL: string; objFileInfo{由用户传入,所以必须由用户负责释放}: TObject): Integer; overload; procedure AddURL (URLs :TStringList); overload; procedure DoAFileEnd; virtual; procedure DoAllWorkEnd; virtual; procedure DoWork; virtual; //工作线程接收到数据 property LocalFileName : string read FLocalFileName; property DownTotalBytes :Int64 read FDownTotalBytes; property TotalBytes :Int64 read FTotalBytes write SetTotalBytes; property TotalFileCount :Integer read FTotalFileCount; property CurFileCount :Integer read FCurFIleCOunt; property FileType :TDownFIleType read FFileType write FFileType Default dfNorm; property StartTime:TDateTime read FStartTime; Constructor Create(AOwner: TComponent); override; // destructor Destroy; override; published end; { HTTP 下载类 先使用 Head 方法获得文件信息 } THTTPDownMan = class (TBaseDownMan) private FHTTPResponseInfo :TIdHTTPResponseInfo; //根据HEAD方法返回的HTTP头 FRawHeaders :TStringList; //服务器响应的原始报头 FOnGetHead :TGetHTTPHeadEvent; //HEAD方法成功 FNoThread :Boolean; //如果是动态生成的文件,则不支持多线程 function GetFileNameByRawHeaders (var FileName: string; Headers :TStringList): boolean; //重新设置保存文件名 function Have_Accept_Ranges (Headers: TStringList): boolean; //是否支持断点续传 procedure GetDownServerInfo (Const URL: string ;var DSInfo: TDownServerInfo); override;//从URL获得信息 procedure DoGetHead; //通过HEAD方法获得返回的文件及服务器信息 procedure getHead; override; procedure BeginThread; override; public Constructor Create(AOwner: TComponent); override; // destructor Destroy; override; published property OnError; property OnAFileEnd; property OnAllDownEnd; property OnWork; property OnGetHead: TGetHTTPHeadEvent read FOnGetHead write FOnGetHead; property HTTPResponseInfo :TIdHTTPResponseInfo read FHTTPResponseInfo; property GaugeTotal; property GaugeCur; property lbURL; property lbSpeed; property lbFileCount; property AverageSpeed; property ThreadCount; property AutoSaveFile; end; TFTPDownMan = class (TBaseDownMan) private FCurCanResume :Boolean; FOnGetHead:TGetFTPHeadEvent; procedure DoGetHead; procedure getHead; override; procedure BeginThread; override; procedure GetDownServerInfo (Const URL: string ;var DSInfo: TDownServerInfo); override;//从URL获得信息 public published property OnError; property OnAFileEnd; property OnAllDownEnd; property OnWork; property OnGetHead:TGetFTPHeadEvent read FOnGetHead write FOnGetHead; property GaugeTotal; property GaugeCur; property lbURL; property lbSpeed; property lbFileCount; property AverageSpeed; property ThreadCount; property AutoSaveFile; end; THTTPGetHeadThread = class (TThread) Private // FURL :string; FErrMSG :string; FRedirectURL :string; // FPort :SmallInt; FDownMan :THTTPDownMan; FHTTPResponseInfo :TIdHTTPResponseInfo; FServerInfo :TDownServerInfo; FRawHeaders :TStringList; procedure SetResponseInfo; procedure DoError; procedure OnRedirect(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod); procedure DoRedirect; protected procedure Execute; override; public constructor create (downMan: THTTPDownMan); overload; end; TFTPGetHeadThread = class (TThread) Private // FURL :string; FErrMsg :string; FPort :SmallInt; FDownMan :TFTPDownMan; FCanResume :Boolean; //是否支持断点续传 FServerInfo :TDownServerInfo; FSize :Int64; procedure SetResponseInfo; procedure DoError; protected procedure Execute; override; public constructor create (downMan: TFTPDownMan); overload; end; { HTTP下载线程类 } THTTPDownThread = class(TThread) //文件下载线程类 private FDownInfo :TDownThreadInfo; //本线程下载信息 FStream :TMemoryStream; FDownMan :THTTPDownMan; // FPort :SmallInt; FServerInfo :TDownServerInfo; FLastAWorkCount :Integer; FAWorkCount :integer; // FAWorkCOuntMax :Integer; FDownEventMode :TDownEventMode; procedure IdHTTPConnected(Sender: TObject); procedure IdHTTPDisConnected(Sender: TObject); procedure IdHTTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer); procedure IdHTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer); procedure IdHTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode); procedure UpdateState; procedure UpdateStream; protected procedure Execute; override; function DownLoadFile: boolean; //下载文件段 public constructor create(downMan: THTTPDownMan;const downInfo: TDownThreadInfo); overload; end; TFTPDownThread = class (TThread) private FErrMsg :string; FDownInfo :TDownThreadInfo; //本线程下载信息 FStream :TMemoryStream; FDownMan :TFTPDownMan; FServerInfo :TDownServerInfo; FCanResume :Boolean; FLastAWorkCount :Integer; FAWorkCount :integer; // FAWorkCOuntMax :Integer; FDownEventMode :TDownEventMode; procedure DoError; procedure IdFTPConnected(Sender: TObject); procedure IdFTPDisConnected(Sender: TObject); procedure IdFTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer); procedure IdFTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer); procedure IdFTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode); procedure UpdateState; procedure UpdateStream; protected procedure Execute; override; function DownLoadFile(): boolean; //下载文件段 public constructor create(downMan: TFTPDownMan;const downInfo: TDownThreadInfo); overload; end; procedure Register; implementation procedure Register; begin RegisterComponents ('RSR', [ THTTPDownMan, TFTPDownMan ] ); end; { TBaseDownMan } constructor TBaseDownMan.Create(AOwner: TComponent); begin Inherited Create (AOwner); FURLList := TStringList.Create; FStream := TMemoryStream.Create; FThreadCount := 5; FAutoSaveFile := True; end; destructor TBaseDownMan.Destroy; begin downStop; FStream.Clear; FStream.Free; FURLList.Free; inherited; end; function TBaseDownMan.GetFileNameByURL(URL: string): string; var i, nLen: integer; begin result := ''; nLen := Length (URL); for i := nLen downto 1 do begin if URL[i] = '/' then break; result := URL[i] + result; end; end; function TBaseDownMan.RemoteFileToURL(rname: string): string; var i, nLen: integer; s: string; begin result := ''; nLen := Length (rname); for i := 1 to nLen do begin if rname[i] in ['!'..'@','A'..'Z', 'a'..'z'] then result := result + rname[i] else result := result + '%' + Format ('%.2X', [Byte (rname[i])]); end; end; procedure TBaseDownMan.ThreadOnTerminate(Sender: TObject); var i: integer; begin for i := low(MyThread) to High (MyThread) do begin if Sender = MyThread[i] then begin MyThread[i] := nil; break; end; end; end; procedure TBaseDownMan.DoAFileEnd; begin if Assigned (FOnAFileEnd) then //如果存在 FCurURLObject ,则应该在用户代码中手工释放 FOnAFileEnd (self, FStream, FCurURLObject); if FURLList.Count > 1 then begin FURLList.Delete(0); downNext; //继续下载其它文件 end else DoAllWorkEnd; end; procedure TBaseDownMan.IdHTTPOnRedirect(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod); begin FLocalFileName := dest; end; function TBaseDownMan.AddURL(URL: string): Integer; begin if FURLList.IndexOf(URL) < 0 then FURLList.Add(URL); result := FURLList.Count; end; procedure TBaseDownMan.AddURL(URLs: TStringList); begin FURLList.AddStrings(URLs); end; procedure TBaseDownMan.DoAllWorkEnd; begin if Assigned (FOnAllDownEnd) then FOnAllDownEnd (self); FURLList.Clear; //清除下载任务列表 end; procedure TBaseDownMan.DoWork; Var S: String; TotalTime: TDateTime; H, M, Sec, MS: Word; DLTime: Double; //下载总秒数 begin //下载总字节数 FDownTotalBytes := FDownTotalBytes + FThreadAWorkCount - FLastThreadAWorkCount; FLastThreadAWorkCount := FThreadAWorkCount; FCurFileCount := FTotalFileCount - FURLList.Count + 1; TotalTime := Now - FStartTime; DecodeTime(TotalTime, H, M, Sec, MS); Sec := Sec + M * 60 + H * 3600; DLTime := Sec + MS / 1000; if DLTime > 0 then FAverageSpeed := ROund (FThreadAWorkCount / DLTime); if FAverageSpeed > 0 then Sec := Trunc ((FCurFileSize - FThreadAWorkCount) / FAverageSpeed ); if (FAverageSpeed > 0) and Assigned (FlbSpeed) then begin S := Format('%d小时%d分%d秒', [Sec div 3600, (Sec div 60) mod 60, Sec mod 60]); S := '剩余时间:' + S; S := FormatFloat('0.00 KB/秒', FAverageSpeed/ 1024) + '; ' + S; FlbSpeed.Caption := S; end; if Assigned (FlbURL) then FlbURL.Caption := FLocalFileName + ' 来自 ' + FDownServerInfo.FHost; if Assigned (FGaugeCur) then FGaugeCur.Progress := FThreadAWorkCount; if Assigned (FlbFileCount) then FlbFileCount.Caption := FOrmat ('%d/%d', [FTotalFileCOunt, FCurFileCount]); ResetGaugeTotal;//设置总下载 if Assigned (FOnWork) then FOnWork (self, FThreadAWorkCount, FCurURLObject); Application.ProcessMessages; end; procedure TBaseDownMan.SetThreadCount(value: integer); begin if value > MAX_THREAD then value := MAX_THREAD; if value <> FThreadCount then FThreadCount := value; end; procedure TBaseDownMan.downStart; var nLen: integer; downInfo: TDownThreadInfo; begin downStop; FDownTotalBytes := 0; //归零下载总字节 FTotalFileCount := FURLList.Count; FCurFileCount := 0; FCurFileSize := 0; if Assigned (FGaugeCur) then FGaugeCur.Progress := 0; if Assigned (FGaugeTotal) then FGaugeTotal.Progress := 0; if Assigned (lbURL) then lbURL.Caption := ''; if Assigned (lbSpeed) then lbSpeed.Caption := ''; downNext; end; procedure TBaseDownMan.downNext; begin if FURLList.Count < 1 then exit; FCurURL := FURLList[0]; GetDownServerInfo (FCurURL, FDownServerInfo); // FCurURLObject := FURLList.Objects[0]; FCurFileSize := 0; if Assigned (FGaugeCur) then FGaugeCur.Progress := 0; if Assigned (lbURL) then lbURL.Caption := ''; if Assigned (lbSpeed) then lbSpeed.Caption := ''; getHead; end; procedure TBaseDownMan.downData; var i, nLen: integer; downInfo: TDownThreadInfo; begin FStream.SetSize(FCurFileSize); //强制将当前文件进度条设置为0% if Assigned (FGaugeCur) then begin FGaugeCur.MaxValue := FCurFileSize; FGaugeCur.Progress := 0; end; nLen := FCurFileSize div FThreadTotalCount; FAThreadDefaultSize := nLen; FStartTime := NOW; //数据线程开始 BeginThread; // end; procedure TBaseDownMan.SetTotalBytes(Value: int64); begin if value <> FTotalBytes then begin FTotalBytes := value; ResetGaugeTotal; end; end; procedure TBaseDownMan.ResetGaugeTotal; var n :Integer; begin if FTotalBytes = 0 then exit; if not Assigned (FGaugeTotal) then exit; if FTotalBytes > $7FFFFFFF then begin n := ROund (FTotalBytes / $7FFFFFF); FGaugeTotal.Progress := Round (FDownTotalBytes / n); end else begin FGaugeTotal.MaxValue := FTotalBytes; FGaugeTotal.Progress := FDownTotalBytes; end; end; procedure TBaseDownMan.downStop; var i: integer; begin for i := low(MyThread) to High(MyThread) do begin if Assigned (MyThread[i]) then begin TerminateThread (MyThread[i].Handle, 0); //MyThread[i].Suspend; MyThread[i] := nil; end; end; end; procedure TBaseDownMan.downPause; var i: integer; begin for i := low(MyThread) to High(MyThread) do begin if Assigned (MyThread[i]) then begin if MyThread[i].Suspended then MyThread[i].Resume else MyThread[i].Suspend; //MyThread[i] := nil; end; end; end; function TBaseDownMan.AddURL(URL: string; objFileInfo: TObject): Integer; begin if FURLList.IndexOf(URL) < 0 then FURLList.AddObject(URL, objFileInfo); result := FURLList.Count; end; procedure TBaseDownMan.getHead; begin if Assigned (FlbURL) then FlbURL.Caption := FCurURL; FLocalFileName := GetFileNameByURL (FCurURL); end; procedure TBaseDownMan.DoError(ErrMsg: string); begin if Assigned (FOnError) then FOnError (self, ErrMsg); end; { THTTPDownThread } constructor THTTPDownThread.create(downMan: THTTPDownMan;const downInfo: TDownThreadInfo); begin inherited create(true); FreeOnTerminate := true; FLastAWorkCount := 0; FDownEventMode := deCreate; FDownInfo := downinfo; FDownMan := downMan; FServerInfo := FDownMan.FDownServerInfo; end; function THTTPDownThread.DownLoadFile: boolean; var FHttp: TIdHTTP; //stream :TMemoryStream; begin RESULT := False; FHttp := TIdHTTP.Create(nil); try //FHttp.OnConnected := IdHTTPConnected ; //FHttp.OnDisconnected := IdHTTPDisConnected; FHttp.OnWork := IdHTTPWork; FHttp.OnWorkBegin := IdHTTPWorkBegin; FHttp.OnWorkEnd := IdHTTPWorkEnd; FHttp.Host := FServerInfo.FHost; FHttp.Port := FServerInfo.FPort; Fstream := TMemoryStream.Create; try FHttp.Request.ContentRangeStart := FDownInfo.nStart; FHttp.Request.ContentRangeEnd := FDownInfo.nEnd; FHttp.Get(FServerInfo.FRemoteFile, FStream); Synchronize (UpdateStream ); //保存数据 result := True; finally begin Fstream.Clear; Fstream.Free; end; end; finally begin FreeAndNil (FHTTP); end; end; end; procedure THTTPDownThread.Execute; begin DownLoadFile ; end; procedure THTTPDownThread.IdHTTPConnected(Sender: TObject); begin FDownEventMode := deConnected; Synchronize ( UpdateState ); end; procedure THTTPDownThread.IdHTTPDisConnected(Sender: TObject); begin FDownEventMode := deDisConnected; Synchronize ( UpdateState ); end; procedure THTTPDownThread.IdHTTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer); begin FDownEventMode := deWork; FAWorkCount := AWOrkCount; Synchronize ( UpdateState ); end; procedure THTTPDownThread.IdHTTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer); begin FDownEventMode := deWorkBegin; FAWorkCountMax := AWorkCountMax; Synchronize ( UpdateState ); end; procedure THTTPDownThread.IdHTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode); begin FDownEventMode := deWorkEnd; FAWorkCount := FDownInfo.nByteCount; Synchronize ( UpdateState ); end; procedure THTTPDownThread.UpdateState; begin if FDownEventMode = deWork then begin FDownMan.FThreadAWorkCount := FDownMan.FThreadAWorkCount + FAWorkCount - FLastAWorkCount; FLastAWorkCount := FAWorkCount; FDownMan.DoWork; end; end; procedure THTTPDownThread.UpdateStream; begin if Assigned (FStream) then begin FdownMan.Fstream.Seek(FDownInfo.nStart, soBeginning); Fstream.Position := 0; FdownMan.Fstream.Write(FStream.Memory^, FStream.Size); Dec (Fdownman.FWorkingThreadCount); if FDownMan.FWorkingThreadCount = 0 then begin if FDownMan.AutoSaveFile then TMemoryStream (FdownMan.Fstream).SaveToFile(FDownMan.FLocalFileName); FDownEventMode := deDownEnd; FDownMan.DoAFileEnd; end; end; end; { THTTPGetHeadThread } constructor THTTPGetHeadThread.create(downMan: THTTPDownMan); begin inherited create(true); FreeOnTerminate := true; FDownMan := downMan; FServerInfo := FDownMan.FDownServerInfo; end; procedure THTTPGetHeadThread.DoError; begin FDownMan.DoError (FErrMsg); end; procedure THTTPGetHeadThread.DoRedirect; begin FDownMan.FCurURL := FRedirectURL; FDOwnMan.FLocalFileName := FRedirectURL; end; procedure THTTPGetHeadThread.Execute; var FHTTP: TIdHTTP; begin //inherited; FHTTP := TIdHTTP.Create(nil); try try FHTTP.ReadTimeout := 5000; FHTTP.HandleRedirects := True; FHTTP.OnRedirect := OnRedirect; FHTTP.Host := FServerInfo.FHost; FHTTP.Port := FServerInfo.FPort; FHTTP.Head(FServerInfo.FRemoteFile); except on E:Exception do begin FErrMsg := E.Message; Synchronize (DoError); end; end; FServerInfo.FHost := FHTTP.Host; FServerInfo.FPort := FHTTP.Port; With FHTTP.Response do begin FHTTPResponseInfo.FCacheControl := CacheControl; FHTTPResponseInfo.FConnection := Connection; FHTTPResponseInfo.FContentEncoding := ContentEncoding; FHTTPResponseInfo.FContentLanguage := ContentLanguage; FHTTPResponseInfo.FContentLength := ContentLength; FHTTPResponseInfo.FContentType := ContentType; FHTTPResponseInfo.FContentVersion := ContentVersion; FHTTPResponseInfo.FDate := Date; FHTTPResponseInfo.FExpires := Expires; FHTTPResponseInfo.FLastModified := LastModified; FHTTPResponseInfo.FPragma := Pragma; FHTTPResponseInfo.FHasContentLength := HasContentLength; FHTTPResponseInfo.FLocation := Location; FHTTPResponseInfo.FServer := Server; FHTTPResponseInfo.FResponseText := ResponseText; FHTTPResponseInfo.FResponseCode := ResponseCode; FHTTPResponseInfo.FResponseVersion := ResponseVersion; end; FRawHeaders := TStringList.Create; FRawHeaders.AddStrings(FHTTP.Response.RawHeaders); Synchronize (SetResponseInfo); FRawHeaders.Free; finally FreeAndNil (FHTTP) end; end; procedure THTTPGetHeadThread.OnRedirect(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: boolean; var VMethod: TIdHTTPMethod); begin FRedirectURL := dest; Synchronize (DoRedirect); end; procedure THTTPGetHeadThread.SetResponseInfo; begin FDownMan.FHTTPResponseInfo := FHTTPResponseInfo; FDownMan.FDownServerInfo := FServerInfo; FDownMan.FRawHeaders.Assign(FRawHeaders); FDownMan.DoGetHead; end; { THTTPDownMan } procedure THTTPDownMan.BeginThread; var i: integer; downinfo :TDownThreadInfo; begin if FNoThread then begin FThreadTotalCount := 1; FWorkingThreadCount := FThreadTotalCount; end; for i := 1 to FThreadTotalCount do begin downinfo.nStart := FAThreadDefaultSize * (i - 1); if i < FThreadTotalCount then downinfo.nEnd := FAThreadDefaultSize * i - 1 else downinfo.nEnd := FCurFileSize - 1; downinfo.URL := FCurURL; downinfo.nIndex := i; downinfo.nByteCount := downinfo.nEnd - downinfo.nStart + 1; MyThread[i-1] := THTTPDownThread.create( self, downinfo); MyThread[i-1].OnTerminate := ThreadOnTerminate; MyThread[i-1].Resume; end; end; constructor THTTPDownMan.Create(AOwner: TComponent); begin Inherited Create (AOwner); FRawHeaders := TStringList.Create; end; destructor THTTPDownMan.Destroy; begin FRawHeaders.Free; inherited; end; procedure THTTPDownMan.DoGetHead; var autoDownNext: boolean; begin autoDownNext := True; //默认发生错误时继续下载下一个 FCurFileSize := FHTTPResponseInfo.FContentLength; //已经从GetHeadThread获得文件大小 if Assigned (FGaugeCur) then begin if FCurFileSize >= 0 then FGaugeCur.MaxValue := FCurFileSize; FGaugeCur.Progress := 0; end; FThreadAWorkCount := 0; FLastThreadAWorkCount := 0; GetFileNameByRawHeaders (FLocalFileName, FRawHeaders); if (FCurFileSize > FIRST_THREAD_SIZE) and (Have_Accept_Ranges (FRawHeaders)) then FThreadTotalCount := FThreadCount else FThreadTotalCount := 1; //设置未下载完成线程数 FWorkingThreadCount := FThreadTotalCount; if Assigned (FOnGetHead) then FOnGetHead (self, FHTTPResponseInfo.FResponseText, FHTTPResponseInfo.FResponseCode, autoDownNext); if Pos ('OK', UpperCase (FHTTPResponseInfo.FResponseText)) > 0 then begin //获得文件信息后即开始下载 downData; end else begin if autoDownNext then DoAFileEnd; end; end; procedure THTTPDownMan.GetDownServerInfo(const URL: string; var DSInfo: TDownServerInfo); var s, shost, suser, spwd, sport: string; n, n2: integer; begin //http://IP地址:端口号/文件地址 DSInfo.FRemoteFile := ''; s := Trim (URL); if Pos ('HTTP://', UpperCase (s)) = 1 then delete (s, 1, 7); shost := s; n := pos ('/', shost); //第一个/前面为host if n > 0 then begin DSInfo.FRemoteFile := copy (shost, n, length (shost) - n + 1); delete (shost, n, length (shost) - n + 1); end; suser := ''; spwd := ''; sport := '80'; n := pos (':', shost); if n > 0 then begin sport := copy (shost, n + 1, length (shost) - n); delete (shost, n, length (shost) - n + 1); end; DSInfo.FHost := shost; DSInfo.FPort := StrToIntDef (sport, 80); DSInfo.FUserName := suser; DSInfo.FPassWord := spwd; end; function THTTPDownMan.GetFileNameByRawHeaders(var FileName: string; Headers: TStringList): boolean; var s : string; //Content-Disposition: attachment; filename="fname.ext" nPos, nLen, i:Integer; begin result := False; s := ''; for i := 0 to Headers.Count - 1 do begin if Pos (UpperCase ('Content-Disposition'), UpperCase (Headers.Strings[i])) > 0 then begin s := Headers.Strings[i]; break; end; end; if s = '' then exit; nPos := Pos ('=', s); if nPos > 1 then begin delete (s, 1, nPos); s := Trim (s); if s = '' then exit; if s[1] = '"' then begin nLen := length (s); if s[nLen] <> '"' then exit; delete (s, 1, 1); delete (s, nLen - 1, 1); FileName := s; end else FIleName := s; result := True; end; end; procedure THTTPDownMan.getHead; var aThread: THTTPGetHeadThread; begin Inherited; aThread := THTTPGetHeadThread.create(Self); aThread.Resume; end; function THTTPDownMan.Have_Accept_Ranges(Headers: TStringList): boolean; var s: string; i :Integer; begin result := False; for i := 0 to Headers.Count - 1 do begin s := UpperCase (Headers[i]); if Pos (UpperCase ('Accept-Ranges'), s) > 0 then begin result := True; break; end; end; end; { TFTPGetHeadThread } constructor TFTPGetHeadThread.create(downMan: TFTPDownMan); begin inherited create(true); FreeOnTerminate := true; FCanResume := False; FDownMan := downMan; FServerInfo := FDownMan.FDownServerInfo; end; procedure TFTPGetHeadThread.DoError; begin FDownMan.DoError(FErrMsg); end; procedure TFTPGetHeadThread.Execute; var FFTP: TIdFTP; begin //inherited; FFTP := TIdFTP.Create(nil); try try FFTP.ReadTimeout := 5000; FFTP.Host := FServerInfo.FHost; FFTP.Port := FServerInfo.FPort; FFTP.Username := FServerInfo.FUserName; FFTP.Password := FServerInfo.FPassWord; FSize := -1; FFTP.Connect(); FCanResume := FFTP.CanResume; FSize := FFTP.Size(FServerInfo.FRemoteFile); except on E:Exception do begin FErrMsg := E.Message; Synchronize (DoError); end; end; Synchronize (SetResponseInfo); finally FreeAndNil (FFTP) end; end; procedure TFTPGetHeadThread.SetResponseInfo; begin FDownMan.FCurFileSize := FSize; FDownMan.FCurCanResume := FCanResume; FDownMan.DoGetHead; end; { TFTPDownMan } procedure TFTPDownMan.BeginThread; var i: integer; downinfo :TDownThreadInfo; begin FWorkingThreadCount := FThreadTotalCount; for i := 1 to FThreadTotalCount do begin downinfo.nStart := FAThreadDefaultSize * (i - 1); if i < FThreadTotalCount then downinfo.nEnd := FAThreadDefaultSize * i - 1 else downinfo.nEnd := FCurFileSize - 1; downinfo.URL := FCurURL; downinfo.nIndex := i; downinfo.nByteCount := downinfo.nEnd - downinfo.nStart + 1; MyThread[i-1] := TFTPDownThread.create( self, downinfo); MyThread[i-1].OnTerminate := ThreadOnTerminate; MyThread[i-1].Resume; end; end; procedure TFTPDownMan.DoGetHead; var autoDownNext: boolean; begin autoDownNext := True; //默认发生错误时继续下载下一个 //FCurFileSize 已经从GetHeadThread获得文件大小 if Assigned (FGaugeCur) then begin if FCurFileSize >= 0 then FGaugeCur.MaxValue := FCurFileSize; FGaugeCur.Progress := 0; end; FThreadAWorkCount := 0; FLastThreadAWorkCount := 0; if (FCurFileSize > FIRST_THREAD_SIZE) and FCurCanResume then FThreadTotalCount := FThreadCount else FThreadTotalCount := 1; if Assigned (FOnGetHead) then FOnGetHead (self, FCurCanResume, FCurFileSize, autoDownNext); if FCurFileSize <> -1 then //获得文件信息后即开始下载 downData else begin if autoDownNext then DoAFileEnd; end; end; procedure TFTPDownMan.GetDownServerInfo (Const URL: string ;var DSInfo: TDownServerInfo); var s, shost, suser, spwd, sport: string; n, n2: integer; begin //ftp://账号:密码@IP地址:端口号 DSInfo.FRemoteFile := '/'; s := Trim (URL); if Pos ('FTP://', UpperCase (s)) = 1 then delete (s, 1, 6); shost := s; n := pos ('/', shost); //第一个/前面为host if n > 0 then begin DSInfo.FRemoteFile := copy (shost, n , length (shost) - n + 1); delete (shost, n, length (shost) - n + 1); end; suser := 'Anonymous'; spwd := 'root@renshou.net'; n := pos ('@', shost); if n > 0 then begin n2 := pos (':', shost); if (n2 > 0) and (n2 < n) then begin suser := copy (shost, 1, n2 - 1); spwd := copy (shost, n2 + 1, n - n2 - 1); end; delete (shost, 1, n); end; sport := '21'; n := pos (':', shost); if n > 0 then begin sport := copy (shost, n + 1, length (shost) - n); delete (shost, n, length (shost) - n + 1); end; DSInfo.FHost := shost; DSInfo.FPort := StrToIntDef (sport, 21); DSInfo.FUserName := suser; DSInfo.FPassWord := spwd; end; procedure TFTPDownMan.getHead; var aThread: TFTPGetHeadThread; begin Inherited; aThread := TFTPGetHeadThread.Create(Self); aThread.Resume; end; { TFTPDownThread } constructor TFTPDownThread.create(downMan: TFTPDownMan; const downInfo: TDownThreadInfo); begin inherited create(true); FreeOnTerminate := true; FLastAWorkCount := 0; FDownEventMode := deCreate; FDownInfo := downinfo; FDownMan := downMan; FServerInfo := FDownMan.FDownServerInfo; FCanResume := FDownMan.FCurCanResume; end; procedure TFTPDownThread.DoError; begin FDownMan.DoError(FErrMsg); end; function TFTPDownThread.DownLoadFile(): boolean; var FTP: TIdFTP; begin result := False; FTP := TIdFTP.Create(nil); try Fstream := TMemoryStream.Create; FTP.ReadTimeout := 5000; FTP.Host := FServerInfo.FHost; FTP.Port := FServerInfo.FPort; FTP.Username := FServerInfo.FUserName; FTP.Password := FServerInfo.FPassWord; FTP.OnConnected := IdFTPConnected; FTP.OnDisconnected := IdFTPDisConnected; FTP.OnWork := IdFTPWOrk; FTP.OnWorkBegin := IdFTPWorkBegin; FTP.OnWorkEnd := IdFTPWorkEnd; try FTP.Connect(); //如果使用 Passive 模式,则工作正常 FTP.Passive := True; if FCanResume then begin //设置stream的大小为目标文件总大小 FStream.SetSize(FDownMan.FCurFileSize); //为符合IdFTP的续传函数参数要求,设置Stream的偏移 FStream.Position := FDownInfo.nStart; try //使用断点续传方式 FTP.Get(FServerInfo.FRemoteFile, FStream, True); //读到指定位置时而触发的异常将忽略 except on E:FTPWorkEndException do end; end else FTP.Get(FServerInfo.FRemoteFile, FStream); Synchronize (UpdateStream ); //保存数据 result := True; except on E:Exception do begin FErrMsg := E.Message; Synchronize (DoError); FStream.Clear; FStream.Free; end; end; finally FreeAndNil (FTP) end; end; procedure TFTPDownThread.Execute; begin DownLoadFile (); end; procedure TFTPDownThread.IdFTPConnected(Sender: TObject); begin FDownEventMode := deConnected; Synchronize ( UpdateState ); end; procedure TFTPDownThread.IdFTPDisConnected(Sender: TObject); begin FDownEventMode := deDisConnected; Synchronize ( UpdateState ); end; procedure TFTPDownThread.IdFTPWork(Sender: TObject; AWorkMode: TWorkMode; const AWorkCount: Integer); begin FDownEventMode := deWork; FAWorkCount := AWOrkCount; if FAWorkCount >= FDownInfo.nByteCount then begin //下面2句将由 WorkEnd 时执行 //FAWorkCount := FDownInfo.nByteCount; //Synchronize ( UpdateState ); raise FTPWorkEndException.Create ('a ftp thread down end.') ; exit; end; Synchronize ( UpdateState ); end; procedure TFTPDownThread.IdFTPWorkBegin(Sender: TObject; AWorkMode: TWorkMode; const AWorkCountMax: Integer); begin FDownEventMode := deWorkBegin; FAWorkCountMax := AWorkCountMax; Synchronize ( UpdateState ); end; procedure TFTPDownThread.IdFTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode); begin FDownEventMode := deWorkEnd; FAWorkCount := FDownInfo.nByteCount; Synchronize ( UpdateState ); end; procedure TFTPDownThread.UpdateState; begin if FDownEventMode in [deWork, deWorkEnd] then begin FDownMan.FThreadAWorkCount := FDownMan.FThreadAWorkCount + FAWorkCount - FLastAWorkCount; FLastAWorkCount := FAWorkCount; FDownMan.DoWork; end; end; procedure TFTPDownThread.UpdateStream; begin if Assigned (FStream) then begin FdownMan.Fstream.Seek(FDownInfo.nStart, soBeginning); //Fstream.Position := 0; FdownMan.Fstream.Write(PLongWord (longword (FStream.Memory) + FDownInfo.nStart)^, FDownInfo.nByteCount); //递减未完成下载的线程计数器 Dec (Fdownman.FWorkingThreadCount); if FDownMan.FWorkingThreadCount = 0 then begin if FDownMan.AutoSaveFile then TMemoryStream (FdownMan.Fstream).SaveToFile(FDownMan.FLocalFileName); FDownEventMode := deDownEnd; FDownMan.DoAFileEnd; end; end; end; end.
unit uMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, Buttons, Spin; type TMain = class(TForm) GroupBox1: TGroupBox; lbox: TListBox; Panel1: TPanel; StatusBar1: TStatusBar; GroupBox2: TGroupBox; btnstartMonitor: TBitBtn; btnStopMonitor: TBitBtn; GroupBox3: TGroupBox; GroupBox4: TGroupBox; Label3: TLabel; Label4: TLabel; btnCreate: TBitBtn; edtName: TEdit; Label5: TLabel; Label6: TLabel; edtRetry: TSpinEdit; GroupBox5: TGroupBox; Label8: TLabel; edtSource: TEdit; edtUse: TEdit; Label9: TLabel; lvInfo: TListView; Splitter1: TSplitter; edtWaitTime: TSpinEdit; Label1: TLabel; Edit1: TEdit; Label2: TLabel; Label7: TLabel; edtTimes: TSpinEdit; Label10: TLabel; CheckBox1: TCheckBox; Label11: TLabel; procedure btnstartMonitorClick(Sender: TObject); procedure btnStopMonitorClick(Sender: TObject); procedure btnCreateClick(Sender: TObject); private { Private declarations } public isMonitor: boolean; //is monitor the status ,is false didn't display the statu information procedure AddInfoTolvinfo(index: integer; s: string); function GetInfoFromlvInfo(index: integer): string; procedure AddInfo(s: string); { Public declarations } end; TDemoProcedure = class(TThread) public ListIndex: integer; strName: string; WaitTime, RetryTime, Times: Integer; isWantSource: boolean; //申请资源标志 isDonotWantSource: boolean; //释放资源标志 constructor Create(); private { Private declarations } protected procedure Execute; override; procedure WantSource; procedure Wantsourceok; procedure donWantSource; procedure donWantsourceOK; procedure EndThisRun; procedure ShowError; procedure ShowErrorEx; //释放资源被锁定,强制释放以防死锁 end; const sRun = '运行状态'; sWait = '申请资源'; sWaitOk = '申请资源成功,进行使用期'; sExit = '申请释放资源'; sExitOk = '释放资源ok'; var Main: TMain; implementation {$R *.dfm} procedure TMain.btnstartMonitorClick(Sender: TObject); begin isMonitor := true; btnStartMonitor.Enabled := false; btnStopMonitor.Enabled := true; end; procedure TMain.btnStopMonitorClick(Sender: TObject); begin isMonitor := false; btnStartMonitor.Enabled := true; btnStopMonitor.Enabled := false; end; procedure TMain.btnCreateClick(Sender: TObject); var strName: string; waitTime, Retry, Times: integer; p: TListitem; isMore: boolean; //判断该进程是否已存在 i: integer; DemoProcedure: TDemoProcedure; begin strName := Trim(edtName.Text); waitTime := edtWaitTime.Value; Retry := edtRetry.Value; Times := edtTimes.Value; if Trim(edtName.Text) = '' then begin ShowMessage('模拟进程的名称必须输入,随便输'); edtName.SetFocus; exit; end; if ((WaitTime <= 0) or (Retry <= 0)) then begin ShowMessage('时间是不能设为小于等于0的数的,随便输'); exit; end; if (Times <= 0) then begin ShowMessage('重试次数不能少于0'); edtTimes.SetFocus; exit; end; isMore := false; for i := 0 to lvinfo.Items.Count - 1 do begin if lvinfo.Items[i].Caption = strName then begin isMore := true; break; end; end; if isMore then begin ShowMessage('模拟进程的名称要唯一哦'); edtName.SetFocus; exit; end; edtName.SetFocus; with lvinfo do //如果成功,写入进程信息列表中 begin p := Items.Add; p.Caption := strname; p.SubItems.Add(intTostr(waitTime)); p.SubItems.Add(intTostr(Retry)); p.SubItems.Add(sRun); end; i := lvInfo.Items.Count - 1; //创建模拟进程 DemoProcedure := TDemoProcedure.Create(); DemoProcedure.strName := strName; DemoProcedure.Times := Times; DemoProcedure.ListIndex := i; DemoProcedure.WaitTime := waitTime * 1000; DemoProcedure.RetryTime := Retry * 1000; DemoProcedure.Resume; end; procedure TMain.AddInfotoLvinfo(index: integer; s: string); begin if lvinfo.Items.Count - 1 < index then exit; if index < 0 then exit; lvinfo.Items[index].SubItems[2] := s; ; end; function TMain.GetInfoFromlvInfo(index: integer): string; begin result := lvinfo.Items[index].SubItems[2]; end; procedure TMain.AddInfo(s: string); begin if not isMonitor then exit; lbox.Items.Add(s); // Application.ProcessMessages; end; { TDemoProcedure } constructor TDemoProcedure.Create; begin FreeOnTerminate := True; inherited Create(True); end; procedure TDemoProcedure.donWantSource; begin with Main do begin isDonotWantSource := not CheckBox1.checked; if isDonotWantSource then begin //释放资源 edtuse.Text := '否'; Edit1.Text := '无'; edtSource.Text := intTostr(strToint(edtSource.Text) + 1); AddinfoTolvinfo(ListIndex, '释放资源成功'); Addinfo(format('%s 试图释放资源---资源尚未锁定,释放成功', [strname])); end else begin AddinfoTolvinfo(ListIndex, '释放资源失败'); Addinfo(format('%s 试图释放资源---资源被用户锁定,释放失败,等待%d毫秒再试', [strname, retrytime])); end; end; end; procedure TDemoProcedure.donWantsourceOK; begin with Main do begin AddinfoTolvinfo(ListIndex, '释放资源'); Addinfo(format('%s 成功释放资源---释放资源后马上会自动终止本进程', [strname])); end; end; procedure TDemoProcedure.EndThisRun; begin with Main do begin addinfoTolvinfo(listindex, '成功结束'); addinfo(format('%s 成功结束', [strName])); end; end; procedure TDemoProcedure.Execute; var i: integer; begin i := 0; repeat synchronize(WantSource); if isWantSource then break else sleep(RetryTime); Inc(i); until (i >= Times); if i >= Times then begin //未申请到资源退出 synchronize(self.ShowError); self.Terminate; end; //进行运行态 synchronize(wantsourceOK); //运行 sleep(waittime); //模拟 //运行完毕申请释放资源 i := 0; repeat synchronize(donWantSource); if isDonotWantSource then break else sleep(RetryTime); Inc(i); until (i >= Times); if i >= Times then begin //未申请到资源退出 synchronize(self.ShowErrorEx); self.Terminate; end; synchronize(donWantSourceOk); synchronize(EndThisRun); // self.Terminate; end; procedure TDemoProcedure.ShowError; begin with Main do begin addinfoTolvinfo(ListIndex, '超时错误并停止'); addinfo(format('%s 经过%d秒重试,仍然没有成功,超时并终止线程', [strName, RetryTime])); end; end; procedure TDemoProcedure.ShowErrorEx; begin with Main do begin addinfoTolvinfo(ListIndex, '超时错误并停止'); addinfo(format('%s 经过%d秒重试,用户仍然锁定不准释放资源,为了防止死锁,强制释放并终止线程', [strName, RetryTime])); edtuse.Text := '否'; Edit1.Text := '无'; edtSource.Text := intTostr(strToint(edtSource.Text) + 1); end; end; procedure TDemoProcedure.WantSource; begin with Main do begin if edtuse.Text = '是' then self.isWantSource := false else self.isWantSource := True; if isWantSource then begin //申请资源 edtuse.Text := '是'; Edit1.Text := strname; edtSource.Text := intTostr(strToint(edtSource.Text) - 1); AddinfoTolvinfo(ListIndex, '申请资源成功'); Addinfo(format('%s 试图申请资源---资源尚未使用,申请成功', [strname])); end else begin AddinfoTolvinfo(ListIndex, '申请资源失败'); Addinfo(format('%s 试图申请资源---资源已在使用中,申请失败,等待%d毫秒再试', [strname, retrytime])); end; end; end; procedure TDemoProcedure.Wantsourceok; begin with Main do begin AddinfoTolvinfo(ListIndex, '使用资源状态'); Addinfo(format('%s 成功申请资源---正在使用过程中,将运行%d毫秒', [strname, waittime])); end; end; end.