經驗1

 

SQL的單個表的大小限制最大可以是多大?
第一個表說明對於所有  Microsoft®  SQL  Server™  2000  版本都相同的最大容量。第二個和第三個表說明因  SQL  Server  2000  的版本和操作系統的不同而異的容量。  
 
下表說明在  Microsoft  SQL  Server  數據庫中定義的,或在  Transact-SQL  語句中引用的各種對象的最大值(數量或大小)。下表不包含  Microsoft®  SQL  Server  2000™  Windows®  CE  版。  
 
   最大值(數量或大小)    
對象        SQL  Server  7.0            SQL  Server  2000    
批處理大小  65,536  *  網絡數據包大小1  65,536  *  網絡數據包大小1    
每個短字符串列的字節數  8,000  8,000    
每個  text、ntext、或  image  列的字節數  2  GB-2  2  GB-2    
每個  GROUP  BY、ORDER  BY的字節數  8,060        
每個索引中的字節數  900  9002    
每個外鍵的字節數  900  900    
每個主鍵的字節數  900  900    
每行字節數  8,060  8,060    
存儲過程源文本中的字節數  批處理大小之較小者或者  250  MB  批處理大小之較小者或者  250  MB    
每個數據表的聚集索引數  1  1    
GROUP  BY、ORDER  BY  中的列數  只受字節數限制      
GROUP  BY  WITH  CUBE  或  WITH  ROLLUP  語句中的列數或表達式數目  10      
每個索引的列數  16  16    
每個外鍵的列數  16  16    
每個主鍵的列數  16  16    
每個基礎數據表的列數  1,024  1,024    
每個SELECT  語句的列數  4,096  4,096  
每個INSERT  語句的列數  1,024  1,024    
每個客戶端的連接個數  已配置連接的最大值  已配置連接的最大值    
數據庫大小  1,048,516  TB3  1,048,516  TB3    
每個  SQL  Server  實例的數據庫個數  32,767  32,767    
每個數據庫的文件組個數  256  256    
每個數據庫的文件個數  32,767  32,767    
文件大小(數據)  32  TB  32  TB    
文件大小(日誌)  4  TB  32  TB    
每個數據表的外鍵表引用  253  253    
標識符長度(以字符計)  128  128    
每臺計算機的實例數  暫缺  16    
包含  SQL  語句的字符串長度(批處理大小)  65,536  *  網絡數據包大小1  65,536  *  網絡數據包大小1    
每個連接的鎖數  每個服務器的最大鎖數  每個服務器的最大鎖數    
每個  SQL  Server  實例的鎖數  2,147,483,647(靜態)  
SQL  Server  40%  的內存(動態)  2,147,483,647(靜態)  
SQL  Server  40%  的內存(動態)    
嵌套存儲過程層數  32  32    
嵌套子查詢  32  32    
嵌套觸發器層數  32  32    
每個數據表的非聚集索引個數  249  249    
SQL  Server  實例中同時打開的對象個數4  2,147,483,647(或可用內存)  2,147,483,647(或可用內存)    
每個數據庫中的對象個數  2,147,483,6474  2,147,483,6474    
每個存儲過程的參數個數  1,024  1,024    
每個數據表的  REFERENCE  個數  253  253    
每個數據表的行數  受可用存儲資源限制  受可用存儲資源限制    
每個數據庫的數據表個數  受數據庫中的對象個數限制4  受數據庫中的對象個數限制4    
每個  SELECT  語句的數據表個數  256  256    
每個數據表的觸發器個數  受數據庫中的對象個數限制4  受數據庫中的對象個數限制4    
每個數據表的  UNIQUE  索引個數或約束個數  249個非聚集索引和  1  個聚集索引  249個非聚集索引和  1  個聚集索引    
 
 
1  網絡數據包大小是表格格式數據方案  (TDS)  數據包的大小,該數據包用於應用程序和關係數據庫引擎之間的通訊。默認的數據包大小爲  4  KB,由  network  packet  size  配置選項控制。  
2  在  SQL  Server  2000  中,任何鍵的最大字節數不能超過  900。可以使用可變長度的列來定義鍵,只要在這種列中不插入數據超過  900  字節的行,其最大大小就可以在  900  以上。有關更多信息,請參見索引鍵的最大值。  
3  當使用  SQL  Server  2000  Desktop  Engine  或  Microsoft  數據引擎  (MSDE)  1.0  時,數據庫的大小不能超過  2  GB。  
4數據庫對象包括所有的表、視圖、存儲過程、擴展存儲過程、觸發器、規則、默認值及約束。一個數據庫中所有對象的總數不得超過  2,147,483,647。    
 
 
說明    SQL  Server  2000  中文版不支持英文版的  NT  4.0  企業版。  
 
SQL  Server  2000  版本支持的最大處理器數  
下表列出各  SQL  Server  2000  版本中的數據庫引擎在對稱多處理  (SMP)  計算機上能夠支持的處理器數。  
 
 
 
 
操作系統  企業版  標準版  個人版  開發版  Desktop  Engine  SQL  Server  CE  企業評估版    
Microsoft  Windows®  2000  DataCenter  32  4  2  32  2  暫缺  32    
Windows  2000  Advanced  Server  8  4  2  8  2  暫缺  8    
Windows  2000  Server  4  4  2  4  2  暫缺  4    
Windows  2000  Professional  暫缺  暫缺  2  2  2  暫缺  2    
Microsoft  Windows  NT®  4.0  Server  企業版  8  8  2  8  2  暫缺  8    
Windows  NT  4.0  Server  4  4  2  4  2  暫缺  4    
Windows  NT  4.0  Workstation  暫缺  暫缺  2  2  2  暫缺  2    
Microsoft  Windows  98  暫缺  暫缺  1  使用  Desktop  Engine  1  暫缺  暫缺    
Microsoft  Windows  CE  暫缺  暫缺  暫缺  暫缺  暫缺  1  暫缺    
 
 
SQL  Server  2000  版本支持的最大物理內存量  
下表列出各  SQL  Server  2000  版中的數據引擎能夠支持的最大物理內存量或  RAM。  
 
操作系統  企業版  標準版  個人版  開發版  Desktop  Engine  SQL  Server  CE  企業評估版    
Windows  2000  DataCenter  64  GB  2  GB  2  GB  64  GB  2  GB  暫缺  64  GB    
Windows  2000  Advanced  Server  8  GB  2  GB  2  GB  8  GB  2  GB  暫缺  8  GB    
Windows  2000  Server  4  GB  2  GB  2  GB  4  GB  2  GB  暫缺  4  GB    
Windows  2000  Professional  暫缺  暫缺  2  GB  2  GB  2  GB  暫缺  2  GB    
Windows  NT  4.0  Server  企業版  3  GB  2  GB  2  GB  3  GB  2  GB  暫缺  3  GB    
Windows  NT  4.0  Server  2  GB  2  GB  2  GB  2  GB  2  GB  暫缺  2  GB    
Windows  NT  4.0  Workstation  暫缺  暫缺  2  GB  2  GB  2  GB  暫缺  2  GB  
---------------------------------------------------------------  
 
行數限制=32  TB  *32,767/每行字節數  
如果你的硬盤容量達不到32  TB  *32,767,就是硬盤容量/每行字節數    


2006-7-19 1:48:30   
 2006-7-19 1:49:14    String的處理

去掉字符串中的空格
S := StringReplace('  aaa  a  ',' ','',[rfReplaceAll]);
Trim();
TrimLeft();
TrimRight();
查找一個字符或者字符串在指定字符中第一次出現的位置
pos('.','test.txt');
複製一個字符串第一位到第10位
copy(str1,1,10);  

 
 2006-7-19 1:49:57    動態數組

To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,

type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;

declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For

example, if I and J are integer-valued variables,

SetLength(Msgs,I,J);

allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.

You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it

parameters for the first n dimensions of the array. For example,

var Ints: array of array of Integer;
SetLength(Ints,10);

allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different

lengths); for example

SetLength(Ints[2], 5);

makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can

assign values to the third column--for example, Ints[2,4] := 6.

The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular

matrix of strings.

var
  A : array of array of string;
  I, J : Integer;
begin
  SetLength(A, 10);
  for I := Low(A) to High(A) do
  begin
    SetLength(A[I], I);
    for J := Low(A[I]) to High(A[I]) do
      A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
  end;
end;

/////////////////////////////////////////////////////////////////////////////////
多維數組


要聲明多維動態數組,需要迭代使用array of ... 結構。例如,

type TMessageGrid = array of array of string;

var Msgs: TMessageGrid;

聲明瞭一個二維動態數組。要初始化該數組,需要調用標準過程SetLength並使用兩個整數參數。例如,如果 I 和 J 是整數值變量,那麼

SetLength(Msgs,I,J);

分配了一個 I x J 的二維數組,Msgs[0, 0]表示數組中的一個元素。

也可以創建非矩陣(上面調用SetLength之後的Msgs就是一個矩陣)的動態數組。首先,調用SetLength,將數組的第一個維數n作爲參數。例如,

var Ints: array of array of Integer;

SetLength(Ints,10);

這裏爲二維數組Ints分配了10行但沒有任何行。然後,可以一次對一列分配行(可以指定不同的長度);例如

SetLength(Ints[2], 5);

這裏爲Ints第3列指定了5個整數的長度。執行該語句後,可以對第3列賦值,如Ints[2, 4] := 6。(儘管此時其他的列可能還沒有被分配。)

下面的例子用動態數組(以及SysUtils單元中聲明的IntToStr函數)創建了一個三角矩陣,數組的基類型是串。

var

A : array of array of string;

I, J : Integer;

begin

SetLength(A, 10);

for I := Low(A) to High(A) do

begin

SetLength(A[I], I);

for J := Low(A[I]) to High(A[I]) do

A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';

end;

end;  

 
 2006-7-19 1:50:33    ado多線程

本人最近正在進行呼叫中心的座席端和服務器軟件開發,座席端登錄部分是進行提取主機信息,然後使用SOCKET提交給遠程服務器,服務器再在後臺數據庫中進行查找信息,進行對比,看是否允許座席端主機登錄,因爲我的電腦中無法安裝SQLSERVER,所以 ,後臺數據庫暫時使用access小型數據庫進行代替,到後期可以改爲SQLSERVER數據庫,,我在後臺數據庫中使用了兩個表,使用WORKMARK字段將其相關聯,如果在第一個表中查找到信息以後馬上會進入第二個表中進行查找,如果第一個表中的信息符合,就返回個客戶第二個表中的信息,因爲座席端主機有200多臺,爲了防止幾臺主機同時進行驗證信息,引起衝突,我在服務器端建立多線程,利用線程進行後臺的查詢,以及查找結果的回傳,編寫成功後進行測試,發現當一個主機連接後可以測試成功,但是,當第二個或者以後的線程產生時,數據集在第一個表中可以查到正確的信息,但是進入第二個表中時,會發現按照正確的查找條件進行查找時,查到的信息都爲NIL,而且經過跟蹤,發現,其實ADO已經找到了正確的信息,而且已經發送成功了,但是卻無法接收到,當時我在論壇中發表了一個帖子尋求幫助,原貼內容:http://expert.csdn.net/Expert/topic/1420/1420051.xml?temp=.3060114

有些朋友說可能ACCESS數據庫不提供多線程訪問,但是我聽說很多的論壇中好像都使用了ACCESS進行後臺線程的查找的。翻看MSDN中關於COM的說明:發現我的線程中竟然缺少最重要的兩個函數過程

CoInitialize( nil );凡是訪問com對象都應該使用。線程的關閉時應該使用CoUnInitialize;否則ADO肯定出錯,我相信肯定有不少的朋友經歷過這種問題的:

我的線程代碼如下:

unit Unitquerythread;

interface

uses
  windows,SysUtils,Classes, Dialogs,ADODB,db, NMMSG, ActiveX{必須要有};

type
  QueryThread = class(TThread)
  private
   FComputerInfor,FIPaddressinfo: string;  //傳遞的信息
   FAdoQuery,FAdoQUserInfor:TadoQuery;  //動態生成的表一,表2
   
   Fadoconnection:Tadoconnection;  //動態生成的連接
   Fnmmsg,FNMretureMSG:TNMMSG;//用來發送返回信息的組件
filestream:tfilestream;
    procedure ExtractInfor(TransInfo:string{自定義的從該提交信息中分離信息的過程});
    procedure ShellexeQuery;
  Destructor Destroy;

  protected
    procedure Execute; override;
  public
constructor  create(ComputerInfor:string;{傳輸來的計算機信息}IPaddressinfo:string{傳輸來的IP地址信息};nmmsg,NMretureMSG:TNMMSG);
  end;
var
  ExtractDomainUser:string;  //提取出來的域用戶名
  ExtractComputername:string;//提取出來的計算機名稱
  ExtractDomainname:string;//提取出來的域名
  strlist:Tstringlist;
  IPlist:Tstringlist;//保存查找到的本工作組的ip地址信息
  const defeat='defeat';  //驗證失敗,必須註銷客戶機,在數據庫中重新進行寫入


implementation


  uses Unitsendthread;


constructor QueryThread.create(ComputerInfor, IPaddressinfo: string;nmmsg,NMretureMSG:TNMMSG);
begin
  CoInitialize( nil );//使用com對象必須要初始化
  inherited create(false);
  FreeOnTerminate:=true;
  FComputerInfor:=ComputerInfor;
  FIPaddressinfo:=IPaddressinfo;
  IPlist:=Tstringlist.create;//創造ip列表
  FAdoQuery:=TAdoQuery.Create(nil);     //動態生成表一
  FAdoQUserInfor:=TadoQuery.Create(nil);//動態生成表2
  Fadoconnection:=Tadoconnection.Create(nil);//動態生成的連接
  Fadoconnection.LoginPrompt :=false;
  Fadoconnection.KeepConnection :=true;
  Fadoquery.Connection:=Fadoconnection;
  FAdoQUserInfor.Connection :=Fadoconnection;
  Fadoconnection.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=PersonInformation.mdb;Mode=Read;Persist Security Info=False';


  Fnmmsg:=nmmsg;
  FNMretureMSG:=NMretureMSG;
  strlist:=Tstringlist.Create;
 
end;

destructor QueryThread.Destroy;
begin
  FAdoQuery.FREE;
  FAdoQUserInfor.FREE;
  Fadoconnection.Free;
  strlist.Free;
  iplist.free;
  CoUnInitialize;//必須使用
inherited destroy;
end;

procedure QueryThread.Execute;
begin

try
begin
  extractinfor(FComputerInfor);  //進行信息提取
Synchronize(ShellexeQuery);//
end;
except

self.Terminate;

end;

end;

procedure QueryThread.ExtractInfor(TransInfo: string);//改過程進行提取用#進行分割//的串裏的各個字符串

integer;
j:array [1..2]of integer;//用來保存分割符的位置
H,L,M,N:integer;//進行組合字符串時的循環參數

begin

全局變量,首先清空
      ExtractDomainUser:='';
      ExtractDomainname:='';
      ExtractComputername:='';
      H:=1;

//=================================
try
    begin
         for i := 1 to length(TransInfo) do

        if TransInfo[i]='#' then //找到了
           begin
            j[H]:=i;
           
            inc(H);
            continue;  //跳出循環
           end;

    BEGIN
     for L:=1 to j[1]-1 do
          ExtractDomainUser:=ExtractDomainUser+TransInfo[L]; //提取的登陸域用戶名
          ://showmessage(extractdomainuser);
     for M:=j[1]+1 to j[2]-1 do
          ExtractDomainname:=ExtractDomainname+TransInfo[M];//提取的域控制器名
        //showmessage(extractdomainname);
     for N:=j[2]+1 to length(trim(TransInfo)) do
          ExtractComputername:=ExtractComputername+Transinfo[N];//提取的計算機名
         //showmessage(extractcomputername);
    END;
   end;//進行異常處理
  Except
   // messagebox(0,'信息提取出現錯誤!','提示信息',mb_iconinformation);
  end;
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure QueryThread.ShellexeQuery;
var
    mark:string;   //保存查找到的工號信息
    SkillInfor:string;
    RetureInformation:string; //返回個客戶端的信息
    WorkGroupUserInfor:Tstringlist;
    filename:string;

begin
try
   begin
       
       FAdoQuery.Close;
       Fadoquery.SQL.Clear;
       FAdoQuery.SQL.Add ('SELECT * From LOGON WHERE DomainUser='+'"'+ExtractDomainUser+'"'+'and DomainName='+'"'+ExtractDomainname+'"'+'and ComputerName='+'"'+ExtractComputername+'"'+'and IPaddress='+'"'+FIPaddressinfo+'"');
       FAdoQuery.Prepared :=true;
       FAdoQuery.active:=true;
file://=====================================================================
   if (FAdoQuery.fieldbyname('WorkMark').asstring ='') or (FAdoQuery.fieldbyname('Privilege').asstring='')  then //沒有查到工號信息
         begin

             Fnmmsg.Disconnect;
             Fnmmsg.Host:=FIPaddressinfo;
             Fnmmsg.Port :=6711;
             Fnmmsg.FromName :='a';
             Fnmmsg.PostIt(defeat); //沒有找到權限和工號則發送錯誤消息
             FAdoQuery.active:=false;
         end

  else      //查詢到了工號,和權限信息 ,從階連表中得到所有信息
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     begin

              strlist.Clear;
              strlist.Add(FAdoQuery.fieldbyname('WorkMark').asstring);//把工號寫入
              mark:=FAdoQuery.fieldbyname('WorkMark').asstring; //將工號寫入mark臨時變量

              FAdoQuery.close; //關閉第一個數據集
   //===========進入第二個表進行查找===============================================
    with FAdoQUserInfor do
       begin
             
              if active =true then close;   //關閉數據集
              sql.Clear;

              sql.Add('Select * From WORKER Where WorkMark='+'"'+mark+'"'); //該部分可能要求具體化內容
              Prepared :=true;
              open;
              //連接第二個線程時這裏出現問題

            if (fieldbyname('Phone').asstring='')or (fieldbyname('Name').asstring='')or (fieldbyname('SkillLevel').asstring='')then
               begin
             showmessage('nil');
                  Fnmmsg.Disconnect;
                  Fnmmsg.Host:= FIPaddressinfo;
                  Fnmmsg.Port :=6711;
                  Fnmmsg.FromName :='b';
                  Fnmmsg.PostIt(defeat);  //發送錯誤消息
                  close;
               end

           else    //如果找到了電話號碼
               begin

                   strlist.add(fieldbyname('Name').asstring);  //寫入姓名
                   SkillInfor:=fieldbyname('SkillGroup').asstring;
                   strlist.add(fieldbyname('SkillGroup').asstring+'業務處理='+fieldbyname('SkillLevel').asstring); //上海市業務處理=1
                   strlist.Add(fieldbyname('Phone').asstring);  //寫入電話號碼
                 
                   RetureInformation :=strlist.Strings[0]{工號}+'#'+strlist.Strings[1]{姓名}+'#'+strlist.Strings[2]+'#'{技能信息}+strlist.strings[3]{電話號碼};
                   //edit;                      //煩會給客戶端的信息
                  // fieldbyname('IsLogon').asstring:='1'; //登錄成功,寫入成功標誌
                  // Post;

                   FNMretureMSG.Disconnect;
                   FNMretureMSG.Host :=FIPaddressinfo;
                   FNMretureMSG.Port:=6722; //回傳信息遠程端口爲6722;
                   FNMretureMSG.PostIt(RetureInformation);  //返回成功的信息


/·······························
   {進行查詢工作組信息,然後傳送信息}
                   if active =true then close;
                   sql.clear;
                   SQL.Add('SELECT * FROM WORKER WHERE SkillGroup='+'"'+SkillInfor+'"');
                   open;
                 
                   WorkGroupUserInfor:=Tstringlist.create;

                 while not eof do
                  begin
                   WorkGroupUserInfor.Add(fieldByName('Name').asstring ); {index0 name}
                   WorkGroupUserInfor.Add(fieldByName('WorkMark').asstring ); {index1 workmark}
                   WorkGroupUserInfor.Add(fieldByName('Phone').asstring );    {index2 Phone}
                   WorkGroupUserInfor.Add(fieldByName('SkillGroup').asstring +'業務處理='+fieldbyname('SkillLevel').asstring);{index3 SkillGroup}
                   IPlist.Add(fieldbyname('IPaddress').asstring); ://所有的ip地址保留到內存中
                   //showmessage(fieldbyname('IPaddress').asstring);
                   iplist.SaveToFile (fieldByName('SkillGroup').asstring+'IPlst.INI');
                   next;
                 end;
                 WorkGroupUserInfor.SaveToFile(fieldByName('SkillGroup').asstring+'.ini');
                 close;
             end;
          end;
     end;
   end;
  except      //防止查詢失敗
    begin
      FAdoQuery.close;
      FAdoQUserInfor.close;
   end;
end;

end;

end.
注意:使用這兩個函數應該加上activex.pas單元,否則,無法運行。

我個人認爲,如果開發基於ADO的多線程操作,最好在每個線程中放置一個連接,而數據集和數據連接都使用動態生成,當然你必須要注意必須要保證線程能過正常的釋放,否則你的電腦很快就快死機了,呵呵,當然還有第二種方法,你可以生成一個數據模塊,靜態放置數據集和ADOCONNECTION組件,然後使該數據模塊不在程序開始時生成,而可以在線程中動態的生成,這種方法也可以,有興趣的朋友可以試一下二者之間的執行效率。

而對於ADO,我認爲在開始情況下,如果不初始函數和後來的釋放函數,卻不能報錯,應該是一個BUG吧。  

 
 2006-7-19 1:51:07    IE超連接失效處理方法

1、點擊“開始→運行”,輸入:regsvr32 actxprxy.dll,然後點擊“確定”按鈕,接着會出現一個信息對話框“DllRegisterServer in actxprxy.dll succeeded”;在該對話框中點“確定”按鈕;

2、再次點擊“開始→運行”,輸入:regsvr32 shdocvw.dll,然後點擊“確定”按鈕,接着會出現一個信息對話框“DllRegisterServer in shdocvw.dll succeeded”,在該對話框中點“確定”按鈕;

3、重新啓動Windows,運行IE,隨便打開一個網頁,點擊一個超鏈接試試。  

 
 2006-7-19 1:51:42    javascript常用到的一些方法

javascript常用到的一些方法
2006-07-11    chenxh       點擊: 1
 
javascript常用到的一些方法
 
function openBigWin(temUrl)
{
 var Wid;
 var Hei;
 var Type;

 Wid=700;
 Hei=500;
 Type=/"_blank/";

 window.open (temUrl,Type, /"scrollbars=yes,resizable=yes,toolbar=1,top=10,left=130,width=/"+Wid+/",height=/"+ Hei );
 return true;
}

 

function openMiddleWin(temUrl)
{


   var Wid=500;
        var Hei=400;

 var left=(screen.width-Wid)/2;
 var top=(screen.height-Hei)/2;

 if(top>100)
  top=100;

 var newWin=window.open(temUrl,/"_blank/", /"scrollbars=yes,resizable=yes,top=/"+top+/",toolbar=0,menubar=1,left=/"+left+/",width=/"+Wid+/",height=/"+ Hei );

 return newWin;
}

 

function openWin(temUrl,Type,Wid,Hei)
{
 window.open (temUrl,Type, /"scrollbars=no,resizable=yes,top=10,toolbar=0,left=130,width=/"+Wid+/",height=/"+ Hei );
 return true;
}

 

function openNewWin(temUrl,left,top,Wid,Hei)
{

 left=(screen.width-Wid)/2;
 top=(screen.height-Hei)/2;

 if(top>100)
  top=100;

 var newWin=window.open(temUrl,/"_blank/", /"scrollbars=yes,resizable=yes,top=/"+top+/",toolbar=0,menubar=1,left=/"+left+/",width=/"+Wid+/",height=/"+ Hei );

 return newWin;
}

 

function openNewWin2(winName,temUrl,Wid,Hei)
{

 var left;
 var top;


 left=(screen.width-Wid)/2;
 top=(screen.height-Hei)/2;

 if(top>100)
  top=100;

 var newWin=window.open(temUrl,winName, /"scrollbars=yes,resizable=yes,top=/"+top+/",toolbar=0,menubar=1,left=/"+left+/",width=/"+Wid+/",height=/"+ Hei );
 newWin.focus();

 return newWin;
}

function openWin(temUrl,Type,Wid,Hei)
{
 Wid=700;
 Hei=500;
 Type=/"_blank/";

 window.open (temUrl,Type, /"scrollbars=yes,resizable=yes,top=10,toolbar=1,left=130,width=/"+Wid+/",height=/"+ Hei );
 return true;
}

 

 

function isAlpha(s){

 for (var i=0; i<s.length; i++){

        var Char = s.charAt(i);
        if ((Char < /"a/" || Char > /"z/") && (Char < /"A/" || Char > /"Z/"))
            return false;
    }
    return true;
}

 


function isNumeric(p){

 if (p == /"/")
  return false;

  var l = p.length;
  var count=0;

  for(var i=0; i<l; i++) {
    var digit = p.charAt(i);
    if(digit == /"./" ){
     ++count;
      if(count>1) return false;
     }else if(digit < /"0/" || digit > /"9/")
     return false;
 }

  return true;
}

 

function isEmail(email){


 invalidChars = /" /;,:{}[]|*%$#!()`<>?/";
 if (email == /"/") {
  return false;
  }
 for (i=0; i< invalidChars.length; i++){

  badChar = invalidChars.charAt(i) ;
  if (email.indexOf(badChar,0) > -1){
   return false;
   }
  }
 atPos = email.indexOf(/"@/",1);
 if (atPos == -1){
   return false;
  }
 if (email.indexOf(/"@/", atPos+1) != -1) {
   return false;
  }

 periodPos = email.indexOf(/"./",atPos)
 if(periodPos == -1){
    return false;
     }

 if ( atPos +2 > periodPos) {
   return false;
  }

 if ( periodPos +3 > email.length){
   return false;
 }

 return true;
}

 


// pageNO :this pageNO
//nextPage: first,last,next,up,number(eg:777777)


function goPage(searchForm,pageNO,pageCounter,nextPage){

 var url;
 var customPageNO;

 //alert(/"hello/");

 url=searchForm.action+/"&pageNO=/";


 if (nextPage==/"first/"){


  if (pageNO==1){
   alert(/"已經是第一頁!/");
   return false;
  }else{
   pageNO=1;
   url=url+pageNO;

   searchForm.action=url;
   searchForm.submit();
  }


 }else  if (nextPage==/"up/"){


  if (pageNO==1){
   alert(/"已經是第一頁!/");
   return false;
  }else{
   pageNO=pageNO-1;
   url=url+pageNO;

   searchForm.action=url;
   searchForm.submit();
  }

 

 }else  if (nextPage==/"next/"){


  if (pageNO==pageCounter){
   alert(/"已經是最後一頁/");
   return false;
  }else{

   pageNO=parseInt(pageNO)+1+/"/";
   url=url+pageNO;

 

   searchForm.action=url;
   searchForm.submit();


  }


 }else  if (nextPage==/"last/"){

  //alert(/"pageNO:/" +pageNO + /"  pageCounter:/"+pageCounter);

  if (pageNO==pageCounter){
   alert(/"已經是最後一頁/");
   return false;
  }else{

   pageNO=pageCounter
   url=url+pageNO;


   searchForm.action=url;
   searchForm.submit();


  }

 }else if (isNumeric(nextPage) ){


  if (pageNO==nextPage){

   alert(/"已經是第/" +pageNO +/"頁!/");
   return false;

  }

  pageNO=nextPage;

  if (pageNO>=1 && pageNO<=pageCounter){

   url=url+pageNO;


   searchForm.action=url;
   searchForm.submit();

  }else{

   alert(/"頁面超出了範圍!/");
   return false;


  }

 

 }
 return false;
}


/*
  文件名: check_data.js
  功  能: 主要進行數據校驗
  更  新: 金永俊 2004年4月16日
     戴  嘉 2004.05.11
*/

//-------------------------------
//  函數名:isNull(i_field,i_value)
//  功能介紹:檢查輸入是否爲非空
//  參數說明:數據項,輸入的對應值
//  返回值  :0-非空,1-爲空
//-------------------------------
function isNull(i_field,i_value)
{
 if (i_value==null || jstrim(i_value)==/"/")
 {
    return 1;
 }
 else
 {
     alert(/"/'/"+i_field+/"/' 要求爲空!/");
     return 0;
 }
}

//-------------------------------
//  函數名:notNull(i_field,i_value)
//  功能介紹:檢查輸入是否爲非空
//  參數說明:數據項,輸入的對應值
//  返回值  :1-非空,0-爲空
//-------------------------------
function notNull(i_field,i_value)
{

 if (i_value==null || jstrim(i_value)==/"/")
 {
     alert(/"/'/"+i_field+/"/' 不可爲空!/");
     return 0;
 }

 return 1;


}

//-------------------------------
//  函數名:isNum(i_field,i_value)
//  功能介紹:檢查輸入字符串是否爲數字
//  參數說明:數據項,輸入的對應值
//  返回值  :1-是數字,0-非數字
//-------------------------------
function isNum(i_field,i_value)
{
    if (notNull(i_field,i_value)==0)
    {return 0;
    }

    re=new RegExp(/"[^0-9]/");
    var s;
    if(s=i_value.match(re))
     {
        alert(/"/'/"+i_field+/"/' 中含有非法字符 /'/"+s+/"/' !/");
        return 0;
     }
    return 1;
}

//-------------------------------
//  函數名:isGreatNum(i_field,i_value,i_value1)
//  功能介紹:檢查輸入字符串是否是數字並且大於i_value1
//  參數說明:數據項,輸入的對應值,比較數值
//  返回值  :1-給定的i_value爲數字且大於i_value1,
//           0-非數字或者i_value小於等於i_value1
//
//  戴嘉 2004.05.11
//-------------------------------
function isGreatNum(i_field,i_value,i_value1)
{
    //校驗輸入的是否爲數值
    if(isNum(i_field,i_value)==0)
     return 0;
    else
    {
        if(i_value<=i_value1)
         return 0;
    }

    return 1;
}

//-------------------------------
//  函數名:isSmallNum(i_field,i_value,i_value1)
//  功能介紹:檢查輸入字符串是否是數字並且小於i_value1
//  參數說明:數據項,輸入的對應值,比較數值
//  返回值  :1-給定的i_value爲數字且小於i_value1,
//           0-非數字或者i_value大於等於i_value1
//
//  戴嘉 2004.05.11
//-------------------------------
function isSmallNum(i_field,i_value,i_value1)
{
    //校驗輸入的是否爲數值
    if(isNum(i_field,i_value)==0)
     return 0;
    else
    {
        if(i_value>=i_value1)
         return 0;
    }

    return 1;
}


//-------------------------------
//  函數名:isDate(i_field,thedate)
//  功能介紹:校驗字符串是否爲日期格式
//  參數說明:數據項,輸入的字符串
//  返回值  :0-不是,1--是
//-------------------------------

function isDate(i_field,thedate)
{
  if (!(thedate.length==8 || thedate.length==10))
   {    alert(/"/'/"+i_field+/"/'日期格式不對,//n要求爲yyyymmdd或yyyy-mm-dd!/");
     return 0;
   }
  if (thedate.length==8)
  {
   thedate=thedate.substr(0,4)+/"-/"+thedate.substr(4,2)+/"-/"+thedate.substr(6,2);
  }

    var reg = /^(//d{1,4})(-)(//d{1,2})//2(//d{1,2})$/;
    var r = thedate.match(reg);

     if (r==null)
    {
       alert(/"請輸入正確的/'/"+i_field+/"/' !/");
       return 0;

    }
    var d= new Date(r[1],r[3]-1,r[4]);
    var newStr=d.getFullYear()+r[2]+(d.getMonth()+1)+r[2]+d.getDate()
    var newDate=r[1]+r[2]+(r[3]-0)+r[2]+(r[4]-0)
    //alert(/"----------r:/"+r+/" d:/"+d+/" newStr:/"+newStr+/" newDate:/"+newDate);
    if (newStr==newDate)
         {
          return 1;
         }
     alert(/"/'/"+i_field+/"/'日期格式不對,//n要求爲yyyymmdd或yyyy-mm-dd!/");
     return 0;
}

//-------------------------------
//  函數名:changeDate(thedate)
//  功能介紹:日期yyyymmdd轉換成yyyy-mm-dd格式
//  參數說明:輸入日期
//  返回值  :0-不是,1--是
//-------------------------------

function changeDate(thedate)
{

 if (thedate.length==8)
  {
   thedate=thedate.substr(0,4)+/"-/"+thedate.substr(4,2)+/"-/"+thedate.substr(6,2);
  }

     return thedate;

}

//-------------------------------
//  函數名:isLength(i_field,i_length,i_value)
//  功能介紹:檢查輸入值是否爲指定長度
//  參數說明:數據項,要求長度,值
//  返回值  :1-是指定長度,0-不是
//-------------------------------
function isLength(i_field,i_length,i_value)
{//  alert(/"---長度要求:/"+i_length+/" /"+i_value.length);
 if (!(i_value.length==i_length))
 {
     alert(/"/'/"+i_field+/"/' 的長度要求爲/' /"+i_length+/" /'!/");
     return 0;
 }
 return 1;
}

//-------------------------------
//  函數名:dyLength(i_field,i_length,i_value)
//  功能介紹:檢查輸入值是否達到指定長度以上
//  參數說明:數據項,要求長度,值
//  返回值  :1-符合,0-不是
//-------------------------------
function dyLength(i_field,i_length,i_value)
{ //alert(/"---長度要求:/"+i_length+/" /"+i_value.length);
 if (i_value.length<i_length)
 {
     alert(/"/'/"+i_field+/"/' 的長度至少爲 /'/"+i_length+/"/'!/");
     return 0;
 }
 return 1;
}

//-------------------------------
//  函數名:xyLength(i_field,i_length,i_value)
//  功能介紹:檢查輸入值不要超過指定長度
//  參數說明:數據項,要求長度,值
//  返回值  :1-符合,0-不是
//-------------------------------
function xyLength(i_field,i_length,i_value)
{ //alert(/"---長度要求:/"+i_length+/" /"+i_value.length);
 if (i_value.length>i_length)
 {
     alert(/"/'/"+i_field+/"/' 的長度最長爲 /'/"+i_length+/"/' !/");
     return 0;
 }
 return 1;
}

//-------------------------------
//  函數名:check_hm(標籤,長度,i_value)
//  參數說明:標籤,長度,值。
//  功能介紹:檢查輸入號碼字符串長度是否滿足;是否全數字。
//  返回值  :1-是,false-不是
//-------------------------------
function check_hm(i_field,i_length,i_value)
{

    if (isLength(i_field,i_length,i_value)==0)
    {
     return 0;
    }
    if (isNum(i_field,i_value)==0)
    {
     return 0;
    }
return 1;
}

//-------------------------------
//  函數名:check_yzbm(i_value)
//  參數說明:郵政編碼值。
//  功能介紹:檢查郵政編碼是否是6位長數字。
//  返回值  :1-是,false-不是
//-------------------------------
function check_yzbm(i_value)
{

    if (isLength(/"郵政編碼/",/"6/",i_value)==0)
    {
     return 0;
    }
    if (isNum(/"郵政編碼/",i_value)==0)
    {
     return 0;
    }
return 1;
}//-------------------------------
//  函數名:check_zjhm(zjmc,obj)
//  參數說明:證件名稱,證件號碼。
//  功能介紹:檢查身份證號碼合法性。
//       對身份證檢查是否爲全數字;出生日期格式是否正確;是否<=18,<=70;校驗碼檢查
//  返回值  :1-是,0-不
//-------------------------------
function check_zjhm(zjmc,zjhm)
{

  var birthday=/"/";
  var zjhm1=/"/";
  var zjhm2=/"/";

  var s=/"/";
  if (notNull(/"證件號碼/",zjhm)==0)  { return 0;  }
  if(zjmc==/"A/")   //身份證號碼
   {
       if(!(zjhm.length==15 || zjhm.length==18) )
      {
        alert(/"身份證長度不對,請檢查!/") ;
               return 0;
      }
        zjhm1=zjhm;
        if (zjhm.length==18)
            {
                zjhm1=zjhm.substr(0,17) ;
                zjhm2=zjhm.substr(17,1);
            }

         re=new RegExp(/"[^0-9]/");
  if(s=zjhm1.match(re))
     {
         alert(/"輸入的值中含有非法字符/'/"+s+/"/'請檢查!/");
         return 0;
             }
        //取出生日期
        if(zjhm.length==15 )
            {
               birthday=/"19/"+zjhm.substr(6,6);
            }
         else
            {
             re=new RegExp(/"[^0-9X]/");
               if(s=zjhm2.match(re))     //18位身份證對末位要求數字或字符
               {
                   alert(/"輸入的值中含有非法字符/'/"+s+/"/'請檢查!/");
                   return 0;
                }
                birthday=zjhm.substr(6,8);
            }
           birthday=birthday.substr(0,4)+/"-/"+birthday.substr(4,2)+/"-/"+birthday.substr(6,2)
          //alert(/"birthday/"+birthday)

          if(isDate(/"證件號碼/",birthday)==0)  //檢查日期的合法性
          {
             return 0;
          }

         var nl=cal_years(birthday);//求年齡

         //if (nl-0<18 || nl>70)
         if (nl-0<18)
     {
             alert(/"年齡要求 18歲以上 ,當前 /"+nl+/" !/");
            return 0;
           }
          if(zjhm.length==18 )
          {
           return(sfzCheck(zjhm));  //對18位長的身份證進行末位校驗
          }
       }
else
 {if (zjhm.length>17){

        alert(/"非‘居民身份證’長度不得超過17位,請檢查!/") ;
               return 0;
 }
 }

   return 1;
   }
function check_zjhmNoAge(zjmc,zjhm)
{

  var birthday=/"/";
  var zjhm1=/"/";
  var zjhm2=/"/";

  var s=/"/";
  if (notNull(/"證件號碼/",zjhm)==0)  { return 0;  }
  if(zjmc==/"A/")   //身份證號碼
   {
       if(!(zjhm.length==15 || zjhm.length==18) )
      {
        alert(/"身份證長度不對,請檢查!/") ;
               return 0;
      }
        zjhm1=zjhm;
        if (zjhm.length==18)
            {
                zjhm1=zjhm.substr(0,17) ;
                zjhm2=zjhm.substr(17,1);
            }

         re=new RegExp(/"[^0-9]/");
  if(s=zjhm1.match(re))
     {
         alert(/"輸入的值中含有非法字符/'/"+s+/"/'請檢查!/");
         return 0;
             }
        //取出生日期
        if(zjhm.length==15 )
            {
               birthday=/"19/"+zjhm.substr(6,6);
            }
         else
            {
             re=new RegExp(/"[^0-9X]/");
               if(s=zjhm2.match(re))     //18位身份證對末位要求數字或字符
               {
                   alert(/"輸入的值中含有非法字符/'/"+s+/"/'請檢查!/");
                   return 0;
                }
                birthday=zjhm.substr(6,8);
            }
           birthday=birthday.substr(0,4)+/"-/"+birthday.substr(4,2)+/"-/"+birthday.substr(6,2)
          //alert(/"birthday/"+birthday)

          if(isDate(/"證件號碼/",birthday)==0)  //檢查日期的合法性
          {
             return 0;
          }


          if(zjhm.length==18 )
          {
           return(sfzCheck(zjhm));  //對18位長的身份證進行末位校驗
          }
       }
else
 {if (zjhm.length>17){

        alert(/"非‘居民身份證’長度不得超過17位,請檢查!/") ;
               return 0;
 }
 }

   return 1;
   }

function id15to18(zjhm)
{


 var strJiaoYan =new  Array(/"1/", /"0/", /"X/", /"9/", /"8/", /"7/", /"6/", /"5/", /"4/", /"3/", /"2/");
 var intQuan =new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1);
 var ll_sum=0;
 var i;
 var ls_check;
 zjhm = zjhm.substring(0, 6) + /"19/" + zjhm.substring(6);
 for (i=0;i<=16;i++){
  ll_sum=ll_sum+(parseFloat(zjhm.substr(i,1)))*intQuan[i];
 }
 ll_sum = ll_sum % 11;
 zjhm=zjhm + strJiaoYan[ll_sum];
 return zjhm;
}
//-------------------------------
//  函數名  :check_sg(i_value)
//  參數說明:身高。
//  功能介紹:檢查身高是否爲數字;是否>=100,<=250
//  返回值  :1-是,0-不是
//-------------------------------

function check_sg(i_value)
{
        if(isNum(/"身高/",i_value)==0)  //檢查身高是否爲數字
        {
               return 0;
        }
        else
        {
  if ((i_value-0)<100 ||(i_value-0)>250)
  {
        alert(/"/'身高/'合理範圍應在 100--250 !/");
               return 0;
  }
        }
  return 1;
}

//-------------------------------
//  函數名  :check_sl(i_value)
//  參數說明:視力。
//  功能介紹:檢查視力是否爲數字;是否>=4.9,<=5.5
//  返回值  :1-是,false-不是
//-------------------------------

function check_sl(i_value)
{
    var reg = /^(//d{1,1})(//.)(//d{1,1})$/;

if (document.all[/"zsl/"].value.length==2)
 {
 document.all[/"zsl/"].value=document.all[/"zsl/"].value.substr(0,1)+/"./"+document.all[/"zsl/"].value.substr(1,1);
 }
 if (document.all[/"ysl/"].value.length==2)
 {
    document.all[/"ysl/"].value=document.all[/"ysl/"].value.substr(0,1)+/"./"+document.all[/"ysl/"].value.substr(1,1);
 }
    var r = document.all[/"zsl/"].value.match(reg);
    var r1 = document.all[/"ysl/"].value.match(reg);
    if(r==null)
     {
         alert(/"左視力的格式應爲:x.x !/")
         return 0;
       }
    if(r1==null)
     {
         alert(/"右視力的格式應爲:x.x !/")
         return 0;
       }

    if ((document.all[/"zsl/"].value-0)<4.9 || (document.all[/"zsl/"].value-0)>5.5)
    {
         alert(/"/'左視力/'應在 4.9--5.5 範圍!/");
         return 0;
    }
    if ((document.all[/"ysl/"].value-0)<4.9 || (document.all[/"ysl/"].value-0)>5.5)
    {
         alert(/"/'右視力/'應在 4.9--5.5 範圍!/");
         return 0;
    }
 return 1;
}

//-------------------------------
//  函數名:isHg(bsl,tl,sz,qgjb)
//  功能介紹:辨色力,聽力,上肢,軀幹頸部是否合格
//  參數說明:辨色力,聽力,上肢,軀幹頸部
//  返回值  :1-符合申請,0-不符合
//-------------------------------

function isHg(bsl,tl,sz,qgjb)
{//alert(bsl+tl+sz+qgjb)
    if (!(bsl==1))
       {
          alert(/"/'辨色力/'不合格者不能申請!/");
          return 0;
       }
    if (!(tl==1))
       {
          alert(/"/'聽力/'不合格者不能申請!/");
          return 0;
       }
    if (!(sz==1))
       {
          alert(/"/'上肢/'不合格者不能申請!/");
          return 0;
       }
    if (!(qgjb==1))
       {
          alert(/"/'軀幹頸部/'不合格者不能申請!/");
          return 0;
       }
 if((document.all[/"yxz/"].value)==0)
 {
   alert(/"右下肢必須合格!/")
   document.all.yxz.focus();
   return 0;
 }
     return 1;
}

//-------------------------------
//  函數名:sfzCheck(hm)
//  功能介紹:對18位長的身份證進行末位校驗
//  參數說明:身份證號碼
//  返回值  :1-符合,0-不符合
//-------------------------------

function sfzCheck(hm)
{

      var w=new Array();
      var ll_sum;
      var ll_i;
      var ls_check;


  if(hm.length==15) //長度15,直接返回true
  return true;

   if(hm.length!=15 && hm.length!=18){

  alert(/"身份證號碼長度不正確/");
  return false;

   }

      w[0]=7;
      w[1]=9;
      w[2]=10;
      w[3]=5;
      w[4]=8;
      w[5]=4;
      w[6]=2;
      w[7]=1;
      w[8]=6;
      w[9]=3;
      w[10]=7;
      w[11]=9;
      w[12]=10;
      w[13]=5;
      w[14]=8;
      w[15]=4;
      w[16]=2;
     ll_sum=0;

     for (ll_i=0;ll_i<=16;ll_i++)
     {   //alert(/"ll_i:/"+ll_i+/" /"+hm.substr(ll_i,1)+/"w[ll_i]:/"+w[ll_i]+/"  ll_sum:/"+ll_sum);
        ll_sum=ll_sum+(hm.substr(ll_i,1)-0)*w[ll_i];

     }
     ll_sum=ll_sum % 11;


     switch (ll_sum)
      {
        case 0 :
            ls_check=/"1/";
            break;
        case 1 :
            ls_check=/"0/";
            break;
        case 2 :
            ls_check=/"X/";
            break;
        case 3 :
            ls_check=/"9/";
            break;
        case 4 :
            ls_check=/"8/";
            break;
        case 5 :
            ls_check=/"7/";
            break;
        case 6 :
            ls_check=/"6/";
            break;
        case 7 :
            ls_check=/"5/";
            break;
        case 8 :
            ls_check=/"4/";
            break;
        case 9 :
            ls_check=/"3/";
            break;
        case 10 :
            ls_check=/"2/";
            break;
      }

      if (hm.substr(17,1) != ls_check)
      {
            alert(/"身份證校驗錯誤!------ 末位應該:/"+ls_check+/" 實際:/"+hm.substr(hm.length-1,1));
            return 0;
     }
return 1
}

function  comm_check(){
if (document.all[/"xm/"].value.length<2)
{
document.all[/"xm/"].focus();
alert(/"/'姓名/'長度至少兩漢字!/");
return 0;
 }
if (document.all[/"lxdh/"].value.length<6)
{
document.all[/"lxdh/"].focus();
alert(/"/'聯繫電話/'長度至少6位!/");
return 0;
 }
return 1;
}

//-------------------------------
//  函數名  :check_zjcx(s_value,s_cx_dm)
//  參數說明:準駕車型字符串,合法的準駕車行字符串數組。
//  功能介紹:檢查車型輸入是否正確,只檢查是否包含合法的準駕車行字符串,重複、次序顛倒不認爲是錯誤
//  返回值  :1-包含合法的準駕車行,0-不合法
//
//  戴嘉 2004.05.12
//-------------------------------
function check_zjcx(s_value,s_cx_dm)
{
   //合法的準駕車行字符串數組
 //var s_cx_dm=new Array(/"A1/",/"A2/",/"A3/",/"B1/",/"B2/",/"C1/",/"C2/",/"C3/",/"C4/",/"D/",/"E/",/"F/",/"M/",/"N/",/"P/");
        //字符串數組的長度
        var s_cx_input; //存放需要檢驗的字符串
 var i_pos; //查找子串定位
        var i;

        s_cx_input=s_value;
 for(i in s_cx_dm) //對合法準駕車行字符串數組輪循
 {
  do
  {
   i_pos=s_cx_input.indexOf(s_cx_dm[i]); //是否包含當前車型
   if(i_pos!=-1) //包含
   {
                           //去掉找到的子串
    s_cx_input=s_cx_input.slice(0,i_pos)+s_cx_input.slice(i_pos+s_cx_dm[i].length);
   }
  }while(i_pos!=-1); //找不到當前車型子串,進入下一車型子串查找
 }

 if(s_cx_input.length==0) //輸入字符串包含的都是合法的車型子串(全部被去掉了)
  return 1;
 else //輸入字符串還包含有非法的字符串
  return 0;
}


//-------------------------------
//  函數名:DateAddMonth(strDate,iMonths)
//  功能介紹:獲得日期加上iMonths月數後的日期
//  參數說明:strDate 日期
//  返回值  :無返回值
//-------------------------------
function DateAddMonth(strDate,iMonths){
   var thisYear = parseFloat(strDate.substring(0,4));
   var thisMonth = parseFloat(strDate.substring(5,7));
   var thisDate = parseFloat(strDate.substring(8,10));
   var d =thisYear *12 + thisMonth + iMonths;

   var newMonth = d % 12;
   if (newMonth==0) {
    newMonth=12;
   }
   var newYear = (d - newMonth) /12;
   var newDate = thisDate;
   var iMonthLastDate=getMonthLastDate(newYear,newMonth)
   if (newDate>iMonthLastDate) newDate=iMonthLastDate;
   var newDay=/"/";

   newDay += newYear;
   if (newMonth<10) {
    newDay +=/"-/" + /"0/" + newMonth;
   }else{
    newDay +=/"-/" + newMonth;
   }

   if (newDate<10) {
    newDay +=/"-/" + /"0/" + newDate;
   }else{
    newDay +=/"-/" + newDate;
   }
   return(newDay);                                // 返回日期。
}

function getMonthLastDate(iYear,iMonth){
 var dateArray= new Array(31,28,31,30,31,30,31,31,30,31,30,31);
 var days=dateArray[iMonth-1];
 if ((((iYear % 4 == 0) && (iYear % 100 != 0)) || (iYear % 400 == 0)) && iMonth==2){
  days=29;
 }
 return days;
}

var keyvalue=/"/";
var srcStr=/"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/";
var objName=/"/";
function findCode(event,obj)
{
 if (objName != obj.name){
  objName=obj.name;
  keyvalue=/"/";
 }
        if (event.keyCode==13 || event.keyCode==9 ) {
          keyvalue=/"/";
          return true;
        }

 //if(srcStr.indexOf(String.fromCharCode(event.keyCode))!=-1)
 // keyvalue=/"/";
 keyvalue=keyvalue+String.fromCharCode(event.keyCode).toUpperCase();
 //alert(keyvalue);
 for(var i=0;i<obj.options.length;i++)
 {
  if(obj.options[i].value.indexOf(keyvalue)!=-1)
  {
   obj.value=obj.options[i].value;
                        if (obj.options[i].value==keyvalue){
    objName=/"/"
   }
   return true;
  }
 }
}
function findName(event,obj)  //根據代碼取名稱
{
 if (objName != obj.name){
  objName=obj.name;
  keyvalue=/"/";
 }
        if (event.keyCode==13 || event.keyCode==9 ) {
          keyvalue=/"/";
          return true;
        }

 //if(srcStr.indexOf(String.fromCharCode(event.keyCode))!=-1)
 // keyvalue=/"/";
 keyvalue=keyvalue+String.fromCharCode(event.keyCode).toUpperCase();
 //alert(keyvalue);
 //alert(obj.options.length);
 for(var i=0;i<obj.options.length;i++)
 {
  //alert(obj.options[i].text);

  if(obj.options[i].text.indexOf(keyvalue)!=-1)
  {
   obj.value=obj.options[i].value;
   return true;
  }
 }
}
//自動清除輸入框中的空格
function ignoreSpaces(string) {
var temp = /"/";
string = /'/' + string;
splitstring = string.split(/" /"); //雙引號之間是個空格;
for(i = 0; i < splitstring.length; i++)
temp += splitstring[i];
return temp;
}


/*
  文件名: function.js
  功  能: 常用的功能庫
  功能塊:

  更  新: 金永俊 2004年4月16日
   戴嘉 2004.05.20
*/


var todaystr;
todaystr=new Date();


//-------------------------------
//  函 數 名:cal_years(rq)
//  功能介紹:計算指定日期到今天是多少年.
//  參數說明:日期
//  返    回:年數
//-------------------------------

function cal_years(rq)
{
var years;
//var dDate = new Date();  //系統日期(系統日期應該大於rq)
var dDate=todaystr;
var month1= dDate.getMonth()+1;
var year1= dDate.getFullYear();
var day1=dDate.getDate()
var year2= rq.substr(0,4);
var month2= rq.substr(5,2);
var day2=rq.substr(8,2);
//alert(/"-----------dDate-/"+dDate+/" year1/"+year1+/" month1/"+month1+/" day1/"+day1);
     years = year1 - year2 - 0;
     if (month2 > month1)   //月份未到,years-1
     {
       years = years - 1;
     }
     else
     {
       if ( (month1 == month2) && (day2 > day1))  //月份到了,但日未到,years-1
       {
         years = years - 1;
       }
     }
//alert(/"-----------years-/"+years);
return years;
}

//-------------------------------
//  函 數 名:cal_years1(rq1,rq2)
//  功能介紹:計算指定日期到今天是多少年.(rq1-rq2)
//  參數說明:日期1,日期2
//  返    回:年數
//-------------------------------

function cal_years1(rq1,rq2)
{
var years;
var year1= rq1.substr(0,4);
var month1= rq1.substr(5,2);
var day1=rq1.substr(8,2);
var year2= rq2.substr(0,4);
var month2= rq2.substr(5,2);
var day2=rq2.substr(8,2);
//alert(/"-----------dDate-/"+dDate+/" year1/"+year1+/" month1/"+month1+/" day1/"+day1);
     years = year1 - year2 - 0;
     if (month2 > month1)   //月份未到,years-1
     {
       years = years - 1;
     }
     else
     {
       if ( (month1 == month2) && (day2 > day1))  //月份到了,但日未到,years-1
       {
         years = years - 1;
       }
     }
//alert(/"-----------years-/"+years);
return years;
}
//-------------------------------
//  函 數 名:cal_days(rq1,rq2)
//  功能介紹:計算兩個日期間隔天數(要求rq2>=rq1).
//  參數說明:日期1,日期2
//  返    回:天數
//-------------------------------

function cal_days(rq1,rq2)
{  var d, s, t, d1 , d2, s1 , s2;
   var DyMilli = 24 * 60 * 60 * 1000;  //一天的毫秒數
   //d = new Date();
   d=todaystr
   s = d.getTime();  //系統日期與 1970 年 1 月 1 日午夜間全球標準時間 的毫秒數

     var days;
     //系統日期、年、月、日
     //var dDate = new Date();
     var dDate=todaystr
     var month= dDate.getMonth()+1;
     var year= dDate.getFullYear();
     var day=dDate.getDate();
         d=new Date(year,month-1,day);
         s = d.getTime()
     var month1;
     var month2;
     var year1;
     var year2;
     var day1;
     var day2;


     if (rq1==/"/")
     {
      s1=s;
       month1= month;
      year1= year;
      day1= day;
    }
     else
     {
        year1= rq1.substr(0,4);
        month1= rq1.substr(5,2);
        day1=rq1.substr(8,2);
        d1=new Date(year1,month1-1,day1);
        s1=d1.getTime();
     }

     if (rq2==/"/")
     {
      s2=s;
      month2= month;
      year2= year;
      day2= day;
     }
     else
     {
        year2= rq2.substr(0,4);
        month2= rq2.substr(5,2);
        day2=rq2.substr(8,2);
        d2=new Date(year2,month2-1,day2);
        s2=d2.getTime();
     }
     //alert(/"rq1:/"+rq1+/" rq2:/"+rq2+/" y1:/"+year1+/" y2:/"+year2+/" m1:/"+month1+/" m2:/"+month2+/" d1:/"+day1+/" d2:/"+day2);
     days=Math.round((s2 - s1) / DyMilli);;
     //alert(/"days:/"+days);
return days;
}

 

//-------------------------------
//  函 數 名:get_checkbox(get_item)
//  功能介紹:取複選框的內容.
//  參數說明:複選框的數組名
//  返    回:複選框的值
//-------------------------------
function get_checkbox(get_item)
{
var get_item_content
get_item_content=/"/"
var item_length=get_item.length
//alert(item_length)
for(var i=0;i<item_length;i++)
{
  if(get_item.item(i).checked)
  {
   //alert(get_item.item(i).value)
  get_item_content=get_item_content+get_item.item(i).value
  }
}
return get_item_content;
}


//-------------------------------
//  函 數 名:set_checkbox(set_item,s_value)
//  功能介紹:設置複選框數組的內容.
//  參數說明:複選框的控件數組對象,表示狀態的字符串(checkbox的value值)
//  返    回:設置的複選框數量
//
//  戴嘉 2004.05.11
//-------------------------------
function set_checkbox(set_item,s_value)
{
        var i,j; //循環計數器,i-控件數組循環,j-字符串值位置控制

 //輪循狀態字符串
 for(j=0;j<s_value.length;j++)
        {
         //輪循控簡數組
         for(i=0;i<set_item.length;i++)
         {
          if(set_item.item(i).value==s_value.substr(j,1))
                 {
                  set_item.item(i).checked=true;
                                break;
                 }
         }
        }

 return j;
}

 

//-------------------------------
//  函 數 名:bulidXzqh(obj,Opt_name,Opt_value)
//  功能介紹:構建新的所屬轄區下拉列表
//  參數說明:日期1,日期2
//  返    回:
//-------------------------------

function bulidXzqh(obj,Opt_name,Opt_value)
{
  var n1
  if(Opt_name.length>0)
  {

    n1=document.createElement(/"OPTION/")
    n1.value=Opt_value
    n1.text=Opt_name
    obj.add(n1)
    var i=obj.length-1
    obj.options[i].selected=true
 }

}

 

 

 

//----------構建下拉列表--------------

function buildList(get_xml_id,put_id,view_type)
{

var xmldoc,theNode,code1Node;
var get_list,get_list_code,get_list_value
var str1=/"document.all./"+get_xml_id+/".XMLDocument/"
xmldoc=eval(str1)
xmldoc.async=false
//xmldoc=eval(/"document.all./"+get_xml_id+/".XMLDocument/")

//取類型
var str2=/"xmldoc.getElementsByTagName(///"Codes///")/"

//get_list=eval(/"xmldoc.getElementsByTagName(///"/"+get_type_name +/"///")/")
get_list=eval(str2)

//get_list_code=get_list.item(0).getElementsByTagName(/"code/")
//get_list_value=get_list.item(0).getElementsByTagName(/"value/")

if(view_type==null || view_type==/"/"){view_type=/"0/"}   //缺省

//顯示名稱,保存名稱,view_type==/"2/"
if(view_type==/"2/")
{

for(var i=0;i<get_list.length;i++)
{
var str3=/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list.item(i).lastChild.text,get_list.item(i).lastChild.text)/"
//alert(str3)
eval(str3)
//eval(/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list_value.item(i).text,get_list_code.item(i).text/")
}
}

//顯示時帶代碼,view_type==/"1/"

if(view_type==/"1/")
{

for(var i=0;i<get_list.length;i++)
{
var str3=/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list.item(i).firstChild.text+get_list.item(i).lastChild.text,get_list.item(i).firstChild.text)/"
//alert(str3)
eval(str3)
//eval(/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list_value.item(i).text,get_list_code.item(i).text/")
}
}
if(view_type==/"0/")
{
//顯示時不帶代碼,view_type==/"0/"

for(var i=0;i<get_list.length;i++)
{
var str3=/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list.item(i).lastChild.text,get_list.item(i).firstChild.text)/"
//alert(str3)
eval(str3)
//eval(/"document.all[///"/"+put_id+/"///"].options[i]=new Option(get_list_value.item(i).text,get_list_code.item(i).text/")
}
}


}
//----------建立複選列表(準駕必備和提交資料)--------------
function build_checkbox(get_xml_id,put_id,checkbox_name)
{
  var xmldoc,theNode,code1Node;
  var get_list,get_list_code,get_list_value
  var str1=/"document.all./"+get_xml_id+/".XMLDocument/"
  xmldoc=eval(str1)
  var htmlstr=/"/"
//取類型
var str2=/"xmldoc.getElementsByTagName(///"Codes///")/"
get_list=eval(str2)
   for(var i=0;i<get_list.length;i++)
  {
   htmlstr=htmlstr+/"<input type=///"checkbox///"  name=///"/"+checkbox_name+ /"///"   value=///"/"+get_list.item(i).firstChild.text+/"///">/"+get_list.item(i).lastChild.text
  }
var str3=/"document.all./"+put_id+/".innerHTML=htmlstr/"
//alert( htmlstr)
eval(str3)


}

//----------整理提交資料項目--------------
function get_checkbox1(get_item,put_id)
{
var get_item_content
get_item_content=/"/"
var item_length=get_item.length
//alert(item_length)
for(var i=0;i<item_length;i++)
{
  if(get_item.item(i).checked)
  {
   //alert(get_item.item(i).value)
  get_item_content=get_item_content+get_item.item(i).value
  }
}
alert(get_item_content);
var the_str=/"document.all[///"/"+put_id+/"///"].value=get_item_content/"
//document.all[/"get_tjzl/"].value=get_item_content
eval(the_str)

}


/*多項選擇checkbox的逆過程
box_value  爲字符串
box_name   checkbox的name
2003-05-10
*/
function back_checkbox(box_name,box_value)
{
var box_length
var item_value
var obj_str
var obj
obj_str=/"document.all[///"/"+box_name+/"///"]/"
obj=eval(obj_str)
box_length=obj.length
for(var i=0;i<box_length;i++)
   {
    item_value=obj.item(i).value
    if(box_value.indexOf(item_value)>-1)
     {
      obj.item(i).checked=true
     }
   }

}

function decode_from_xml(xml_id,the_code)    //代碼翻譯
{
 var de_code=/"/"
 var str,obj
 str=/"document.all[///"/"+xml_id+/"///"]/"
 obj=eval(str)
  while(!obj.recordset.EOF)
  {
    var code=obj.recordset(/"code/")
    if(code==the_code)
    {
    de_code=new String(obj.recordset(/"Value/"))
    }
    obj.recordset.moveNext();

}
  obj.recordset.moveFirst();
  return  de_code;

}


function decode_self(the_code)
{

 var de_code
 de_code=/"/"


 if(the_code==/"1/")
 {
    de_code=/"合格/";
 }
 else
 {

   de_code=/"不合格/";
}

  return  de_code;

}


//----------構建可管理車型下拉列表--------------

function glcx_list(get_xml_id,glcx,put_id)
{

var xmldoc,theNode,code1Node;
var get_list,get_list_code,get_list_value
var str1=/"document.all./"+get_xml_id+/".XMLDocument/"
//alert(str1)
xmldoc=eval(str1)
xmldoc.async=false
//alert(xmldoc.xml)


//取類型
var str2=/"xmldoc.getElementsByTagName(///"Codes///")/"
get_list=eval(str2)

//alert(/"AAA:/"+get_list.length)


var j=0

for(var i=0;i<get_list.length;i++)
{

  if(glcx.indexOf(get_list.item(i).firstChild.text)>-1)
  {

  var str3=/"document.all[///"/"+put_id+/"///"].options[j]=new Option(get_list.item(i).firstChild.text+get_list.item(i).lastChild.text,get_list.item(i).firstChild.text)/"
  eval(str3)
  j=j+1
  }
}


}


function cReadonly(obj){
 if (obj.type==/"text/"){
  obj.readOnly=true
  obj.parentElement.className=/"readonly/"
 }else{
  obj.parentElement.className=/"readonly/"
 }
}

function cEditable(obj){
 if (obj.type==/"text/"){
  obj.readOnly=false
  obj.parentElement.className=/"editable/"
 }else{
  obj.parentElement.className=/"editable/"
 }
}

//-------------------------------
//  函數名:jstrim(s_value)
//  功能介紹:去掉s_value兩端的空格
//  參數說明:被操作的字符串
//  返回值  :處理結果字符串
//-------------------------------
function jstrim(s_value)
{


 var i;
 var ibegin;

 for(i=0;i<s_value.length;i++)
 {
  if(s_value.charAt(i)!=/' /')
   break;
 }


 if(i==s_value.length)
  return /"/";
 else
  ibegin=i;


 for(i=s_value.length-1;i>=0;i--)
 {
  if(s_value.charAt(i)!=/' /')
   break;
 }


 return s_value.substr(ibegin,i-ibegin+1);
}

//-------------------------------
//  函數名:trimall()
//  功能介紹:去掉document的所有form裏面的所有的input(text)裏面的兩端空格
//  參數說明:無
//  返回值  :無
//-------------------------------
function trimall()
{
 var i,j;
 var allforms;
 var myelement;

 allforms=document.forms;

 for(i=0;i<allforms.length;i++)
 {
  for(j=0;j<allforms(i).elements.length;j++)
  {
   myelement=allforms(i).elements(j);
   if(myelement.type==/"text/")
    //myelement.value=jstrim(myelement.value.toUpperCase());
   myelement.value=jstrim(myelement.value);
  }
 }
}
//-------------------------------
//  函數名:
//  功能介紹:日期加年
//  參數說明:無
//  返回值  :無
//-------------------------------
function rqaddyears(rq1,ns)
{
if (rq1.length==10){
y=parseInt(rq1.substring(0,4))+ns
m=parseInt(rq1.substring(5,7))
d=parseInt(rq1.substring(8,10))

}else if (rq1.length==8){
y=parseInt(rq1.substring(0,4))+ns
m=parseInt(rq1.substring(4,6))
d=parseInt(rq1.substring(6,8))
}else{
return /"/";
}
var str =y+rq1.substring(4,10);
if (m==2 && d==29){
str=y+rq1.substring(4,7)+/"-28/";
}

return str
}

//光標移動至最後
function movelast()
{
var e = event.srcElement;
var r =e.createTextRange();
r.moveStart(/'character/',e.value.length);
r.collapse(true);
r.select();
}


//翻譯obj(select)中的值
function trancode(obj,val){
for (var i=0;i<obj.length;i++){
var tmp
tmp=obj.options(i).text
tmp=tmp.substr((tmp.indexOf(/":/")+1),tmp.length-tmp.indexOf(/":/")-1)
if (obj.options(i).value==val){
return tmp
}

}
return /"/"
}
//-------------------------------
//  函數名:DateAddMonth(strDate,iMonths)
//  功能介紹:獲得日期加上iMonths月數後的日期
//  參數說明:strDate 日期
//  返回值  :無返回值
//-------------------------------
function DateAddMonth(strDate,iMonths){
   var thisYear = parseFloat(strDate.substring(0,4));
   var thisMonth = parseFloat(strDate.substring(5,7));
   var thisDate = parseFloat(strDate.substring(8,10));
   var d =thisYear *12 + thisMonth + parseFloat(iMonths);

   var newMonth = d % 12;
   if (newMonth==0) {
    newMonth=12;
   }
   var newYear = (d - newMonth) /12;
   var newDate = thisDate;
   var iMonthLastDate=getMonthLastDate(newYear,newMonth)
   if (newDate>iMonthLastDate) newDate=iMonthLastDate;
   var newDay=/"/";

   newDay += newYear;
   if (newMonth<10) {
    newDay +=/"-/" + /"0/" + newMonth;
   }else{
    newDay +=/"-/" + newMonth;
   }

   if (newDate<10) {
    newDay +=/"-/" + /"0/" + newDate;
   }else{
    newDay +=/"-/" + newDate;
   }
   return(newDay);                                // 返回日期。
}
function getMonthLastDate(iYear,iMonth){
 var dateArray= new Array(31,28,31,30,31,30,31,31,30,31,30,31);
 var days=dateArray[iMonth-1];
 if ((((iYear % 4 == 0) && (iYear % 100 != 0)) || (iYear % 400 == 0)) && iMonth==2){
  days=29;
 }
 return days;
}


//####################################
//保存客戶信息
//
//
//#####################################
function getcookie(nKey){
 var search=nKey+/"=/";
 begin=document.cookie.indexOf(search);
 if (begin!=-1){
  begin+=search.length
  end=document.cookie.indexOf(/";/",begin);
  if (end==-1){
   end=document.cookie.length;
  }
  return document.cookie.substring(begin,end)
 }else{
 return /"/"
 }
}

function setcookie(nKey,nVal){
document.cookie=nKey+/"=/"+nVal+/";expires=wednesday,09-oct-2099 23:00:00 GMT/"
}


function disableall()
{
 var i,j;
 var allforms;
 var myelement;

 allforms=document.forms;

 for(i=0;i<allforms.length;i++)
 {
  for(j=0;j<allforms(i).elements.length;j++)
  {
   myelement=allforms(i).elements(j);
   if(myelement.type==/"text/")
    //myelement.value=jstrim(myelement.value.toUpperCase());
   //myelement.value=jstrim(myelement.value);
   myelement.readOnly=true;
  }
 }
}


function selectedObj(obj,value){


 var i=obj.length;
 for(index=0;index<i;index++){

  if (obj.options[index].value==value)
  {
      obj.options[index].selected=true;
      break;
  }

 }

}

function getSelectedObjText(obj){

     return obj.options[obj.selectedIndex].text;

}

 

 
 2006-7-19 1:52:25    Delphi的Socket I/O模型

老陳有一個在外地工作的女兒,不能經常回來,老陳和她通過信件聯繫。他們的信會被郵遞員投遞到他們的信箱裏。

  這和Socket模型非常類似。下面我就以老陳接收信件爲例講解Socket I/O模型。

  一:select模型

  老陳非常想看到女兒的信。以至於他每隔10分鐘就下樓檢查信箱,看是否有女兒的信,在這種情況下,“下樓檢查信箱”然後回到樓上耽誤了老陳太多的時間,以至於老陳無法做其他工作。

  select模型和老陳的這種情況非常相似:周而復始地去檢查......如果有數據......接收/發送.......

  使用線程來select應該是通用的做法:
procedure TListenThread.Execute;
var
 addr : TSockAddrIn;
 fd_read : TFDSet;
 timeout : TTimeVal;
 ASock,
 MainSock : TSocket;
 len, i : Integer;
begin
 MainSock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
 addr.sin_family := AF_INET;
 addr.sin_port := htons(5678);
 addr.sin_addr.S_addr := htonl(INADDR_ANY);
 bind( MainSock, @addr, sizeof(addr) );
 listen( MainSock, 5 );

 while (not Terminated) do
 begin
  FD_ZERO( fd_read );
  FD_SET( MainSock, fd_read );
  timeout.tv_sec := 0;
  timeout.tv_usec := 500;
  if select( 0, @fd_read, nil, nil, @timeout ) > 0 then //至少有1個等待Accept的connection
  begin
   if FD_ISSET( MainSock, fd_read ) then
   begin
   for i:=0 to fd_read.fd_count-1 do //注意,fd_count <= 64,也就是說select只能同時管理最多64個連接
   begin
    len := sizeof(addr);
    ASock := accept( MainSock, addr, len );
    if ASock <> INVALID_SOCKET then
     ....//爲ASock創建一個新的線程,在新的線程中再不停地select
    end;
   end;   
  end;
 end; //while (not self.Terminated)

 shutdown( MainSock, SD_BOTH );
 closesocket( MainSock );
end;

  二:WSAAsyncSelect模型

  後來,老陳使用了微軟公司的新式信箱。這種信箱非常先進,一旦信箱裏有新的信件,蓋茨就會給老陳打電話:喂,大爺,你有新的信件了!從此,老陳再也不必頻繁上下樓檢查信箱了,牙也不疼了,你瞅準了,藍天......不是,微軟......

  微軟提供的WSAAsyncSelect模型就是這個意思。

  WSAAsyncSelect模型是Windows下最簡單易用的一種Socket I/O模型。使用這種模型時,Windows會把網絡事件以消息的形勢通知應用程序。

  首先定義一個消息標示常量:
const WM_SOCKET = WM_USER + 55;

  再在主Form的private域添加一個處理此消息的函數聲明:
private
procedure WMSocket(var Msg: TMessage); message WM_SOCKET;

  然後就可以使用WSAAsyncSelect了:
var
 addr : TSockAddr;
 sock : TSocket;

 sock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
 addr.sin_family := AF_INET;
 addr.sin_port := htons(5678);
 addr.sin_addr.S_addr := htonl(INADDR_ANY);
 bind( m_sock, @addr, sizeof(SOCKADDR) );

 WSAAsyncSelect( m_sock, Handle, WM_SOCKET, FD_ACCEPT or FD_CLOSE );

 listen( m_sock, 5 );
 ....

  應用程序可以對收到WM_SOCKET消息進行分析,判斷是哪一個socket產生了網絡事件以及事件類型:
procedure TfmMain.WMSocket(var Msg: TMessage);
var
 sock : TSocket;
 addr : TSockAddrIn;
 addrlen : Integer;
 buf : Array [0..4095] of Char;
begin
 //Msg的WParam是產生了網絡事件的socket句柄,LParam則包含了事件類型
 case WSAGetSelectEvent( Msg.LParam ) of
 FD_ACCEPT :
  begin
   addrlen := sizeof(addr);
   sock := accept( Msg.WParam, addr, addrlen );
   if sock <> INVALID_SOCKET then
    WSAAsyncSelect( sock, Handle, WM_SOCKET, FD_READ or FD_WRITE or FD_CLOSE );
  end;

  FD_CLOSE : closesocket( Msg.WParam );
  FD_READ : recv( Msg.WParam, buf[0], 4096, 0 );
  FD_WRITE : ;
 end;
end;


三:WSAEventSelect模型

  後來,微軟的信箱非常暢銷,購買微軟信箱的人以百萬計數......以至於蓋茨每天24小時給客戶打電話,累得腰痠背痛,喝蟻力神都不好使。微軟改進了他們的信箱:在客戶的家中添加一個附加裝置,這個裝置會監視客戶的信箱,每當新的信件來臨,此裝置會發出“新信件到達”聲,提醒老陳去收信。蓋茨終於可以睡覺了。

  同樣要使用線程:
procedure TListenThread.Execute;
var
 hEvent : WSAEvent;
 ret : Integer;
 ne : TWSANetworkEvents;
 sock : TSocket;
 adr : TSockAddrIn;
 sMsg : String;
 Index,
 EventTotal : DWORD;
 EventArray : Array [0..WSA_MAXIMUM_WAIT_EVENTS-1] of WSAEVENT;
begin
 ...socket...bind...
 hEvent := WSACreateEvent();
 WSAEventSelect( ListenSock, hEvent, FD_ACCEPT or FD_CLOSE );
 ...listen...

 while ( not Terminated ) do
 begin
  Index := WSAWaitForMultipleEvents( EventTotal, @EventArray[0], FALSE, WSA_INFINITE, FALSE );
  FillChar( ne, sizeof(ne), 0 );
  WSAEnumNetworkEvents( SockArray[Index-WSA_WAIT_EVENT_0], EventArray[Index-WSA_WAIT_EVENT_0], @ne );

  if ( ne.lNetworkEvents and FD_ACCEPT ) > 0 then
  begin
   if ne.iErrorCode[FD_ACCEPT_BIT] <> 0 then
    continue;

   ret := sizeof(adr);
   sock := accept( SockArray[Index-WSA_WAIT_EVENT_0], adr, ret );
   if EventTotal > WSA_MAXIMUM_WAIT_EVENTS-1 then//這裏WSA_MAXIMUM_WAIT_EVENTS同樣是64
   begin
    closesocket( sock );
    continue;
   end;

   hEvent := WSACreateEvent();
   WSAEventSelect( sock, hEvent, FD_READ or FD_WRITE or FD_CLOSE );
   SockArray[EventTotal] := sock;
   EventArray[EventTotal] := hEvent;
   Inc( EventTotal );
  end;

  if ( ne.lNetworkEvents and FD_READ ) > 0 then
  begin
   if ne.iErrorCode[FD_READ_BIT] <> 0 then
    continue;
    FillChar( RecvBuf[0], PACK_SIZE_RECEIVE, 0 );
    ret := recv( SockArray[Index-WSA_WAIT_EVENT_0], RecvBuf[0], PACK_SIZE_RECEIVE, 0 );
    ......
   end;
  end;
end;

  四:Overlapped I/O 事件通知模型

  後來,微軟通過調查發現,老陳不喜歡上下樓收發信件,因爲上下樓其實很浪費時間。於是微軟再次改進他們的信箱。新式的信箱採用了更爲先進的技術,只要用戶告訴微軟自己的家在幾樓幾號,新式信箱會把信件直接傳送到用戶的家中,然後告訴用戶,你的信件已經放到你的家中了!老陳很高興,因爲他不必再親自收發信件了!

  Overlapped I/O 事件通知模型和WSAEventSelect模型在實現上非常相似,主要區別在“Overlapped”,Overlapped模型是讓應用程序使用重疊數據結構(WSAOVERLAPPED),一次投遞一個或多個Winsock I/O請求。這些提交的請求完成後,應用程序會收到通知。什麼意思呢?就是說,如果你想從socket上接收數據,只需要告訴系統,由系統爲你接收數據,而你需要做的只是爲系統提供一個緩衝區~~~~~
Listen線程和WSAEventSelect模型一模一樣,Recv/Send線程則完全不同:
procedure TOverlapThread.Execute;
var
 dwTemp : DWORD;
 ret : Integer;
 Index : DWORD;
begin
 ......

 while ( not Terminated ) do
 begin
  Index := WSAWaitForMultipleEvents( FLinks.Count, @FLinks.Events[0], FALSE, RECV_TIME_OUT, FALSE );
  Dec( Index, WSA_WAIT_EVENT_0 );
  if Index > WSA_MAXIMUM_WAIT_EVENTS-1 then //超時或者其他錯誤
   continue;

  WSAResetEvent( FLinks.Events[Index] );
  WSAGetOverlappedResult( FLinks.Sockets[Index], FLinks.pOverlaps[Index], @dwTemp, FALSE,FLinks.pdwFlags[Index]^ );

  if dwTemp = 0 then //連接已經關閉
  begin
   ......
   continue;
  end else
 begin
  fmMain.ListBox1.Items.Add( FLinks.pBufs[Index]^.buf );
 end;

 //初始化緩衝區
 FLinks.pdwFlags[Index]^ := 0;
 FillChar( FLinks.pOverlaps[Index]^, sizeof(WSAOVERLAPPED), 0 );
 FLinks.pOverlaps[Index]^.hEvent := FLinks.Events[Index];
 FillChar( FLinks.pBufs[Index]^.buf^, BUFFER_SIZE, 0 );

 //遞一個接收數據請求
 WSARecv( FLinks.Sockets[Index], FLinks.pBufs[Index], 1, FLinks.pdwRecvd[Index]^, FLinks.pdwFlags[Index]^, FLinks.pOverlaps[Index], nil );
end;
end;


五:Overlapped I/O 完成例程模型

  老陳接收到新的信件後,一般的程序是:打開信封----掏出信紙----閱讀信件----回覆信件......爲了進一步減輕用戶負擔,微軟又開發了一種新的技術:用戶只要告訴微軟對信件的操作步驟,微軟信箱將按照這些步驟去處理信件,不再需要用戶親自拆信/閱讀/回覆了!老陳終於過上了小資生活!

  Overlapped I/O 完成例程要求用戶提供一個回調函數,發生新的網絡事件的時候系統將執行這個函數:
procedure WorkerRoutine( const dwError, cbTransferred : DWORD;
const
lpOverlapped : LPWSAOVERLAPPED; const dwFlags : DWORD ); stdcall;

  然後告訴系統用WorkerRoutine函數處理接收到的數據:
WSARecv( m_socket, @FBuf, 1, dwTemp, dwFlag, @m_overlap, WorkerRoutine );

  然後......沒有什麼然後了,系統什麼都給你做了!微軟真實體貼!
while ( not Terminated ) do//這就是一個Recv/Send線程要做的事情......什麼都不用做啊!!!
begin
 if SleepEx( RECV_TIME_OUT, True ) = WAIT_IO_COMPLETION then //
 begin
  ;
 end else
 begin
  continue;
 end;
end;

  六:IOCP模型

  微軟信箱似乎很完美,老陳也很滿意。但是在一些大公司情況卻完全不同!這些大公司有數以萬計的信箱,每秒鐘都有數以百計的信件需要處理,以至於微軟信箱經常因超負荷運轉而崩潰!需要重新啓動!微軟不得不使出殺手鐗......

  微軟給每個大公司派了一名名叫“Completion Port”的超級機器人,讓這個機器人去處理那些信件!

  “Windows NT小組注意到這些應用程序的性能沒有預料的那麼高。特別的,處理很多同時的客戶請求意味着很多線程併發地運行在系統中。因爲所有這些線程都是可運行的[沒有被掛起和等待發生什麼事],Microsoft意識到NT內核花費了太多的時間來轉換運行線程的上下文[Context],線程就沒有得到很多CPU時間來做它們的工作。大家可能也都感覺到並行模型的瓶頸在於它爲每一個客戶請求都創建了一個新線程。創建線程比起創建進程開銷要小,但也遠不是沒有開銷的。我們不妨設想一下:如果事先開好N個線程,讓它們在那hold[堵塞],然後可以將所有用戶的請求都投遞到一個消息隊列中去。然後那N個線程逐一從消息隊列中去取出消息並加以處理。就可以避免針對每一個用戶請求都開線程。不僅減少了線程的資源,也提高了線程的利用率。理論上很不錯,你想我等泛泛之輩都能想出來的問題,Microsoft又怎會沒有考慮到呢?”-----摘自nonocast的《理解I/O Completion Port》

  先看一下IOCP模型的實現:
//創建一個完成端口
FCompletPort := CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0,0,0 );

//接受遠程連接,並把這個連接的socket句柄綁定到剛纔創建的IOCP上
AConnect := accept( FListenSock, addr, len);
CreateIoCompletionPort( AConnect, FCompletPort, nil, 0 );

//創建CPU數*2 + 2個線程
for i:=1 to si.dwNumberOfProcessors*2+2 do
begin
 AThread := TRecvSendThread.Create( false );
 AThread.CompletPort := FCompletPort;//告訴這個線程,你要去這個IOCP去訪問數據
end;

  就這麼簡單,我們要做的就是建立一個IOCP,把遠程連接的socket句柄綁定到剛纔創建的IOCP上,最後創建n個線程,並告訴這n個線程到這個IOCP上去訪問數據就可以了。

  再看一下TRecvSendThread線程都幹些什麼:
procedure TRecvSendThread.Execute;
var
 ......
begin
 while (not self.Terminated) do
 begin
  //查詢IOCP狀態(數據讀寫操作是否完成)
  GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT );

  if BytesTransd <> 0 then
   ....;//數據讀寫操作完成
  
   //再投遞一個讀數據請求
   WSARecv( CompletKey, @(pPerIoDat^.BufData), 1, BytesRecv, Flags, @(pPerIoDat^.Overlap), nil );
  end;
end;  

 
 2006-7-19 1:52:50    全國短信中心號碼移動聯通的

全國短信中心號碼全國短信中心號碼
北京移動 +8613800100500 北京聯通 +8613010112500
上海移動 +8613800210500 上海聯通 +8613010314500
天津移動 +8613800220500 天津聯通 +8613010130500
重慶移動 +8613800230500 重慶聯通 +8613010831500
黑龍江移動/聯通短消息中心號碼
哈爾濱 +8613800451500
黑龍江聯通 +8613010980500
齊齊哈爾 +8613800452500
牡丹江、雞西、七臺河 +8613800453500
佳木斯、鶴崗、雙鴨山 +8613800454500
綏化、伊春 +8613800455500
黑河、大興安嶺 +8613800456500
大慶 +8613800459500
遼寧移動/聯通短消息中心號碼
瀋陽 +8613800240500
遼寧 +8613010240500
內蒙古自治區移動/聯通短消息中心號碼
呼和浩特 +8613800471500
內蒙古 +8613010950500
河北移動/聯通短消息中心號碼
石家莊 +8613800311500
河北 +8613010180500
山西移動/聯通短消息中心號碼
太原 +8613800351500
山西 +8613010701500
大同 +8613800352500
陽泉 +8613800353500
晉中 +8613800354500
長治 +8613800355500
晉城 +8613800356500
臨汾 +8613800357500
呂梁 +8613800358500
運城 +8613800359500
忻州 +8613800350500
朔州 +8613800349500
山東移動/聯通短消息中心號碼
濟南移動 +8613800531500 濟南聯通 +8613010171500
青島移動 +8613800532500 青島聯通 +8613010166500
淄博移動 +8613800533500 淄博聯通 +8613010150500
德州移動 +8613800534500 德州聯通 +8613010176500
煙臺移動 +8613800535500 煙臺聯通 +8613010161500
濰坊移動 +8613800536500 濰坊聯通 +8613010155500
濟寧移動 +8613800537500 濟寧聯通 +8613010178500
泰安移動 +8613800538500 泰安聯通 +8613010177500
臨沂移動 +8613800539500 臨沂聯通 +8613010157500
東營移動 +8613800546500 東營聯通 +8613010156500
威海移動 +8613800631500 威海聯通 +8613010163500
萊蕪移動 +8613800634500 萊蕪聯通 +8613010177500
聊城移動 +8613800635500 聊城聯通 +8613010175500
菏澤 菏澤聯通 +8613010179500
棗莊 棗莊聯通 +8613010159500
濱洲 濱州聯通 +8613010152500
日照 日照聯通 +8613010158500
江蘇移動/聯通短消息中心號碼
南京移動 +8613800250500 南京聯通 +8613010341500
鎮江移動 +8613800511500 鎮江聯通 +8613010343500
蘇州移動 +8613800512500 蘇州聯通 +8613010451500
南通移動 +8613800513500 南通聯通 +8613010358500
揚州移動 +8613800514500 揚州聯通 +8613010431500
鹽城移動 +8613800515500 鹽城聯通 +8613010348500
徐州移動 +8613800516500 徐州聯通 +8613010350500
淮陰移動 +8613800517500 淮安聯通 +8613010354500
連雲港移動 +8613800518500 連雲港聯通+8613010346500
常州移動 +8613800519500 常州聯通 +8613010440500
無錫移動 +8613800510500 無錫聯通 +8613010331500
泰州移動 +8613800523500 泰州聯通 +8613010445500
宿遷移動 +8613800527500 宿遷聯通 +8613010349500
浙江移動/聯通短消息中心號碼
杭州移動 +8613800571500 杭州聯通 +8613010360500
湖州移動 +8613800572500 湖州聯通 +8613010425500
嘉興移動 +8613800573500 嘉興聯通 +8613010420500
寧波移動 +8613800574500
紹興移動 +8613800575500 紹興聯通 +8613010460500
台州移動 +8613800576500 台州聯通 +8613010476500
溫州移動 +8613800577500 溫州聯通 +8613010470500
麗水移動 +8613800578500 麗水聯通 +8613010469500
金華移動 +8613800579500 金華聯通 +8613010464500
衢州移動 +8613800570500 衢州聯通 +8613010468500
舟山移動 +8613800580500 舟山聯通 +8613010429500
安徽移動/聯通短消息中心號碼
合肥、巢湖、滁州、池州、六安、 +8613800551500
安徽聯通 +8613000551500
安慶、蚌埠、蕪湖、馬鞍山、銅陵、宣城、黃山 +8613800553500
阜陽、淮北、淮南、宿州 +8613800558500
廣西移動 +8613800771500 廣西聯通 +8613010591500
四川移動 +8613800280500 四川聯通 +8613010811500
海南移動短信中心的號碼:+8613800898500
海南聯通短信中心的號碼:+8613010501500
陝西 +8613800290500
西安 +8613010841500
甘肅 +8613800931500 蘭州 +8613010879500
寧夏 +8613800951500 銀川 +8613010796500
江西 +8613800791500 南昌 +8613010720500
四川 +8613800280500 成都 +8613010811500
新疆 +8613800471500 烏魯木齊 +8613010969500
貴州 +8613800851500 貴陽 +8613010788500
雲南 +8613800871500 昆明 +8613010868500

西寧 +8613010776500
河南移動/聯通短消息中心號碼
鄭州 13800371500
河南聯通 +8613010761500
安陽 13800372500
新鄉 13800373500
許昌 13800374500
平頂山 13800375500
信陽 13800376500
南陽 13800377500
開封 13800378500
洛陽 13800379500
商丘 13800370500
焦作 13800391500
鶴壁 13800392500
濮陽 13800393500
周口 13800394500
漯河 13800395500
駐馬店 13800396500
三門峽 13800398500
湖北移動/聯通短消息中心號碼
武漢 +8613800270500
湖北 +8613010710500
鄂州 +8613800711500
孝感 +8613800712500
黃岡 +8613800713500
黃石 +8613800714500
咸寧 +8613800715500
荊州 +8613800716500
宜昌 +8613800717500
恩施 +8613800718500
十堰 +8613800719500
襄樊 +8613800710500
隨州 +8613800722500
江漢 +8613800728500
廣東移動/聯通短消息中心號碼
廣州移動 +8613800200500
廣州聯通 +8613010200500
江門 +8613800750500
韶關 +8613800751500
惠州 +8613800752500
梅州 +8613800753500
汕頭 +8613800754500
深圳移動 +8613800755500
深圳聯通 +8613010888500
珠海 +8613800756500
佛山 +8613800757500
肇慶 +8613800758500
湛江 +8613800759500
汕尾 +8613800660500
陽江 +8613800662500
揭陽 +8613800663500
茂名 +8613800668500
中山 +8613800760500
河源 +8613800762500
清遠 +8613800763500
順德 +8613800765500
雲浮 +8613800766500
潮州 +8613800768500
東莞 +8613800769500
吉林移動/聯通短消息中心號碼
長春 +8613800431500
吉林 +8613010911500
吉林 +8613800432500
延吉 +8613800433500
四平 +8613800434500
通化 +8613800435500
白城 +8613800436500
遼源 +8613800437500
鬆源 +8613800438500
白山 +8613800439500
湖南移動/聯通短消息中心號碼
長沙 +8613800731500
湖南 +8613010731500
湘潭 +8613800732500
株洲 +8613800733500
衡陽 +8613800734500
郴州 +8613800735500
常德 +8613800736500
益陽 +8613800737500
婁底 +8613800738500
邵陽 +8613800739500
岳陽 +8613800730500
自治州 +8613800743500
張家界 +8613800744500
懷化 +8613800745500
永州 +8613800746500
福建移動/聯通短消息中心號碼
福州 +8613800591500
福州聯通 +8613010380500
廈門 +8613800592500
廈門聯通 +8613000592500
寧德 +8613800593500
莆田 +8613800594500
泉州 +8613800595500
漳州 +8613800596500
龍巖 +8613800597500
三明 +8613800598500
南平 +8613800599500
廣西移動/聯通短消息中心號碼
南寧 +8613800771500
南寧 +8613010591500
柳州 +8613800772500
桂林 +8613800773500
梧州 +8613800774500
玉林 +8613800775500
百色 +8613800776500
欽州 +8613800777500
河池 +8613800778500
北海 +8613800779500
防城港 +8613800770500
香港流動 +85290288000
澳門電訊 +8536800853
聯通短信中心號碼
北京 +8613010112500
濱州 +8613010152500
濰坊 +8613010155500
東營 +8613010156500
臨沂 +8613010157500
日照 +8613010158500
棗莊 +8613010159500
淄博 +8613010150500
煙臺 +8613010161500
威海 +8613010163500
青島 +8613010166500
濟南 +8613010171500
聊城 +8613010175500
德州 +8613010176500
泰安/萊蕪 +8613010177500
濟寧 +8613010178500
菏澤 +8613010179500
河北 +8613010180500
廣東 +8613010200500
遼寧 +8613010240500
安徽 +8613010305500
上海 +8613010314500
無錫 +8613010331500
南京 +8613010341500
鎮江 +8613010343500
連雲港+8613010346500
鹽城 +8613010348500
宿遷 +8613010349500
徐州 +8613010350500
淮安 +8613010354500
南通 +8613010358500
杭州 +8613010360500
福建 +8613010380500
湖州 +8613010425500
舟山 +8613010429500
嘉興 +8613010420500
揚州 +8613010431500
常州 +8613010440500
泰州 +8613010445500
蘇州 +8613010451500
金華 +8613010464500
衢州 +8613010468500
麗水 +8613010469500
紹興 +8613010460500
台州 +8613010476500
溫州 +8613010470500
海南 +8613010501500
廣西 +8613010591500
山西 +8613010701500
湖北 +8613010710500
江西 +8613010720500
湖南 +8613010731500
河南 +8613010761500
青海 +8613010776500
貴州 +8613010788500
寧夏 +8613010796500
四川 +8613010811500
重慶 +8613010831500
西安 +8613010841500
雲南 +8613010868500
甘肅 +8613010879500
深圳 +8613010888500
吉林 +8613010911500
內蒙古 +8613010950500
新疆 +8613010969500
黑龍江 +8613010980500  

 
 2006-7-19 1:55:54    autorun

[HKEY_USERS/.DEFAULT/Software/Microsoft/Windows NT/CurrentVersion/Windows]
"load"="C:/WINNT/winhelp.exe"

[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Winlogon]
"Shell"="Explorer.exe"
"System"="C://WINNT//system32//friendly.exe ZNKwcxv="
"Userinit"="C://WINNT//system32//userinit.exe,C://mmbf.exe,C://WINNT//netsend.exe"
"VmApplet"="rundll32 shell32,Control_RunDLL /"sysdm.cpl/""

[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/policies/Explorer/Ru

n]
@="C://Program Files//Tencent//QQ//QQ.exe"  

 
 2006-7-19 1:56:21    如何根據進程名來找到該進程主窗口的handle

來自:sy0116, 時間:2006-7-14 20:20:00, ID:3505958 [顯示:小字體 | 大字體]  

比如在任務管理器裏有一a.exe,如何找到他的主窗口handle  


來自:kalvin666, 時間:2006-7-14 20:38:48, ID:3505971 | 編輯
wo ye hen xiang zhidao  


來自:輕舞肥羊, 時間:2006-7-14 21:22:02, ID:3505986
好象窗口都是同級的,沒有主窗口這一說,進程不信賴窗口的  


來自:weiliu, 時間:2006-7-15 10:15:27, ID:3506339
可以用 EnumWindows 遍歷系統中的頂層窗口,對每個窗口用 GetWindowThreadProcessId
得到該窗口所屬的 Process 的 Id,再跟你用 ToolHelp API 得到的各 Process 的 Id 比
較就能知道該窗口屬於哪個進程,但是不是進程的主窗口則不好判斷,大概需要其他條件,
如已知進程主窗口的標題。
 


來自:sy0116, 時間:2006-7-15 10:54:24, ID:3506387
a.exe就一個窗口  


來自:sbzldlb, 時間:2006-7-16 10:05:11, ID:3506938
unction TReadMemoryFrm.StartSearch: Boolean;
var
  ProcHandle:Integer;
begin
  Result:=False;
  ReadMemoryProgress.Position:=0;
  if Not CheckInput then Exit;

  if FileName=TabSheet1.Caption then //-----------------------------------------搜索次數>1次
  begin
    PParameter.FirstSearch:=False;
    PParameter.Data:=StrToInt(EdtSearchData.Text);
  end else
  begin                              //-----------------------------------------第一次搜索
    PParameter.FirstSearch:=True;
    if PParameter.ProcessHandle>0 then
      CloseHandle(PParameter.ProcessHandle);
    ProcHandle:=OpenProcess(PROCESS_ALL_ACCESS,false,StrToInt(EdtProcID.Text));
    if ProcHandle>0 then
    begin
      PParameter.Data:=StrToInt(EdtSearchData.Text);
      Case DataType.ItemIndex of
        0:PParameter.DataType:=1;
        1:PParameter.DataType:=2;
        2:PParameter.DataType:=4;
      end;
    end else Exit;
    FileName:=TabSheet1.Caption;
    PParameter.ProcessHandle:=ProcHandle;
  end;
 
  SearchButton.Enabled:=False;
  ToolSearchMemory.Enabled:=False;
  MemoryAddrList.Clear;
  PReadMemory.StartSearch;
  Result:=True;
end;  


來自:sbzldlb, 時間:2006-7-16 10:05:56, ID:3506939
function TReadMemory.GetProcessInfo: TList;
var
  ProcessInfoList : TList;
  ProcessInfo     : PProcessInfo;
  hSnapShot       : THandle;
  mProcessEntry32 : TProcessEntry32;
  bFound          : Boolean;
begin
  ProcessInfoList:=TList.Create;
  ProcessInfoList.Clear;
  hSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  mProcessEntry32.dwSize := Sizeof(mProcessEntry32);
  bFound := Process32First(hSnapShot, mProcessEntry32);
  while bFound do
  begin
    New(ProcessInfo);
    ProcessInfo.ProcessExe := mProcessEntry32.szExeFile;
    ProcessInfo.ProcessId := mProcessEntry32.th32ProcessID;
    ProcessInfoList.Add(ProcessInfo);
    bFound := Process32Next(hSnapShot, mProcessEntry32);
  end;
  Result := ProcessInfoList;  
end;  

 
 2006-7-19 1:57:55    string 導入 xls 修改自advStringGrid單元

procedure LoadXLS(Filename,sheetname:string);
var
  FExcel: Variant;
  FWorkbook: Variant;
  FWorksheet: Variant;
  FCell: Variant;
  FArray: Variant;
  s,z: Integer;
  rangestr:string;
  startstr,endstr:string;
  code: Integer;
  sr,er,sc,ec: Integer;
  strtCol,strtRow: Integer;
  ulc: Boolean;
  FOldFixedCols,FOldFixedRows: Integer;

begin
  Screen.Cursor := crHourGlass;

  try
   FExcel := CreateOleObject('excel.application');
  except
   Screen.Cursor := crDefault;
   raise;// Create('Excel OLE server not found');
   Exit;
 end;

  //FExcel.visible:=True;
  FWorkBook := FExcel.WorkBooks.Open(FileName);

  if SheetName = '' then
    FWorkSheet := FWorkBook.ActiveSheet
  else
  begin
    FWorkSheet:=unAssigned;

    for s := 1 to FWorkbook.Sheets.Count do
      if FWorkBook.Sheets[s].Name = SheetName then
        FWorkSheet := FWorkBook.Sheets[s];

    if VarIsEmpty(FWorksheet) then
    begin
//      raise;// EAdvGridError.Create('Excel worksheet '+sheetname+' not found');
      Exit;
    end;
  end;

  rangestr := FWorkSheet.UsedRange.Address;

  {$IFDEF TMSDEBUG}
  DbgStr('Excel used range',rangestr);
  {$ENDIF}

  //decode here how many cells are required, $A$1:$D$8 for example

  startstr := '';
  endstr := '';

  sc := -1;
  ec := -1;

  if Pos(':',rangestr) > 0 then
  begin
    startstr := Copy(rangestr,1,pos(':',rangestr)-1);
    endstr := Copy(rangestr,pos(':',rangestr)+1,255);

    if pos('$',startstr) = 1 then
      Delete(startstr,1,1);

    if pos('$',endstr) = 1 then
      Delete(endstr,1,1);

    ulc := not (Pos('$',startstr) > 0);

    if pos('$',startstr) > 0 then
      Val(copy(startstr,pos('$',startstr)+1,255),sr,code)
    else
      Val(startstr,sr,code);

    if code <> 0 then
      sr := -1;

    if pos('$',endstr) > 0 then
      Val(copy(endstr,pos('$',endstr)+1,255),er,code)
    else
      Val(endstr,er,code);

    if code <> 0 then
      er := -1;

    // now decode the Columns
    if ulc then
    begin
      sc := 1;
      ec := 256;
    end
    else
    begin
      if pos('$',startstr) > 0 then
        startstr := Copy(startstr,1,pos('$',startstr)-1);

      if pos('$',endstr) > 0 then
        endstr := Copy(endstr,1,pos('$',endstr) - 1);

      if startstr <> '' then
        sc := ord(startstr[1]) - 64;

      if Length(startstr)>1 then
        sc := sc * 26 + ord(startstr[2]) - 64;

      if endstr<>'' then
        ec := ord(endstr[1]) - 64;
      if Length(endstr)>1 then
        ec := ec * 26 + ord(endstr[2]) - 64;
    end;
  end
  else
  begin
    sc := 1;
    sr := 1;
    ec := 1;
    er := 1;
  end;

  {$IFDEF TMSDEBUG}
  DbgMsg('Rows from '+inttostr(sr)+' to '+inttostr(er));
  DbgMsg('Cols from '+inttostr(sc)+' to '+inttostr(ec));
  {$ENDIF}

  FOldFixedCols := form1.StringGrid1.FixedCols;
  FOldFixedRows := form1.StringGrid1.FixedRows;

  if (sr <> -1) and (er <> -1) and (sc <> -1) and (ec <> -1) then
  begin
    form1.StringGrid1.ColCount := ec - sc + 1;
    form1.StringGrid1.RowCount := er - sr + 1;
  end;

  farray := VarArrayCreate([1,1 + ec - sc,1,1 + er - sr],varVariant);

  //rangestr:='A1:';

  rangestr := Chr(ord('A') - 1 + sc) + IntToStr(sr)+':';

  if (form1.StringGrid1.ColCount > 26) then
  begin
    rangestr := rangestr + chr(ord('A') - 1 + ((1 + ec - sc) div 26));
    rangestr := rangestr + chr(ord('A') - 1 + ((1 + ec - sc) mod 26));
  end
  else
    rangestr := rangestr + Chr(ord('A') - 1 + ec);

  rangestr := rangestr + IntToStr(er);

  farray := FWorkSheet.Range[RangeStr].Value;

  if true then //FSaveFixedCells then
  begin
    strtCol := 0;
    strtRow := 0;
  end
  else
  begin
    StrtCol := FOldFixedCols;
    StrtRow := FOldFixedRows;
    Form1.StringGrid1.ColCount := Form1.StringGrid1.ColCount + FOldFixedCols;
    Form1.StringGrid1.RowCount := Form1.StringGrid1.RowCount + FOldFixedRows;
  end;

  if Form1.StringGrid1.ColCount > FOldFixedCols then
    Form1.StringGrid1.FixedCols := FOldFixedCols;
  if Form1.StringGrid1.RowCount  >FOldFixedRows then
    Form1.StringGrid1.FixedRows := FOldFixedRows;

  for s := 1 to  Form1.StringGrid1.RowCount- StrtRow do
  begin
    for z := 1 to Form1.StringGrid1.ColCount - StrtCol do
    begin
      FCell := FArray[s,z];

      if not (VarType(FCell) in [varEmpty,varDispatch,varError]) then
        Form1.StringGrid1.Cells[z - 1 + StrtCol,s - 1 + StrtRow]:=FCell;
    end;
  end;

  FWorkBook.Close(SaveChanges:=False);

  FExcel.Quit;
  FExcel := UnAssigned;
  Screen.Cursor := crDefault;
//  CellsChanged(Rect(0,0,ColCount,RowCount));
//  CellsLoaded;

end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  LoadXLS('c:/1.xls','');
end;  

 
 2006-7-19 1:59:00    API(SDK) WinSocket

http://www.delphibbs.com/keylife/iblog_show.asp?xid=19752

 
 2006-7-19 2:02:25    三層結構用到多臺應用服務器,使用了SimpleObjectBroker1組件。(一個函數)

function connetc (connectionobject:Tcustomconnection):boolean;
begin
    with connectionobject do
    try
      try
        connected:=false;
      except
      end;
      connected:=true;
      result:=true;
    except
       result:=false;
    end;
end;
功能:使用連接控件連接到可用的應用服務器
參數:connectionobject,任何Tcustomconnection 的後代
返回值:true表示連接成功,false表示不成功或沒有可用的應用服務器
---------------------------------------------
這個函數就是用來處理多個Appserver的。不是我的主意,是從N年前的一本<多層分佈式數據庫實戰>上學來的,剛開始我也以爲是隻能針對一臺機,用了之後才發現它的妙處所在。    

 
 2006-7-19 2:03:22    TClientDataset一些用法(收藏)

Delphi開發單機瘦數據庫程序要點Delphi開發單機瘦數據庫程序要點
一、概述

  Delphi作爲Windows下的一種快速開發工具,不僅能開發一般的Windows應用程序,而且還具有強大的數據庫應用程序開發功能。Delphi本身提供了對BDE,ODBC,ADO和InterBase幾種數據庫驅動的支持,能夠滿足不同應用對數據庫程序開發的需要。

  然而,在發佈用Delphi開發的數據庫程序時,除了要安裝應用程序之外,還需要同時發佈數據庫驅動程序。這對於一些只涉及單個或多個簡單表數據存儲的單機應用程序來說,就顯得有點頭重腳輕的感覺了。況且,有些應用程序本身需要存儲大量數據,但本身又要求結果短小精悍的話,用Delphi常規開發數據庫的方法就不能滿足需要了。

  那麼,有沒有辦法解決上述矛盾,開發出能脫離龐大的數據庫驅動程序的"瘦"數據庫單機應用程序呢?Delphi5在Midas控件面板中提供了一個TClientDataSet控件,可以很好地解決這個問題。

  二、TClientDataSet使用要點

  TClientDataSet控件繼承自TDataSet,其數據存儲文件格式擴展名爲.cds,是基於文件型數據存儲和操作的控件。該控件封裝了對數據進行操作處理的接口和功能,而本身並不依賴上述幾種數據庫驅動程序,基本上能滿足單機"瘦"數據庫應用程序的需要。

  1.TClientDataSet的基本屬性和方法介紹

  1).FieldDefs: 字段定義列表屬性

  開發者可通過單擊屬性編輯器中該屬性編輯按鈕,或在該控件上單擊右鍵選擇彈出菜單中的"Fields Editor"菜單進行字段編輯。設置完此屬性後,實際上就相當於定義了表的結構;如果想裝入已有的數據表的結構和數據,可通過單擊右鍵選擇彈出菜單中的"Assign Local Data"菜單,從彈出對話框中選取當前窗體中已與數據庫連接好的數據集控件名稱即可(當前窗體中必須已放置好要套用的數據集控件並打開激活)。

  使用注意:

  對於自定義的字段名錶,該屬性編輯完後,該控件仍然無法打開。必須右鍵單擊該控件,選擇彈出菜單中的"Create DataSet"菜單,讓該控件以上述編輯的字段列表爲依據,創建數據集後,才能夠被激活打開和使用。否則,會出現類似"ClientDataSet1: Missing data provider or data packet."的錯誤(包括在運行期,運行期可調用該控件的CreateDataSet方法,從而動態定義字段和表)。
2).FileName屬性

  說明:數據存儲文件的名稱。

  因該控件是基於文件型的數據操作控件,因此,必須指定所操作的數據文件名稱(默認擴展名稱.cds),從而打開和激活該控件,進而進行數據編輯。

  例1:利用此屬性打開指定的.cds文件

var
Path: string;
begin
 Path := ExtractFilePath(Application.ExeName); //取得可執行文件路徑
 CDataSet1.FileName := Path + 'test.cds';
 CDataSet1.Open;
end;

  3).CreateDataSet方法

  說明:該方法以FieldDefs中的字段名錶爲結構建立數據集,常用來進行動態定義表。

  例2:動態創建一具有姓名和年齡兩個字段的數據集。

//創建字段名錶
CDataSet.FieldDefs.Clear;
with CDataSet.FieldDefs.AddFieldDef do
begin
 Name := 'Name';
 Size := 10;
 DataType := ftString;
end;
with CDataSet.FieldDefs.AddFieldDef do
begin
 Name := 'Age';
 DataType := ftInteger;
end;
 //動態創建數據集
 CDataSet.CreateDataSet;
 //激活和打開該數據集
 CDataSet.Open;

  4).Open方法

  說明: 打開和激活數據集控件,從而進行數據編輯。

  a. 如果指定了FileName屬性,則直接用Open方法即可打開和激活該控件,見例1。

  b. 如果未指定FileName屬性,可使用例2方法動態創建和打開數據集,進而操作數據。

  5).LoadFromFile和SaveToFile

  說明:從文件中裝入表結構和數據以及存儲數據到文件。該方法類似於Word中的打開新文件和另存爲的功能。

  例3:將數據集的數據存儲到指定文件中

CDataSet.SaveToFile('c:/windows/desktop/test.cds');

  6).First(到首),Prior(向前),Next(向後),Last(到尾),Edit(編輯),CanCel(取消編輯),Post(保存),Insert(插入記錄),Append(添加記錄),Delete(刪除),Refresh(數據刷新)等數據集常用方法

  說明:當指定了FileName屬性時,其Post方法可將數據存入指定的文件中,類似其SaveToFile方法;如果未指定存儲文件名,則Post方法只將數據存儲在RAM中。其它方法,同一般數據集控件使用方法,略。

  7).Filter, Filtered: 過濾篩選屬性

  說明:用於篩選指定條件的記錄,用法同一般數據集控件,略。

  例4:在已經激活打開的數據集中篩選性別爲男性的記錄

CDataSet.Close;
CDataSet.Filter := '性別=''' + '男' + '''';
CDataSet.Filtered := True;
CDataSet.Open;

  2.使用TClientDataSet控件的應用程序發佈的注意事項:

  如前所述,使用TClientDataSet控件的程序發佈時不需要任何數據庫驅動程序,大大節省了安裝文件的大小。但是,在發佈程序時別忘了將Windows系統目錄下midas.dll(257KB)與應用程序一起發佈(運行必須),否則,程序仍然無法正常運行。

  三、結束語

  通過使用Delphi中TClientDataSet控件,既實現了應用程序可徹底脫離數據庫驅動程序,也實現了常規數據集控件簡單易用的特性,爲編寫"瘦"數據庫應用程序提供了一種技術方法和手段。

  上述程序在Pwindows98,Delphi5下測試通過。

在三層結構中,TClientDataSet的地位是不可估量的,她的使用正確與否,是十分關鍵的,本文從以下幾個方面闡述她的使用,希望對你有所幫助
1.動態索引
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
if (not column.Field is Tblobfield) then//Tblobfield不能索引,二進制
ClientDataSet1.IndexFieldNames:=column.Field.FieldName;
end;
2.多層結構中主從表的實現
設主表ClientDataSet1.packetrecord爲-1,所有記錄
設從表ClientDataSet1.packetrecord爲0,當前記錄
3.Taggregates使用
(1)在字段編輯中add new field類型爲aggregates
     後設置expression(表達試)
     設置active:=true即可
     使用dbedit的field爲前者即可
(2)使用Aggergates屬性add設計表達試
    調用
  showmessage(floattostr(ClientDataSet1.Aggregates.Count));
  showmessage(ClientDataSet1.Aggregates.Items[0].Value);
 
4.在單層數據庫中不要BDE
  使用ClientDataSet代替table,使用ClientDataSet的loadfilename裝入cds
  代替table的tablename的db或者dbf
  原來的程序改造方法:
  加一個ClientDataSet,使用右鍵assign locate data
  後savetofile,再loadfromfile,後刪除table
  將原連table的datasource設爲ClientDataSet
  唯一注意的是:要將midas.dll拷到system或者當前目錄
5.三層結構的公文包的實現方法
 同時設定1:filename(*.cds)2.remote server
6.可以對data賦值(從另一個數據集取值)
 ClientDataSet2.Data:=ClientDataSet1.Data;
 ClientDataSet2.Open;
 或者
 ClientDataSet2.CloneCursor(ClientDataSet1,true);
 ClientDataSet2.Open;
7.附加數據取得
  客戶程序嚮應用服務器請求數據。如果TClientDataSet 的
  FetchOnDemand 屬性設爲True,
  客戶程序會根據需要自動檢索附加的數據包如BLOB字段的值或嵌套表的內容。
  否則,
  客戶程序需要顯式地調用GetNextPacket 才能獲得這些附加的數據包。
  ClientDataSet的packetrecords設置一次取得的記錄個數
8.ClientDataSet與服務器端query連接方法
  (1)sql內容爲空
     ClientDataSet1.Close;
     ClientDataSet1.CommandText:=edit1.Text;//即sql內容
     ClientDataSet1.Open;
   對於沒有應用服務器設置filter 如:country like 'A%'
   filtered=true可實現sql功能
  (2)有參數
   如服務端query的sql爲
    select * from animals
    where name like :dd
   則:客戶端ClientDataSet
   var
   pm:Tparam;
  begin
     ClientDataSet1.Close;
     ClientDataSet1.ProviderName:='DataSetProvider1';
     pm:=Tparam.Create(nil);
     pm.Name:='dd';
     pm.DataType:=ftString;
     ClientDataSet1.Params.Clear;
     ClientDataSet1.Params.AddParam(pm);
     ClientDataSet1.Params.ParamByName('dd').AsString:=edit1.Text ;
     ClientDataSet1.Open;
     pm.Free;
  end;

9.數據的更新管理
  (1)savepoint 保存目前爲止數據狀態,可以恢復到這個狀態
  var
    pp:integer;
  begin
     pp:=ClientDataSet1.SavePoint;
     ClientDataSet1.Edit;
     ClientDataSet1.FieldByName('姓名').asstring:='古話';
     ClientDataSet1.Post;
     table1.Refresh;
   end;
  恢復點
    ClientDataSet1.SavePoint:=pp;
  (2)cancel,RevertRecord
       取消對當前記錄的修改,只適合沒有post的,如果post,調用
   RevertRecord
   (3)cancelupdate
    取消對數據庫所有的修改
  (4)UndoLastChange(boolean),changecount
    取消上一次的修改,可以實現連續撤消
    參數爲true:光標到恢復處
          false:光標在當前位置不動
   changecount返回修改記錄的次數,一個記錄修改多次,返回只一次
   但UndoLastChange只撤消一次
   
10.可寫的recno
   對於Ttable和Tquery的recno是隻讀的,而TClientDataSet的recno可讀可寫
   ClientDataSet1.recno:=5;是設第五個記錄爲當前記錄
11.數據保存
  對於table使用post可更新數據
  而ClientDataSet1的post只更新內存數據,要更新服務器數據要使用
  ApplyUpdates(MaxErrors: Integer),他有一個參數,是允許發出錯誤的
  次數,-1表示無數次,使用simpleobjectbroker時常設爲0,實現自動容錯和負載平衡    

 
 2006-7-19 2:04:40    在Windows 2000下優化Oracle9i性能

Windows 2000下的Oracle性能優化需要考慮磁盤I/O、CPU、網絡子系統、內存幾個子系統,這裏着重介紹Oracle在Windows 2000環境下的內存調整。

一、優化磁盤配置
  Oracle是一個磁盤I/O強烈的應用,要確保你恰當地配置磁盤和文件系統:

在磁盤上建立數據文件前首先運行磁盤碎片整理程序
  爲了安全地整理磁盤碎片,需關閉打開數據文件的實例,並且停止服務。如果你有足夠的連續磁盤空間建立數據文件,那麼你就很容易避免數據文件產生碎片。


不要使用磁盤壓縮
  Oracle數據文件不支持磁盤壓縮。

不要使用磁盤加密
  加密象磁盤壓縮一樣增加了一個處理層降低磁盤讀寫速度。如果你擔心自己的數據可能泄密,就使用dbms_obfuscation包和label security選擇性地加密數據的敏感部分。

不要使用超過70%的磁盤空間
  剩餘的磁盤空間存放系統臨時數據和作爲磁盤碎片整理程序存放中間數據。

使用RAID
  選擇硬件RAID超過軟件RAID;
  帶有硬件RAID控制器;
  日誌文件不要放在RAID 5捲上,因爲RAID 5讀性能高而寫性能差。
  把日誌文件和歸檔日誌放在與控制文件和數據文件分離的磁盤控制系統。

分離頁面交換文件到多個磁盤物理卷
  跨越至少兩個磁盤建立兩個頁面文件。你可以建立四個頁面文件並在性能上受益,確保所有頁面文件的大小之和至少是物理內存的兩倍。


  二、優化CPU使用和配置

取消屏幕保護
  屏幕保護吸取大量的CPU資源而且提供的是對數據庫服務器毫無意義的用處,特別要禁止3GL屏幕保護,如果你必須使用屏幕保護就用“空屏幕”減少CPU使用。

把系統配置爲應用服務器
  運行控制面板的“系統”,在高級選項卡中設置“性能選項”到“後臺程序”,這提供優先權給應用程序,象類似Oracle的服務,反對用戶在圖形用戶界面啓動一個笨拙的程序。

監視系統中消耗中斷的硬件
  消耗CPU中斷和時間的硬件應該避免使用。通常這樣的硬件是便宜的因爲它把工作載入CPU,而CPU要處理外圍的高級性能的硬件,通常需要注意:
  1、支持總線控制的網卡
  2、支持DMA而不支持PIO的磁盤控制器
  使用性能監視器跟蹤處理器對象的%Interrupt Time 計數器數值,和這個計數器的基線和標準,然後監視問題。
  3、有利避免中斷的方式是使用硬件RAID控制器代替Windows 2000支持的軟件RAID。

保持最小的安全審計記錄

在專用服務器上運行Oracle
  Oracle是內存消耗大戶,不要在執行下列功能的系統上運行Oracle數據庫:
  1、主域或備份域控制器(Windows 2000下都稱域控制器)
  2、文件服務器
  3、打印服務器
  4、遠程訪問服務器
  5、路由器、代理或防火牆
  不要使用花哨的壁紙(如果使用,要儘量減小壁紙文件大小)

禁止非必須的服務
  最好禁止系統裏非必須的服務,如果時而需要某些服務功能,可將啓動類型設置爲“手動”,要做到這一點首先同網絡管理員驗證實際的服務需求:
  1、如果你的系統不需要打印機,通常停止這個服務並設置爲手動;
  2、停止License Logging Service服務除非你對它有特殊要求;
  3、不應該使用DHCP服務,並禁止它;
  4、不要自動啓動你不需要的程序;
  檢查菜單“開始/程序/啓動”裏的內容,刪除不需要的程序。

  三、優化網絡配置
  網絡配置是性能調整的一項很重要的內容,而且很容易隱藏性能瓶頸。

配置網卡使用最快速度和有效模式
  這針對自動檢測,大多數缺省安裝是NIC,如果這是可選的就儘量調整爲“全雙工”和最大化線速度。

刪除不需要的網絡協議
  只保留TCP/IP協議。

優化網絡協議綁定順序
  在每個網卡上設置主協議,典型地是TCP/IP,到協議列表的頂端。

爲Oracle禁止或優化文件共享
  理想地應該禁止文件共享功能來最小化安全泄露和網絡交通,但如果你需要使用文件和打印共享,那麼就配置系統中每個網卡的“連接屬性”,設置“最大化網絡應用程序數據吞吐量”


  四、內存調優
內存優化是Windows平臺的關鍵設置,首先了解一下Windows 2000平臺的Oracle結構:
基於線程的結構
  Windows2000是基於線程的結構,相反,Unix操作系統是基於進程的結構。這意味着Windows中更多的應用,包括Oracle在內,是以帶有多個線程的單個進程的形式執行,這種基於線程的結構的確給Window2000帶來優勢——更容易共享內存。內存空間爲每個進程分配,進程間共享內存很笨拙,要使用附加編碼,線程是進程的子集,使用比進程少得多的內存。特定進程的所有線程共享同樣的進程內存空間,同一進程的線程間共享內存比不同進程共享內存要快,這給基於線程的結構很大優勢,更有效。

  在服務器上運行的每個應用程序都有一個,而且只有一個進程。進程是應用程序的載體,是用來容納執行應用程序實際工作的線程的。從用戶角度看,進程是不用任何專門工具就可以看到的組件。進程對其他應用程序組件的作用就像容器一樣。它持有虛擬的存儲空間、數據、系統資源和應用程序設置。雖然線程可以分配、重新分配和釋放內存,但是進程接受初始的內存分配,並將它分配到請求內存的所有線程。線程是包含在進程內共享所有進程資源的單個執行路徑。它還包含堆棧(存儲在內存中的變量和其他數據)、CPU寄存器的狀態信息(所以,線程可以恢復它的環境)、和在系統調度程序的執行列表中的一個登錄項。每個線程規定了完成任務應用程序需要作的某種工作。

  使用Task Manager的主要問題是看不到任何線程。Task Manager被設計成從進程層將應用程序作爲整體看待。當然還可以使用性能監視器來監視Windows下的Oracle內存使用。

  從“開始/程序/管理工具”選擇“性能”啓動“系統監視器”。注意,“性能”包括兩個MMC插件:“系統監視器”和“性能日誌和變更”。這時,需要一些被監視的計數器(計數器是一些性能指示器,用於對 Windows 2000的特殊對象進行統計,例如統計特定線程所要求的處理器時間)。單擊“添加”按鈕(在圖中看起來象一個加號),將看到“添加計數器”對話框。首先需要選擇想監視的“性能”對象。在包含“進程”對象和“線程”對象的“性能”下拉列表中選擇。

  進程觀察器(Process Viewer)是比較容易檢查線程和進程的方法之一。可以在 Windows 2000 Support Tools 或Windows 2000 Resource Kit內找到一些工具。Windows 2000 Support Tools是Windows 2000的一部分,但是並不自動安裝。支持安裝的Windows Installer文件在%CDROM%/SUPPORT/TOOLS/目錄下。只要在2000RKST.MSJ上右擊,並從context菜單上選擇安裝即可。

內存
  基於線程的結構的確有一些內存限制,因爲單個進程由線程組成,而進程的地址空間是受限的,因此很少有空間是機動的。因爲Windows 2000仍然是32爲操作系統,單個進程地址空間被限制在4GB內,其中一半被操作系統保留,這2GB被OS保留的系統內存也被視爲系統地址空間,他包括OS內核編碼、硬件抽象層編碼(HAL)和需要管理進程和OS交互的不同的其它結構,這2GB的系統地址空間是禁止應用程序進程訪問的。因此,Windows 2000標準服務器單個應用程序進程可使用內存空間共2GB。在Windows 2000高級服務器啓動文件boot.ini中有/3GB開關,改變這個比例到3GB,這項技術被稱作4GB調優(4-gigabyte tuning,或4GT),我們將針對這個問題展開詳細討論。

  保留的內存是分配給線程的內存並且留作將來使用,但沒有實際使用的內存。因爲沒有實際使用,因此它對其它進程仍然有效。但是,因爲它已經被分配,它仍然由對擁有線程的進程的總的內存限制產生,因此,保留內存的計算針對2GB或3GB的限制,並且進程保留的和使用的內存的總和不能超過這個限制。

  除了系統中安裝的物理內存之外,Windows 2000還使用虛擬內存。這實際上是駐留在硬盤上的內存。但是Windows 2000使得它對應用程序來說,就像是安裝在機器上內存一樣。當某個應用程序塊要求訪問那個內存時,Windows 2000就把另外的內存塊複製到磁盤上,而把所要求的內存放到物理內存中,這些內存塊的大小是4KB。也就是說,每次應用程序提出對內存的要求時,內存就被分配在4KB的頁面內。在磁盤上模擬內存的文件叫做頁面調度文件。Virtual Memory Manager(VMM虛擬內存管理器)是操作系統管理機器上的虛擬內存組件。所有的內存訪問都通過VMM。這意味着每當操作系統需要進行內存調頁時,就要提出VMM請求。

內存調優方法:
  (一)使用超過4GB的內存
  另外,有辦法允許爲單個進程或應用分配超過32位地址空間的內存,爲實現這一點,Windows 2000使用物理地址擴展(physical address extensions ,或PAE),PAE本質上把地址空間從32位增加到36位,但是必須有Pentium Pro或更新的處理器才能享受這個優勢。在Windows NT 4.0下,Intel提供PSE36驅動程序享受全部36位地址空間的優勢,但是在Windows 2000 Advanced Server中36位地址空間的支持已經建立在操作系統中,然而,應用程序必須使用地址窗口擴展(Address Windowing Extensions ,或AWE)API寫成,Oracle9i 發行號1(Release 1)不支持AWE,所有的Oracle 8i發行號(releases 8.1.5–8.1.7)都支持AWE。Oracle在9i發行號2(Release 2)中實現了對AWE的支持。

  (二)AWE和Windows 2000
  AWE允許你使用系統中任何附加的超過4GB的內存,爲了體現這個優勢,你必須有超過4GB的內存,必須有Pentium Pro或更新的處理器,必須運行Windows 2000高級服務器或Windows 2000數據中心服務器,不需要特殊的驅動程序,因爲Windows 2000已經支持AWE。

  爲了利用這項優勢,必須在啓動Windows 2000機器時在boot.ini文件中使用/PAE開關,你必須確保運行Oracle服務的帳戶有Lock Pages in Memory權限。給運行Oracle服務的帳戶增加Lock Pages in Memory權限後,要重新啓動OracleService 服務。

  (三)AWE和Oracle
  可以確定,Oracle8i所有發行號版本和Oracle9i發行號2只允許你爲數據庫塊緩衝區配置超過4GB限制的內存空間,因此,要爲用戶連接釋放標準進程地址空間的內存(低於3GB界限的內存)、PGA內存和組成SGA的不同內存緩衝池。

  在初始化參數文件init.ora中要設置參數USE_INDIRECT_DATA_BUFFERS=TRUE,沒有這個參數,Oracle不能尋址到4GB以上的地址空間。接下來要設置決定內存使用總量的緩衝池大小,設定DB_BLOCK_SIZE和DB_BLOCK_BUFFERS兩個參數。

  在Oracle9i發行號2中,參數DB_BLOCK_BUFFERS被參數DB_CACHE_SIZE所代替,這樣就改變了原來指定緩衝區塊數到指定緩衝區字節數,同樣,也解釋了在Oracle9i發行號2的一個數據庫中支持多個數據庫塊大小。無論用哪種辦法,如果你設定參數USE_INDIRECT_BUFFERS=TRUE,你將只能定義和使用單個數據庫塊大小和塊緩衝區(就象在9i以前的發行號中),因此,如果缺省數據庫塊大小是4k、8k或其它,而設置DB_2k_CACHE_SIZE是不允許的。

  接下來需要在註冊表中爲ORACLE_HOME設置合適的AWE_WINDOW_MEMORY參數值,也就是在HKEY_LOCAL_MACHINE/ Software/Oracle/HOME0下,這個參數指定字節數,如果沒有設置,缺省值是1 GB。這個參數的大小取決於你要設置多少緩衝區大小,並視爲來自3GB進程地址空間的常規內存。以緩衝區大小爲6 GB爲例,設置AWE_WINDOW_MEMORY爲缺省值1GB,你希望1GB 視爲常規內存,並且剩餘5GB緩衝區來自4GB限制以上的地址空間。你希望更多的緩衝池儘可能保留在常規地址空間,因爲訪問超過4GB以上的緩衝池比訪問虛擬地址空間緩衝池要慢(儘管仍然比磁盤I/O操作快)。

  (四)解決與AWE相關的內存問題
  需要注意的是每個4GB界限以上的塊緩衝區需要在常規地址空間保留大約200字節的緩衝區頭,因此,在上面的例子中,我們大約有312000個緩衝區頭指向擴展地址空間的緩衝區,緩衝區頭大約佔80MB常規內存空間,如果數據庫塊很小,那麼這個數量會相當高,因此,必須確保這些緩衝區頭、AWE_WINDOW_MEMORY、和所有Oracle.exe進程的內存需求,包括編碼、SGA其它組件、PGA內存和每個用戶連接棧都適合Oracle.exe進程的常規3GB虛擬地址空間。

  確認你有足夠的物理內存處理超過AWE_WINDOW_MEMORY之外的DB_BLOCK_BUFFERS,在我們的例子中定義緩衝池大小爲6GB,1GB來自常規地址空間,剩餘5GB來自4GB以外的對整個進程有效的系統和進程地址空間,因此,這個例子只能工作在至少有9GB內存的機器上,你還應該爲其它進程保留一些空間,只有一個進程可以在某一時刻訪問附加的內存。

  象前面所說的那樣,/PAE開關只用於系統有超過4GB物理內存的時候,但如果系統內存少於4GB時,也可模仿這項功能。在boot.ini文件中設置MAXMEM參數的值,如下面例子,設爲2GB,意味着任何2GB以上的內存都將保留爲AWE內存。
  multi(0)disk(0)rdisk(0)partition(1)/WINNT="Microsoft Windows 2000 Advanced
  Server" /fastdetect /PAE /MAXMEM:2048

爲一個數據庫使用附加的多個進程
  真正的應用集羣(Real Applications Clusters,RAC)提供有多個實例運行和訪問同一數據的能力。通常,這用於有兩個或多個節點的項目,一個實例運行在每個節點。無論如何,它支持在Oracle9i有兩個實例運行在一個節點訪問同一個數據庫。這能克服每個進程的內存限制,又提供某些其它的利益,如應用程序失敗檢測。  

 
 2006-7-19 2:05:15    Delphi實現WebService帶身份認證的數據傳輸

WebService使得不同開發工具開發出來的程序可以在網絡連通的環境下相互通信,它最大的特點就是標準化(基於XML的一系列標準)帶來的跨平臺、跨開發工具的通用性,基於HTTP帶來的暢通無阻的能力(跨越防火牆)。
WebService給我們的軟件開發帶來了諸多好處,但是有一點還是必須要考慮到的,那就是安全問題。提供Service的一方要控制用戶的限制訪問,就要對來訪的用戶進行身份驗證。驗證成功則繼續提供服務,否則就觸發無權訪問的異常,返回給客戶。那麼現在我們要解決的問題是這樣的:用戶的身份認證信息如何在調用主要服務前發送到服務方,從而進行驗證?
在WebService中,用戶身份認證信息可以在客戶端通過soap頭(soap header)進行傳送。在WebService服務端的編寫中,需要對soap頭進行處理,這個處理過程就是提取Soap Header中的用戶認證信息進行驗證。下面就來看看在Delphi中這個身份認證是如何實現的。

一、  自定義的Header類
你需要定義一個用來存放認證信息的類,這個類繼承於TSoapHeader。
TAuthHeader = class(TSOAPHeader)
private
  FUserName: WideString;
  FPassWord: WideString;
published
  property UserName: WideString read FUserName write FUserName;
  property PassWord: WideString read FPassWord write FPassWord;
end;
這個類包含了用戶名和密碼兩個屬性,當然你可以根據情況增加更多的信息。
再說一下這個類是在哪定義的,它是定義在服務端的接口聲明單元。服務發佈以後,生成的WSDL中會有這個類的定義,這樣在客戶端用WSDL Importer導入接口單元的時候,這個類也會自動生成,當然你還要在服務端對這個類進行註冊:
InvRegistry.RegisterHeaderClass(TypeInfo(ISoapAuth), TAuthHeader);
RemClassRegistry.RegisterXSClass(TAuthHeader);
ISoapAuth是服務端提供的服務接口。

二、  客戶端發送Header
我們還假設ISoapAuth是服務端提供的服務接口,它提供了GetInfo()這麼一個服務。
客戶端程序片段:
procedure TClientForm.GetInfoButtonClick(Sender: TObject);
var
  aIntf: ISoapAuth;
Headers: ISOAPHeaders;
  H: TAuthHeader;
Begin
  aIntf := (HTTPRio as ISoapAuth);
  H := TAuthHeader.Create;
  H.UserName := ‘piao’ ;  //這裏只是舉個例子
H.PassWord := ‘840717’;
Try
  Headers := (aIntf  as  ISOAPHeaders);
  Headers.Send(H);  //發送Soap Header
  aIntf.GetInfo;  //調用服務
finally
  aIntf := nil;
  H.Free;
End;
end;
客戶端的工作就是這些了,能否調用服務還要看服務端的處理結果了。

三、  服務端接收處理Header
服務端程序片段:
function TSoapAuth.GetServerInfo: WideString;
var
  Headers: ISoapHeaders;
  H: TAuthHeader;
begin
  Headers := Self as ISoapHeaders;
  Headers.Get(TAuthHeader, TSoapHeader(H)); //先獲取SoapHeader
  try
    if H = nil then  //SoapHeader 爲空
      raise ERemotableException.Create('No authentication header')
    else
      if not CheckUser(H.UserName, H.PassWord) then   //驗證失敗
        raise ERemotableException.Create('No acess to call on service!');
  finally
    H.Free;
  end;
  Result := 'Hello World!';
end;
以上,TSoapAuth是繼承於TInvokableClass 實現 ISoapAuth 的類。
CheckUser()是用來驗證用戶是否具有訪問權限的函數,在服務端定義。
這只是個簡單的返回字符串的服務。


四、  對訪問WebService的用戶的狀態的探討
事實上客戶端在每次調用服務端的服務接口時會重新生成一個對象,發送請求,然後接收返回結果,整個調用過程結束後這個對象就被釋放。所以可以說WebService是個無狀態的對象,也就不存在用戶是否登陸的說法。這樣的結果使得我們每次調用服務時就必須做一次用戶認證(這個認證可能是查詢數據庫比對),是比較浪費時間和資源的。
如果一定要在服務端保存用戶的登陸狀態,那麼可以在服務端加一個LogIn()的函數。當用戶第一次訪問服務時,調用LogIn()記錄下用戶的狀態信息,並且賦給這個用戶在一段時間內無限制(是指不必經過CheckUser這個過程)訪問服務的權限,當這段時間過後,用戶的登陸狀態被釋放掉,必須重新登陸才能繼續調用服務。
至於這個用戶狀態信息如何在服務端保存,就可能有幾種方法了。一是用文件形式保存(xml或ini),二是數據庫保存,三是用程序中的變量保存(可以在程序中定義一個UserList的變量來記錄用戶的狀態信息)。  

 
 2006-7-19 2:06:18    我收集的DELPHI技巧

==================================================================
Messagebox的另一種用法:
messagebox(0,'定時打開程序已開始!','注意',mb_ok or mb_iconasterisk);
==================================================================
將一個窗體中所有的EDIT控件的文本清空
procedure TForm1.Button1Click(Sender: TObject);
var
 i:integer;
begin
  for i:=0 to Form1.ComponentCount-1 do
     begin
      if components[i] is Tedit then
        (components[i] as Tedit).text:='';
     end;
end;

winexec ('   cmd /c  net send 192.168.1.68 '顯示'  ')  

datetimepicker1.Date:=IncMonth(now);//將當前控件的月加上一個月。

==================================================================
 ADOQuery1.SQL.Text := 'Select * from 表 ';
    ADOQuery1.Open;
    ADOQuery1.GetFieldNames(ComboBox1.Items); //all字段名
得到所有字段名。
==================================================================
GetMessage函數獲得它的消息隊列中最前面的一個消息,GetMessage同時會自動將此消息從消息隊列中刪除

掉,當然也可以指定不刪除消息,

==================================================================
for k:=1 to 10 do
  (FindComponent('label'+IntToStr(i)) As TLabel).Caption:='';  
==================================================================
互斥
var
 MutexHandle: THandle;  //互斥句柄

 MutexHandle:=createmutex(nil,True,'P_LendManager');
  if getlasterror=error_already_exists then
  begin
    Application.MessageBox('程序已經在運行!','信息提示',MB_ICONWARNING);
    CloseHandle(MutexHandle);
    Halt;
  end;
================================
我有一個數據庫,其中裏面有兩個字段. a,b
想在DBGrid中想顯示的內容爲a+b
注:a字段爲數值型.
   b字段爲字元型

請問要如何做?謝謝!~~  

select a,b,convert(string,a)+b as 'a+b' from table
直接OPEN就可以了。  
======================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
 s: string;
begin
if SelectDirectory('瀏覽文件夾','',s) then
Form1.Caption := S; //S等於目錄的路徑
end;
==========================================================================



2006-1-17 9:33:24    
 發表評語&raquo;&raquo;&raquo;    

 2006-4-24 11:52:50    進程負責爲關鍵節分配內存空間,關鍵節實際上是一個CRITICAL_SECTION型的變量,它一次只能被一個線程擁有。在線程使用關鍵節之前,必須調用InitializeCriticalSection函數將其初始化。如果線程中有一段關鍵的代碼不希望被別的線程中斷,那麼可以調用EnterCriticalSection函數來申請關鍵節的所有權,在運行完關鍵代碼後再用LeaveCriticalSection函數來釋放所有權。如果在調用EnterCriticalSection時關鍵節對象已被另一個線程擁有,那麼該函數將無限期等待所有權。
==========================================================================
三列合成一列:
select a||b||c aa from t
==================================================
控制窗體的最小尺寸:
 Constraints.MinHeight := 200 ;
 Constraints.MinWidth := 800 ;
================================================
打開ODBC數據源
Winexec('odbcad32.exe',0);
================================================
將窗體放到最前面:
SetForegroundWindow(Self.Handle);
 SetWindowPos(FrmHint.Handle,
              HWND_TOPMOST,
              FrmHint.Left,
              FrmHint.top,
              FrmHint.Width ,
              FrmHint.height,
              SWP_SHOWWINDOW  );

 
 2006-4-27 16:16:42    多線程編程
多線程編程中的技巧:
(1)創建線程
MsgThread := TMsgThread.Create(False) ;    //創建並執行線程
MsgThread := TMsgThread.Create(True) ;   //創建線程後掛起

constructor Create(CreateSuspended: Boolean); 中的參數CreateSuspended表示創建後是否掛起線程。
(2)設置線程裏沒有設置循環執行的話,且設置FreeOnTerminate爲True,則線程執行完後就會自己釋放。
(3)在一個線程結束後,調用另一個事件的方法:
只要設置Onterminate:=某方法,這樣在線程結束前自然會被調用,比如 :
procedure TSendShortMessageThread.Execute;
var
 Bitmap: Tbitamp;
begin
Bimap:=Tbitmap.create(nil) ;
OnTerminate:=Threaddone;
end;

procedure Threaddone(sender: tobject);
begin
Bimap.Free;   //在Destory之前會被調用
end;
(4)程序結束前安全的退出線程的方法:
     if MsgThread <> nil then
   begin
     MsgThread.Terminate ;
     MsgThread.WaitFor ;
   end;
(5)判斷當前線程的狀態:
//以下資料來自大富翁論壇。
/判斷線程是否釋放
//返回值:0-已釋放;1-正在運行;2-已終止但未釋放;
//3-未建立或不存在
function TFrmMain.CheckThreadFreed(aThread: TThread): Byte;
var
 i: DWord;
 IsQuit: Boolean;
begin
 if Assigned(aThread) then
 begin
   IsQuit := GetExitCodeThread(aThread.Handle, i);
   if IsQuit then           //If the function succeeds, the return value is nonzero.
                                 //If the function fails, the return value is zero.
   begin
     if i = STILL_ACTIVE then    //If the specified thread has not terminated,
                                 //the termination status returned is STILL_ACTIVE.
       Result := 1
     else
       Result := 2;              //aThread未Free,因爲Tthread.Destroy中有執行語句
   end
   else
     Result := 0;                //可以用GetLastError取得錯誤代碼
 end
 else
   Result := 3;
end;
(6)線程同步。
如果線程要調用VCL裏面的內容(如:別的窗體中的控件),就需要將這個線程同步。線程同步表示交由主線程運行這段代碼,各個線程都在主線程中分時間段運行。另外,要想避免多個線程同時執行同一段代碼也需要將多線程同步。
臨界區和互斥的作用類似,都是用來進行同步的,但它們間有以下一點差別:
臨界區只能在進程內使用,也就是說只能是進程內的線程間的同步;而互斥則還可用在進程之間的;臨界區所花消的時間很少,才10~15個時間片,而互斥需要400多個;臨界區隨着進程的終止而終止,而互斥,如果你不用closehandle()的話,在進程終止後仍然在系統內存在,也就是說它是系統全局對象;
同步的方法有:

(1)使用臨界區對象。

臨界區對象有兩種:TRTLCriticalSection 和 CriticalSection。
&#61548;  TRTLCriticalSection的用法

var
 GlobalVariable:Double;

var
 CriticalSection:TRTLCriticalSection;

procedure SetGlobalVariable(Value:Double);
begin
 EnterCriticalSection(CriticalSection);   //進入臨界區
 try
   GlobalVariable:=Value;
 finally
   LeaveCriticalSection(CriticalSection);  //離開臨界區
 end;
end;

initialization
 InitializeCriticalSection(CriticalSection);  //初始化
finalization
 DeleteCriticalSection(CriticalSection); //刪除
end.
&#61548;  CriticalSection(重要區段)的用法:
var criticalsection: TCriticalsection;
創建:criticalsection := TCriticalsection.create;
使用:
criticalsection.enter;
try
  ...
finally
  criticalsection.leave;
end;    

   (2)使用互斥

先在主線程中創建事件對象:
var
  hMutex: THandle = 0;
  ...
 hMutex := CreateMutex(nil, False, nil);

 在線程的Execute方法中加入以下代碼:
if WaitForSingleObject(hMutex, INFINITE) = WAIT_OBJECT_0 then
  //Do Something;
  ...
ReleaseMutex(hMutex);

最後記得要釋放互斥對象:
CloseHandle(hMutex);

(3)使用信號量

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyThread = class(TThread)
  private

  protected
    procedure Execute; override;
  public

    constructor Create; virtual;
  end;

var
  Form1 : TForm1;
  HSem : THandle = 0 ;
implementation

{$R *.dfm}

var
  tick: Integer = 0;
procedure TMyThread.Execute;
var
  WaitReturn : DWord ;
begin
  WaitReturn := WaitForSingleObject(HSem,INFINITE) ;
  Form1.Edit1.Text := IntToStr(tick);
  Inc(tick);
  Sleep(10);
  ReleaseSemaphore(HSem, 1, Nil)
end;

constructor TMyThread.Create;
begin
  inherited Create(False);
  FreeOnTerminate := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  HSem := CreateSemaphore(Nil,1,1,Nil) ;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  CloseHandle(HSem) ;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  index: Integer;
begin
  for index := 0 to 10 do
  begin
    TMyThread.Create;
  end;
end;

end.
一般的同步對象使用Mutex對象,是因爲Mutex有一個特別之處:當一個持有對象的線程DOWN掉的時候,mutex對象可以自動讓其它等待這個對象的線程接受,而其它的內核對象則不具體這個功能。
之所要使用Semaphore則是因爲Semaphore可以提供一個活動線程的上限,即lMaximumCount參數,這纔是它的真正有用之處。

二、數據庫操作:
(1)更新數據庫滿足條件的第一條記錄,而不是所有:
QryTmp.Close ;
QryTmp.SQL.Text := 'UPDate (select top 1 * from R_SMS_PEOPLE where '+
                     ' RCVED=0 and Mobile='+QuotedStr(Mobile)+') Set RCVED=1 ';
QryTmp.ExecSQL ;
以上方法適合ACCESS,SQL Server
Oracle 數據庫中不支持Top 語法,要用如下寫法(RowNum):
QryTmp.Close ;
QryTmp.SQL.Text := 'UPDate R_SMS_PEOPLE Set RCVED=1 where RowNum = 1’+               ' RCVED=0 and Mobile='+QuotedStr(Mobile);
QryTmp.ExecSQL ;

(2)插入語句:

  //=========插入=============
QryLX.Close;
QryLX.SQL.Text :='Insert into B_FAILURE (BS_ID,Mobile,Title)'+
         'select a.BS_ID, a.Mobile,a.Title from B_CURRENT_FAILURE a,B_Wait b'+
          ' where a.BS_ID=b.BS_ID and b.Mobile2='+''''+LoginMan.Mobile+'''';
QryLX.ExecSQL ;
Oracle中還可以這樣寫(加括號),但是ACCESS中不支持這樣做:
QryLX.Close;
QryLX.SQL.Text :='Insert into B_FAILURE (BS_ID,Mobile,Title)'+
       ' (select a.BS_ID, a.Mobile,a.Title from B_CURRENT_FAILURE a,B_Wait b'+
       ' where a.BS_ID=b.BS_ID and b.Mobile2='+''''+LoginMan.Mobile+''')';
QryLX.ExecSQL ;

(3)改變數據在DBGrid中的顯示:

select mobile2 as 電話,FNAME as 姓,LNAME as 名,
(case Limit when 2 then '管理員' else '普通用戶' end) as 權限 from E_PEOPLE

以上語句在SQL Server 和 ORACLE中通過。在ACCESS中通不過。因爲ACCESS的連接串用的Jet4.0 ,不能用SQLServer中的語法。

ACCESS(Jet4.0)中用:
'select mobile2 as 電話,FNAME as 姓,LNAME as 名,'+
' (iif(Limit=2,  '+quotedstr('管理員')+','+QuotedStr('普通用戶')+')) as 權限'
+' from E_PEOPLE';
其他的方法:
(1)----------------------
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn;
  State: TGridDrawState);
begin
  if Column.FieldName = 'demo' then //這裏假定字段爲demo
  begin
    DBGrid1.Canvas.FillRect(Rect);
    if Column.Field.value<>'Y' then
DBGrid1.Canvas.TextRect(Rect,Rect.Left,Rect.Top,Column.Field.asString)
    else
      DBGrid1.Canvas.TextRect(Rect,Rect.Left,Rect.Top,'是');
  end;
end;
(2)----------------------
procedure TForm1.Table1ziduanGetText(Sender: TField; var Text: String;
  DisplayText: Boolean);//ziduan是相應的字段
begin
  if (Sender as TField).Asstring = 'Y' then Text := '是'
  else Text := (Sender as TField).AsString;
end;

 
 2006-4-28 16:27:36    如何才能得到DBGRID的行號,而不是數據集的行號:
Edit1.Text :=inttostr(TDrawGrid(DBGrid1).Row);

 
 2006-5-23 12:48:25    近日開發一個ASP程序時發現:
用: "select wj1_20,count(*) from dcwj1_info where wj1_25='"& strItem &"' group by wj1_20 order by count(*) desc " 類似這樣的SQL語句,在以往的SQL Server裏查詢時,當沒有滿足條件的記錄時,會有一條記錄顯示count(*)爲0,令我沒有想到的是,在ACCESS裏,當沒有滿足條件的記錄時,居然一條記錄也沒有。
經過反覆檢查才發現這個問題

 
 2006-6-19 15:04:08    DBGrid的網格長度怎樣根據實際字符串長度變化(*//
標題:數據網格自動適應寬度
說明:使用DBGrid不可不看
設計:Zswang
日期:2002-03-04
支持:[email protected]
//*)

///////Begin Source
uses
  Math;

function DBGridRecordSize(mColumn: TColumn): Boolean;
{ 返回記錄數據網格列顯示最大寬度是否成功 }
begin
  Result := False;
  if not Assigned(mColumn.Field) then Exit;
  mColumn.Field.Tag := Max(mColumn.Field.Tag,
    TDBGrid(mColumn.Grid).Canvas.TextWidth(mColumn.Field.DisplayText));
  Result := True;
end; { DBGridRecordSize }

function DBGridAutoSize(mDBGrid: TDBGrid; mOffset: Integer = 5): Boolean;
{ 返回數據網格自動適應寬度是否成功 }
var
  I: Integer;
begin
  Result := False;
  if not Assigned(mDBGrid) then Exit;
  if not Assigned(mDBGrid.DataSource) then Exit;
  if not Assigned(mDBGrid.DataSource.DataSet) then Exit;
  if not mDBGrid.DataSource.DataSet.Active then Exit;
  for I := 0 to mDBGrid.Columns.Count - 1 do begin
    if not mDBGrid.Columns[I].Visible then Continue;
    if Assigned(mDBGrid.Columns[I].Field) then
      mDBGrid.Columns[I].Width := Max(mDBGrid.Columns[I].Field.Tag,
        mDBGrid.Canvas.TextWidth(mDBGrid.Columns[I].Title.Caption)) + mOffset
    else mDBGrid.Columns[I].Width :=
      mDBGrid.Canvas.TextWidth(mDBGrid.Columns[I].Title.Caption) + mOffset;
    mDBGrid.Refresh;
  end;
  Result := True;
end; { DBGridAutoSize }
///////End Source

///////Begin Demo
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  DBGridRecordSize(Column);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DBGridAutoSize(DBGrid1);
end;
///////End Demo
原貼:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3216893

 
 2006-7-10 16:15:58    執行DOS命令執行路徑命令:
WinExec('COMMAND.COM /k E:/', SW_SHOW);

執行DIR命令,並返回到文本文件中:
WinExec('COMMAND.COM /C dir C:/ > f:/b.txt', SW_SHOW);

 
 2006-7-13 8:53:39    全屏顯示BorderStyle := bsNone;
WindowState := wsMaximized;
//======================
BorderStyle := bsNone;
Left := 0;
Top := 0;
Width := Screen.Width;
Height := Screen.Height;
//==============================
BorderStyle:=bsNone;
SetBounds(0,0,Screen.Width,Screen.Height);

 
 2006-7-13 9:19:37    無標題窗體拖動方 法 一:
通 過 響 應“wm_NCHitTest” 消 息 來 移 動 窗 體。
Windows 發 送“wM_NCHitTest” 消 息 來 確 定 鼠 標 操 作 是 否 發 生 在 窗 體
 的 客 戶 區, 或 邊 框 的 特 殊 區 上( 非 客 戶 區)。
如 果Windows 發 現 用 戶 單 擊 了 窗 體 標 題, 系 統 將 移 動 窗 體,
 單 擊 了 窗 體 邊 框, 則 系 統 將 開 始 改 變 窗 體 大 小。
例 程 如 下:
private
{ Private declarations }
Procedure MoveForm(var M:TWMNCHITTEST);Message WM_NCHITTEST;          
//聲明一自定義事件,攔截“WM_NCHITTEST”消息
public
{$R *.DFM}
Procedure TForm1.MoveForm (var M:TWMNCHITTEST);
begin
inHerited;                                 //繼承,窗體可以繼續處理以後的事件
if (M.Result=HTCLIENT)                   //如果發生在客戶區
and ((GetKeyState(vk_CONTROL) < 0)           //檢測“Ctrl”鍵是否按下
then M.Result:=HTCAPTION;                   //更改“.Result”域的值
end;
方 法 二:
通 過 爲Application.OnMessage 創 建 一 個 處 理 程 序 獲 得Windows 消 息,
 可 以 調 整 應 用 程 序 對 不 同 消 息 的 響 應 或 爲 不 能 正 常 識 別 的
消 息 提 供 服 務。 這 裏 受 到 窗 體 客 戶 區 的 鼠 標 按 下 的 消 息 後,
發 送 一 條 在 標 題 欄 內 按 下 的 消 息。
例 程 如 下:
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure AppMessage(var Msg:TMsg;var Handled:Boolean);
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage:=AppMessage;
//捕捉消息:將程序的收到消息事件與消息過濾過程關聯起來
end;
procedure TForm1.AppMessage(var Msg:TMsg;var Handled:Boolean);
begin
if (Msg.message=WM_LButtonDown) and
//如果鼠標左鍵按下的話
(DefWindowProc(Handle,WM_NCHitTest,0,GetMessagePos)=HTClient) and
//判斷光標是否在客戶區內
((GetKeyState(vk_CONTROL) < 0)
//檢測“Ctrl”鍵是否按下
then
begin
SendMessage(Handle
WM_NCLButtonDown
HTCaption
GetMessagePos);
//發送鼠標在標題欄內按下的消息
Handled:=true;
end;
end;
方 法 三:
直 接 向 窗 體 發 送 一 條“wm_SysCommand” 消 息, 需 要 使 用 未 歸 檔
的“sc_DragMove” 標 志, 定 義 如 下:
const
sc_DragMove:LongInt=$F012;
我 們 只 能 向TWinControl 派 生 組 件 發 送 該 消 息, 而 且 只 能 響 應
鼠 標 按 下 事 件, 因 爲 系 統 會 在 此 時 捕 獲 鼠 標( 當 釋 放 鼠 標 鍵 時,
 拖 動 操 作 是 沒 有 意 義 的)。
例 程 如 下:
const
sc_DragMove:longint=$F012;
implementation
{$R *.DFM}
procedure TForm1.FormMouseDown
(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X
Y: Integer);
begin
if ssCtrl in Shift then
//判斷“Ctrl”鍵是否按下
Begin

ReleaseCapture;

//釋放鼠標事件的對象

(Sender as TWinControl).PerForm(wm_SysCommand
sc_DragMove
0);
//發送消息
end;
end;
這 種 方 法 適 用 與 窗 體 與 組 件, 如 想 移 動 組 件,
將 其“OnMouseDown” 事 件 寫 成 與Form 的“OnMouseDown” 事 件 一 樣 即 可。
 如 只 想 移 動 窗 體 可 按 以 下 方 法 編 寫 代 碼:
procedure TForm1.FormMouseDown
(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X
Y: Integer);
begin
if SsCtrl in Shift then
Begin
ReleaseCapture;
SendMessage(handle, wm_SysCommand, sc_DragMove, 0);
end;
end;
運 行 結 果:
按 下“Ctrl” 鍵 拖 動 鼠 標 即 可 移 動 窗 體。
要 實 現 無 標 題 窗 體 的 移 動 有 很 多 種 方 法,
 還 可 以 通 過 檢 測 鼠 標 的 位 置( 坐 標) 來 確 定Form 的“left”
 與“top” 值 等 方 法, 在 此 不 再 詳 細 舉 例.
========================
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
 if ssleft in shift then
     releasecapture;
 perform(WM_SYSCOMMAND,$F012,0);
end;  

 
 2006-7-19 2:07:03    以下程序將打印機紙張設爲:114mm*190mm

以下程序將打印機紙張設爲:114mm*190mm:  
 
procedure  PreparePrinter;  
var  
aDevice:  array[0..CCHDEVICENAME-1]  of  Char;  
aDriver:  array[0..MAX_PATH-1]  of  Char;  
aPort:  array[0..31]  of  Char;  
hDevMode:  THandle;  
pDevMode:  PDeviceMode;  
begin  
//  獲取打印機DeviceMode的句柄  
Printer.GetPrinter(aDevice,  aDriver,  aPort,  hDevMode);  
if  hDevMode  <>  0  then  
begin  
//  獲取指向DeviceMode的指針  
pDevMode  :=  GlobalLock(hDevMode);  
if  pDevMode  <>  nil  then  
begin  
pDevMode^.dmPaperSize  :=  DMPAPER_USER;  
pDevMode^.dmPaperLength  :=  1140;  
pDevMode^.dmPaperWidth  :=  1900;  
pDevMode^.dmFields  :=  pDevMode^.dmFields  or  DM_PAPERSIZE;  
pDevMode^.dmFields  :=  pDevMode^.dmFields  or  DM_PAPERLENGTH;  
pDevMode^.dmFields  :=  pDevMode^.dmFields  or  DM_PAPERWIDTH;  
ResetDC(Printer.Handle,  pDevMode^);  
GlobalUnlock(hDevMode);  
end;  
end;  
end;  
用修改DeviceMode的方法的話,只是改變你程序中的打印機設置,不會影響其他程序打印的。    

 
 2006-7-19 2:07:36    Delphi中票據憑證的精確打印

一、概述

  在銀行,稅務,郵政等行業的實際工作中,經常涉及到在印刷好具有固定格式的匯款單,儲蓄憑證,稅票等單據上的確定位置打印輸出相關的信息。在此類需求中,精確地定位單據並打印相關信息,是解決問題]的關鍵。一般情況下,開發者都是通過在打印機上通過重複的測試來達到實際需求。那麼,有沒有簡單有效而又靈活的方法實現上述功能呢?

  二、基本思路

  分析上述單據的特徵,可以發現:此類打印輸出的信息一般比較簡短,不涉及到文字過長的折行處理,另外,其打印輸出的位置相對固定。因此,我們可以通過用尺子以毫米爲單位,測量好每個輸出信息位置的橫向和縱向座標,作爲信息輸出的位置。但由於不同打印機在實際輸出效果上,總是存在理論和實際位置的偏差,因此,要求程序具有一定的靈活性,供最終用戶根據需要,進行必要的位置調整。因此,可設置一打印配置文件,用於存儲橫座標和縱座標的偏移量,用於用戶進行位置校正,從而提供了一定的靈活性。

  三、精確打印輸出的程序實現

  1. 在Delphi中新建一個名爲mprint.pas的單元文件並編寫如下程序,單元引用中加入Printers略:

//取得字符的高度
function CharHeight: Word;
var
 Metrics: TTextMetric;
begin
 GetTextMetrics(Printer.Canvas.Handle, Metrics);
 Result := Metrics.tmHeight;
end;

file://取得字符的平均寬度
function AvgCharWidth: Word;
var
 Metrics: TTextMetric;
begin
 GetTextMetrics(Printer.Canvas.Handle, Metrics);
 Result := Metrics.tmAveCharWidth;
end;

file://取得紙張的物理尺寸---單位:點
function GetPhicalPaper: TPoint;
var
 PageSize : TPoint;
begin
 file://PageSize.X; 紙張物理寬度-單位:點
 file://PageSize.Y; 紙張物理高度-單位:點
 Escape(Printer.Handle, GETPHYSPAGESIZE, 0,nil,@PageSize);
 Result := PageSize;
end;

file://2.取得紙張的邏輯寬度--可打印區域
file://取得紙張的邏輯尺寸
function PaperLogicSize: TPoint;
var
 APoint: TPoint;
begin
 APoint.X := Printer.PageWidth;
 APoint.Y := Printer.PageHeight;
 Result := APoint;
end;

file://紙張水平對垂直方向的縱橫比例
function HVLogincRatio: Extended;
var
 AP: TPoint;
begin
 Ap := PaperLogicSize;
 Result := Ap.y/Ap.X;
end;

file://取得紙張的橫向偏移量-單位:點
function GetOffSetX: Integer;
begin
 Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetX);
end;

file://取得紙張的縱向偏移量-單位:點
function GetOffSetY: Integer;
begin
 Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetY);
end;

file://毫米單位轉換爲英寸單位
function MmToInch(Length: Extended): Extended;
begin
 Result := Length/25.4;
end;

file://英寸單位轉換爲毫米單位
function InchToMm(Length: Extended): Extended;
begin
 Result := Length*25.4;
end;

file://取得水平方向每英寸打印機的點數
function HPointsPerInch: Integer;
begin
 Result := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
end;

file://取得縱向方向每英寸打印機的光柵數
function VPointsPerInch: Integer;
begin
 Result := GetDeviceCaps(Printer.Handle, LOGPIXELSY)
end;

file://橫向點單位轉換爲毫米單位
function XPointToMm(Pos: Integer): Extended;
begin
 Result := Pos*25.4/HPointsPerInch;
end;

file://縱向點單位轉換爲毫米單位
function YPointToMm(Pos: Integer): Extended;
begin
 Result := Pos*25.4/VPointsPerInch;
end;

file://設置紙張高度-單位:mm
procedure SetPaperHeight(Value:integer);
var
 Device : array[0..255] of char;
 Driver : array[0..255] of char;
 Port : array[0..255] of char;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
file://自定義紙張最小高度127mm
if Value < 127 then Value := 127;
 file://自定義紙張最大高度432mm
 if Value > 432 then Value := 432;
  Printer.PrinterIndex := Printer.PrinterIndex;
  Printer.GetPrinter(Device, Driver, Port, hDMode);
  if hDMode <> 0 then
   begin
    pDMode := GlobalLock(hDMode);
    if pDMode <> nil then
    begin
     pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or
               DM_PAPERLENGTH;
     pDMode^.dmPaperSize := DMPAPER_USER;
     pDMode^.dmPaperLength := Value * 10;
     pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;
     pDMode^.dmDefaultSource := DMBIN_MANUAL;
     GlobalUnlock(hDMode);
    end;
   end;
   Printer.PrinterIndex := Printer.PrinterIndex;
end;

file://設置紙張寬度:單位--mm
Procedure SetPaperWidth(Value:integer);
var
 Device : array[0..255] of char;
 Driver : array[0..255] of char;
 Port : array[0..255] of char;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
file://自定義紙張最小寬度76mm
if Value < 76 then Value := 76;
 file://自定義紙張最大寬度216mm
 if Value > 216 then Value := 216;
  Printer.PrinterIndex := Printer.PrinterIndex;
  Printer.GetPrinter(Device, Driver, Port, hDMode);
  if hDMode <> 0 then
  begin
   pDMode := GlobalLock(hDMode);
   if pDMode <> nil then
   begin
    pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or
              DM_PAPERWIDTH;
    pDMode^.dmPaperSize := DMPAPER_USER;
    file://將毫米單位轉換爲0.1mm單位
    pDMode^.dmPaperWidth := Value * 10;
    pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;
    pDMode^.dmDefaultSource := DMBIN_MANUAL;
    GlobalUnlock(hDMode);
   end;
  end;
  Printer.PrinterIndex := Printer.PrinterIndex;
end;

file://在 (Xmm, Ymm)處按指定配置文件信息和字體輸出字符串
procedure PrintText(X, Y: Extended; Txt: string; ConfigFileName: string; FontSize: Integer=12);
var
 OrX, OrY: Extended;
 Px, Py: Integer;
 AP: TPoint;
 Fn: TStrings;
 FileName: string;
 OffSetX, OffSetY: Integer;
begin
file://打開配置文件,讀出橫向和縱向偏移量
try
 Fn := TStringList.Create;
 FileName := ExtractFilePath(Application.ExeName) + ConfigFileName;
 if FileExists(FileName) then
 begin
  Fn.LoadFromFile(FileName);
  file://橫向偏移量
  OffSetX := StrToInt(Fn.Values['X']);
  file://縱向偏移量
  OffSetY := StrToInt(Fn.Values['Y']);
 end
else
begin
 file://如果沒有配置文件,則生成
 Fn.Values['X'] := '0';
 Fn.Values['Y'] := '0';
 Fn.SaveToFile(FileName);
end;
finally
 Fn.Free;
end;
X := X + OffSetX;
Y := Y + OffSetY;
Px := Round(Round(X * HPointsPerInch * 10000/25.4) / 10000);
Py := Round(Round(Y * VPointsPerInch * 10000/25.4) / 10000);
Py := Py - GetOffSetY; file://因爲是絕對座標, 因此, 不用換算成相對於Y軸座標
Px := Px + 2 * AvgCharWidth;
Printer.Canvas.Font.Name := '宋體';
Printer.Canvas.Font.Size := FontSize;
file://Printer.Canvas.Font.Color := clGreen;
Printer.Canvas.TextOut(Px, Py, Txt);
end;

  2. 使用舉例

  在主窗體中加入對mprint單元的引用,在一命令鈕的OnClick事件中書寫如下代碼(用於在郵政匯款單上的相應方框內打印郵政編碼843300):

Printer.BeginDoc;
PrintText(16, 14, '8', 'config.txt');
PrintText(26, 14, '4', 'config.txt');
PrintText(36, 14, '3', 'config.txt');
PrintText(46, 14, '3', 'config.txt');
PrintText(56, 14, '0', 'config.txt');
PrintText(66, 14, '0', 'config.txt');
Printer.EndDoc;

  觀察結果,用尺子測量偏移量,在config.txt文件中修改X,Y的值即可。

  其它,設置打印機和紙張類型從略。

  四、結束語

  筆者通過該方法,實現了郵政匯款單,儲蓄憑證,客戶信封等單據的精確打印,取得了較爲滿意的效果。該程序在Windows98,Delphi5下調試通過。  

 
 2006-7-19 2:09:08    自行編寫Windwos服務CPU佔用率過高問題的解決

最近在編寫我的第一個Windows服務程序時,因需要檢測當前時間是否符合條件,在線程中加入了測試條件的代碼,結果服務安裝並啓動後,CPU佔用率一直在100%
    後來,經過思考,發現如果不在循環代碼中讓CPU有休息的機會,那麼它就會一直工作,導致系統變慢了.所以,非常簡單的解決辦法就是,在循環體內加上一句: Sleep(integer X);即可.如:

While not Terminated do
begin
  //Do something here
  Sleep(100);
end;  

 
 2006-7-19 2:12:33    加快ClientDataSet1速度。詳請查書。不理解

with ClientDataset1 do
begin
 DisableControl;
 try

for ...
begin
  ClientDataSet1.Append;
  ClientDataSet1.Fields[0].Value := ...
  ...
  ClientDataSet1.Fields[N].Value := ...
end;
  ClientDataSet1.Post;//移到外面來

 finally
  EnableControl;
 end;
end;  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章