经验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
支持:wjhu111@21cn.com
//*)

///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;  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值