ThreadedTimer 如题 线程定时器

 
//////////////////////////////////////////////////// 
//                                                // 
//   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. 
 
View Code
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. 
 
View Code
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. 
tcp
(**************************** 
 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. 
base64
 
//第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. 
indy 下载 http ftp
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. 
 
实现UP、DOWN原语 产生3个进程
原文地址:https://www.cnblogs.com/marklove/p/12340681.html