??xml version="1.0" encoding="utf-8" standalone="yes"?>精品久久久久久无码人妻蜜桃,久久久久久精品免费看SSS,亚洲国产精品无码久久一区二区http://www.shnenglu.com/Khan/category/773.html路O漫,长修q,我们不能没有?/description>zh-cnTue, 20 May 2008 13:13:02 GMTTue, 20 May 2008 13:13:02 GMT60昨天玩delphiU程,扑ֈ一文?强烈推荐大家看看,tthread代码分析http://www.shnenglu.com/Khan/archive/2006/11/21/15503.htmlKhan's NotebookKhan's NotebookTue, 21 Nov 2006 03:46:00 GMThttp://www.shnenglu.com/Khan/archive/2006/11/21/15503.htmlhttp://www.shnenglu.com/Khan/comments/15503.htmlhttp://www.shnenglu.com/Khan/archive/2006/11/21/15503.html#Feedback1http://www.shnenglu.com/Khan/comments/commentRss/15503.htmlhttp://www.shnenglu.com/Khan/services/trackbacks/15503.html

Delphi中的U程c?br /> 
转脓?华夏黑客同盟 http://www.77169.org

Delphi中有一个线E类TThread是用来实现多U程~程的,q个l大多数Delphi书藉都有说到Q但基本上都是对

TThreadcȝ几个成员作一单介l,再说明一下Execute的实现和Synchronize的用法就完了。然而这q不是多U程~?br />E的全部Q我写此文的目的在于Ҏ作一个补充?/p>

U程本质上是q程中一Dƈ发运行的代码。一个进E至有一个线E,x谓的ȝE。同时还可以有多个子U程?br />当一个进E中用到过一个线E时Q就是所谓的“多U程”?br />那么q个所谓的“一D代码”是如何定义的呢Q其实就是一个函数或q程Q对Delphi而言Q?br />如果用Windows API来创建线E的话,是通过一个叫做CreateThread的API函数来实现的Q它的定义ؓQ?br />HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    DWORD dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags,
    LPDWORD lpThreadId
);

其各参数如它们的名称所_分别是:U程属性(用于在NT下进行线E的安全属性设|,?X下无效)Q堆栈大,
起始地址Q参敎ͼ创徏标志Q用于设|线E创建时的状态)Q线EIDQ最后返回线EHandle。其中的起始地址是U?br />E函数的入口Q直至线E函数结束,U程也就l束了?/p>

因ؓCreateThread参数很多Q而且是Windows的APIQ所以在C Runtime Library里提供了一个通用的线E函敎ͼ理论?br />可以在Q何支持线E的OS中用)Q?br />unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);

Delphi也提供了一个相同功能的cM函数Q?br />function BeginThread(
    SecurityAttributes: Pointer;
    StackSize: LongWord;
    ThreadFunc: TThreadFunc;
    Parameter: Pointer;
    CreationFlags: LongWord;
    var ThreadId: LongWord
): Integer;

 

q三个函数的功能是基本相同的Q它们都是将U程函数中的代码攑ֈ一个独立的U程中执行。线E函C一般函数的
最大不同在于,U程函数一启动Q这三个U程启动函数p回了Q主U程l箋向下执行Q而线E函数在一个独立的U?br />E中执行Q它要执行多久,什么时候返回,ȝE是不管也不知道的?br />正常情况下,U程函数q回后,U程q止了。但也有其它方式Q?/p>

Windows APIQ?br />VOID ExitThread( DWORD dwExitCode );

C Runtime LibraryQ?br />void _endthread(void);

Delphi Runtime LibraryQ?br />procedure EndThread(ExitCode: Integer);

Z记录一些必要的U程数据Q状?属性等Q,OS会ؓU程创徏一个内部ObjectQ如在Windows中那个Handle便是q?br />个内部Object的HandleQ所以在U程l束的时候还应该释放q个Object?/p>

虽然说用API或RTL(Runtime Library)已经可以很方便地q行多线E编E了Q但是还是需要进行较多的l节处理Qؓ?br />Delphi在Classes单元中对U程作了一个较好的装Q这是VCL的线E类QTThread
使用q个cM很简单,大多数的Delphi书籍都有_基本用法是:先从TThreadz一个自qU程c(因ؓTThread
是一个抽象类Q不能生成实例)Q然后是Override抽象ҎQExecuteQ这是U程函数Q也是在线E中执行的代?br />部分Q,如果需要用到可视VCL对象Q还需要通过Synchronizeq程q行。关于之斚w的具体细节,q里不再赘述Q请
参考相关书c?/p>

本文接下来要讨论的是TThreadcL如何对线E进行封装的Q也是深入研究一下TThreadcȝ实现。因为只是真正地
了解了它Q才更好C用它?br />下面是DELPHI7中TThreadcȝ声明Q本文只讨论在Windowsq_下的实现Q所以去掉了所有有关Linuxq_部分的代?br />Q:

TThread = class
private
    FHandle: THandle;
    FThreadID: THandle;
    FCreateSuspended: Boolean;
    FTerminated: Boolean;
    FSuspended: Boolean;
    FFreeOnTerminate: Boolean;
    FFinished: Boolean;
    FReturnValue: Integer;
    FOnTerminate: TNotifyEvent;
    FSynchronize: TSynchronizeRecord;
    FFatalException: TObject;
    procedure CallOnTerminate;
    class procedure Synchronize(ASyncRec: PSynchronizeRecord); overload;
    function GetPriority: TThreadPriority;
    procedure SetPriority(Value: TThreadPriority);
    procedure SetSuspended(Value: Boolean);
protected
    procedure CheckThreadError(ErrCode: Integer); overload;
    procedure CheckThreadError(Success: Boolean); overload;
    procedure DoTerminate; virtual;
    procedure Execute; virtual; abstract;
    procedure Synchronize(Method: TThreadMethod); overload;
    property ReturnValue: Integer read FReturnValue write FReturnValue;
    property Terminated: Boolean read FTerminated;
public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    procedure AfterConstruction; override;
    procedure Resume;
    procedure Suspend;
    procedure Terminate;
    function WaitFor: LongWord;
    class procedure Synchronize(AThread: TThread; AMethod: TThreadMethod); overload;
    class procedure StaticSynchronize(AThread: TThread; AMethod: TThreadMethod);
    property FatalException: TObject read FFatalException;
    property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
    property Handle: THandle read FHandle;
    property Priority: TThreadPriority read GetPriority write SetPriority;
    property Suspended: Boolean read FSuspended write SetSuspended;
    property ThreadID: THandle read FThreadID;
    property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
end;

TThreadcdDelphi的RTL里算是比较简单的c,cL员也不多Q类属性都很简单明白,本文只对几个比较重要的c?br />成员Ҏ和唯一的事ӞOnTerminate作详l分析?br />首先是构造函敎ͼ
constructor TThread.Create(CreateSuspended: Boolean);
begin
    inherited Create;
    AddThread;
    FSuspended := CreateSuspended;
    FCreateSuspended := CreateSuspended;
    FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
    if FHandle = 0 then
        raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
end;
虽然q个构造函数没有多代码,但却可以是最重要的一个成员,因ؓU程是在这里被创徏的?br />在通过Inherited调用TObject.Create后,W一句就是调用一个过E:AddThreadQ其源码如下Q?br />procedure AddThread;
begin
    InterlockedIncrement(ThreadCount);
end;

同样有一个对应的RemoveThreadQ?br />procedure RemoveThread;
begin
    InterlockedDecrement(ThreadCount);
end;
它们的功能很单,是通过增减一个全局变量来统计进E中的线E数。只是这里用于增减变量的q不是常用的
Inc/Decq程Q而是用了InterlockedIncrement/InterlockedDecrementq一对过E,它们实现的功能完全一P都是
对变量加一或减一。但它们有一个最大的区别Q那是InterlockedIncrement/InterlockedDecrement是线E安全的?br />卛_们在多线E下能保证执行结果正,而Inc/Dec不能。或者按操作pȝ理论中的术语来说Q这是一对“原语”操作?/p>

以加一Z来说明二者实现细节上的不同:
一般来_对内存数据加一的操作分解以后有三个步骤Q?br />1?从内存中d数据
2?数据加一
3?存入内存
现在假设在一个两个线E的应用中用Incq行加一操作可能出现的一U情况:
1?U程A从内存中d数据Q假设ؓ3Q?br />2?U程B从内存中d数据Q也?Q?br />3?U程AҎ据加一Q现在是4Q?br />4?U程BҎ据加一Q现在也?Q?br />5?U程A数据存入内存(现在内存中的数据?Q?br />6?U程B也将数据存入内存Q现在内存中的数据还?Q但两个U程都对它加了一Q应该是5才对Q所以这里出C
错误的结果)

 

而用InterlockIncrementq程则没有这个问题,因ؓ所谓“原语”是一U不可中断的操作Q即操作pȝ能保证在一?br />“原语”执行完毕前不会q行U程切换。所以在上面那个例子中,只有当线EA执行完将数据存入内存后,U程B才可
以开始从中取数ƈq行加一操作Q这样就保证了即使是在多U程情况下,l果也一定会是正的?/p>

前面那个例子也说明一U“线E访问冲H”的情况Q这也就是ؓ什么线E之间需要“同步”(SynchronizeQ,关于q?br />个,在后面说到同步时q会再详l讨论?/p>

说到同步Q有一个题外话Q加拿大滑铁卢大学的教授李明曑ְSynchronize一词在“线E同步”中被译作“同步”提?br />q异议,个h认ؓ他说的其实很有道理。在中文中“同步”的意思是“同时发生”,而“线E同步”目的就是避免这
U“同时发生”的事情。而在英文中,Synchronize的意思有两个Q一个是传统意义上的同步QTo occur at the same
timeQ,另一个是“协调一致”(To operate in unisonQ。在“线E同步”中的Synchronize一词应该是指后面一U?br />意思,即“保证多个线E在讉K同一数据Ӟ保持协调一_避免出错”。不q像q样译得不准的词在IT业还有很?br />Q既然已l是U定俗成了,本文也将l箋沿用Q只是在q里说明一下,因ؓ软g开发是一细致的工作Q该弄清楚的
Q绝不能含糊?/p>

扯远了,回到TThread的构造函CQ接下来最重要是q句了:
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
q里qC前面说到的Delphi RTL函数BeginThreadQ它有很多参敎ͼ关键的是W三、四两个参数。第三个参数是
前面说到的线E函敎ͼ卛_U程中执行的代码部分。第四个参数则是传递给U程函数的参敎ͼ在这里就是创建的U程
对象Q即SelfQ。其它的参数中,W五个是用于讄U程在创建后xP不立x行(启动U程的工作是?br />AfterConstruction中根据CreateSuspended标志来决定的Q,W六个是q回U程ID?/p>

现在来看TThread的核心:U程函数ThreadProc。有意思的是这个线E类的核心却不是U程的成员,而是一个全局函数
Q因为BeginThreadq程的参数约定只能用全局函数Q。下面是它的代码Q?/p>

function ThreadProc(Thread: TThread): Integer;
var
    FreeThread: Boolean;
begin
      try
            if not Thread.Terminated then
            try
                Thread.Execute;
            except
                Thread.FFatalException := AcquireExceptionObject;
            end;
      finally
            FreeThread := Thread.FFreeOnTerminate;
            Result := Thread.FReturnValue;
            Thread.DoTerminate;
            Thread.FFinished := True;
            SignalSyncEvent;
            if FreeThread then Thread.Free;
            EndThread(Result);
      end;
end;
虽然也没有多代码,但却是整个TThread中最重要的部分,因ؓq段代码是真正在U程中执行的代码。下面对代码?br />逐行说明Q?br />首先判断U程cȝTerminated标志Q如果未被标志ؓl止Q则调用U程cȝExecuteҎ执行U程代码Q因为TThread
是抽象类QExecuteҎ是抽象方法,所以本质上是执行派生类中的Execute代码?/p>

所以说QExecute是U程cM的线E函敎ͼ所有在Execute中的代码都需要当作线E代码来考虑Q如防止讉K冲突{?br />如果Execute发生异常Q则通过AcquireExceptionObject取得异常对象Qƈ存入U程cȝFFatalException成员中?br />最后是U程l束前做的一些收ַ作。局部变量FreeThread记录了线E类的FreeOnTerminated属性的讄Q然后将U?br />E返回D|ؓU程cȝq回值属性的倹{然后执行线E类的DoTerminateҎ?/p>

DoTerminateҎ的代码如下:
procedure TThread.DoTerminate;
begin
    if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;

很简单,是通过Synchronize来调用CallOnTerminateҎQ而CallOnTerminateҎ的代码如下,是单地调用
OnTerminate事gQ?br />procedure TThread.CallOnTerminate;
begin
    if Assigned(FOnTerminate) then FOnTerminate(Self);
end;

因ؓOnTerminate事g是在Synchronize中执行的Q所以本质上它ƈ不是U程代码Q而是ȝE代码(具体见后面对
Synchronize的分析)?/p>

执行完OnTerminate后,线E类的FFinished标志讄为True。接下来执行SignalSyncEventq程Q其代码如下Q?br />procedure SignalSyncEvent;
begin
    SetEvent(SyncEvent);
end;

也很单,是讄一下一个全局EventQSyncEventQ关于Event的用,本文在后文详述Q而SyncEvent的用途将
在WaitForq程中说明?/p>

然后ҎFreeThread中保存的FreeOnTerminate讄军_是否释放U程c,在线E类释放Ӟq有一些些操作Q详见接
下来的析构函数实现?br />最后调用EndThreadl束U程Q返回线E返回倹{至此,U程完全l束?br />说完构造函敎ͼ再来看析构函敎ͼ
destructor TThread.Destroy;
begin
  if (FThreadID <> 0) and not FFinished then  begin
      Terminate;
      if FCreateSuspended then
          Resume;
      WaitFor;
  end;
  if FHandle <> 0 then CloseHandle(FHandle);
  inherited Destroy;
  FFatalException.Free;
  RemoveThread;
end;

在线E对象被释放前,首先要检查线E是否还在执行中Q如果线E还在执行中Q线EID不ؓ0Qƈ且线E结束标志未?br />|)Q则调用Terminateq程l束U程。Terminateq程只是单地讄U程cȝTerminated标志Q如下面的代码:

procedure TThread.Terminate;
begin
    FTerminated := True;
end;

所以线E仍然必ȝl执行到正常l束后才行,而不是立即终止线E,q一点要注意?/p>

在这里说一炚w外话Q很多h都问q我Q如何才能“立即”终止线E(当然是指用TThread创徏的线E)。结果当然是
不行Q终止线E的唯一办法是让ExecuteҎ执行完毕Q所以一般来_要让你的U程能够快l止Q必d
ExecuteҎ中在较短的时间内不断地检查Terminated标志Q以便能及时地退出。这是设计线E代码的一个很重要的原
则!

当然如果你一定要能“立即”退出线E,那么TThreadcM是一个好的选择Q因为如果用API强制l止U程的话Q最l?br />会导致TThreadU程对象不能被正释放,在对象析构时出现Access Violation。这U情况你只能用API或RTL函数来创
建线E?/p>

如果U程处于启动挂v状态,则将U程转入q行状态,然后调用WaitForq行{待Q其功能是{待到线E结束后才
l向下执行。关于WaitFor的实玎ͼ放到后面说明?/p>

U程l束后,关闭U程HandleQ正常线E创建的情况下Handle都是存在的)Q释放操作系l创建的U程对象?br />然后调用TObject.Destroy释放本对象,q攑ַl捕L异常对象Q最后调用RemoveThread减小q程的线E数?/p>

其它关于Suspend/Resume及线E优先讄{方面,不是本文的重点,不再赘述。下面要讨论的是本文的另两个重点
QSynchronize和WaitFor?/p>

但是在介l这两个函数之前Q需要先介绍另外两个U程同步技术:事g和界区?/p>

事gQEventQ与Delphi中的事g有所不同。从本质上说QEvent其实相当于一个全局的布变量。它有两个赋值操?br />QSet和ResetQ相当于把它讄为True或False。而检查它的值是通过WaitFor操作q行。对应在Windowsq_上,是三
个API函数QSetEvent、ResetEvent、WaitForSingleObjectQ实现WaitFor功能的APIq有几个Q这是最单的一个)?/p>

q三个都是原语,所以Event可以实现一般布变量不能实现的在多U程中的应用。Set和Reset的功能前面已l说q了
Q现在来说一下WaitFor的功能:

WaitFor的功能是查Event的状态是否是Set状态(相当于TrueQ,如果是则立即q回Q如果不是,则等待它变ؓSet
状态,在等待期_调用WaitFor的线E处于挂L态。另外WaitFor有一个参数用于超时设|,如果此参Cؓ0Q则?br />{待Q立卌回Event的状态,如果是INFINITE则无限等待,直到Set状态发生,若是一个有限的数|则等待相应的
毫秒数后q回Event的状态?/p>

当Event从Reset状态向Set状态{换时Q唤醒其它由于WaitForq个Event而挂LU程Q这是它ؓ什么叫Event的原
因。所谓“事件”就是指“状态的转换”。通过Event可以在线E间传递这U“状态{换”信息?/p>

当然用一个受保护Q见下面的界区介绍Q的布尔变量也能实现cM的功能,只要用一个@环检查此布尔值的代码?br />代替WaitFor卛_。从功能上说完全没有问题Q但实际使用中就会发玎ͼq样的等待会占用大量的CPU资源Q降低系l?br />性能Q媄响到别的U程的执行速度Q所以是不经的Q有的时候甚臛_能会有问题。所以不q样用?/p>

临界区(CriticalSectionQ则是一共享数据访问保护的技术。它其实也是相当于一个全局的布变量。但对它的操
作有所不同Q它只有两个操作QEnter和LeaveQ同样可以把它的两个状态当作True和FalseQ分别表C现在是否处于
界区中。这两个操作也是原语Q所以它可以用于在多U程应用中保护共享数据,防止讉K冲突?/p>

用界区保护׃n数据的方法很单:在每ơ要讉K׃n数据之前调用Enter讄q入临界区标志,然后再操作数据,
最后调用Leaved临界区。它的保护原理是q样的:当一个线E进入界区后,如果此时另一个线E也要访问这个数
据,则它会在调用EnterӞ发现已经有线E进入界区Q然后此U程׃被挂P{待当前在界区的线E调?br />Leaved临界区,当另一个线E完成操作,调用Leaved后,此线E就会被唤醒Qƈ讄临界区标志,开始操作数
据,q样防止了讉K冲突?/p>

以前面那个InterlockedIncrementZQ我们用CriticalSectionQWindows APIQ来实现它:
Var
InterlockedCrit : TRTLCriticalSection;
Procedure InterlockedIncrement( var aValue : Integer );
Begin
    EnterCriticalSection( InterlockedCrit );
    Inc( aValue );
    LeaveCriticalSection( InterlockedCrit );
End;

现在再来看前面那个例子:
1. U程Aq入临界区(假设数据?Q?br />2. U程Bq入临界区,因ؓA已经在界区中,所以B被挂?br />3. U程AҎ据加一Q现在是4Q?br />4. U程Ad临界区,唤醒U程BQ现在内存中的数据是4Q?br />5. U程B被唤醒,Ҏ据加一Q现在就?了)
6. U程Bd临界区,现在的数据就是正的了?/p>

临界区就是这样保护共享数据的讉K?/p>

关于临界区的使用Q有一点要注意Q即数据讉K时的异常情况处理。因为如果在数据操作时发生异常,导致Leave?br />作没有被执行Q结果将使本应被唤醒的线E未被唤醒,可能造成E序的没有响应。所以一般来_如下面这样用
界区才是正确的做法:

EnterCriticalSection
Try
// 操作临界区数?br />Finally
    LeaveCriticalSection
End;

最后要说明的是QEvent和CriticalSection都是操作pȝ资源Q用前都需要创建,使用完后也同样需要释放。如
TThreadcȝ到的一个全局EventQSyncEvent和全局CriticalSectionQTheadLockQ都是在
InitThreadSynchronization和DoneThreadSynchronization中进行创建和释放的,而它们则是在Classes单元?br />Initialization和Finalization中被调用的?/p>

׃在TThread中都是用API来操作Event和CriticalSection的,所以前面都是以APIZQ其实Delphi已经提供了对?br />们的装Q在SyncObjs单元中,分别是TEventcdTCriticalSectioncR用法也与前面用API的方法相差无几。因?br />TEvent的构造函数参数过多,Z单v见,Delphiq提供了一个用默认参数初始化的Eventc:TSimpleEvent?/p>

Z再介l一下另一个用于线E同步的c:TMultiReadExclusiveWriteSynchronizerQ它是在SysUtils单元中定义的
。据我所知,q是Delphi RTL中定义的最长的一个类名,q好它有一个短的别名:TMREWSync。至于它的用处,我想?br />看名字就可以知道了,我也׃多说了?/p>

有了前面对Event和CriticalSection的准备知识,可以正式开始讨论Synchronize和WaitFor了?br />我们知道QSynchronize是通过部分代码放CU程中执行来实现U程同步的,因ؓ在一个进E中Q只有一个主U程
。先来看看Synchronize的实玎ͼ

procedure TThread.Synchronize(Method: TThreadMethod);
begin
    FSynchronize.FThread := Self;
    FSynchronize.FSynchronizeException := nil;
    FSynchronize.FMethod := Method;
    Synchronize(@FSynchronize);
end;

其中FSynchronize是一个记录类型:
PSynchronizeRecord = ^TSynchronizeRecord;
TSynchronizeRecord = record
    FThread: TObject;
    FMethod: TThreadMethod;
    FSynchronizeException: TObject;
end;

用于q行U程和主U程之间q行数据交换Q包括传入线E类对象Q同步方法及发生的异常?br />在Synchronize中调用了它的一个重载版本,而且q个重蝲版本比较特别Q它是一个“类Ҏ”。所谓类ҎQ是一U?br />Ҏ的类成员ҎQ它的调用ƈ不需要创建类实例Q而是像构造函数那P通过cd调用。之所以会用类Ҏ来实?br />它,是因Zؓ了可以在U程对象没有创徏时也能调用它。不q实际中是用它的另一个重载版本(也是cL法)和另一
个类ҎStaticSynchronize。下面是q个Synchronize的代码:

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
var
    SyncProc: TSyncProc;
begin
    if GetCurrentThreadID = MainThreadID then
        ASyncRec.FMethod
    else begin
    SyncProc.Signal := CreateEvent(nil, True, False, nil);
    try
    EnterCriticalSection(ThreadLock);
    try
    if SyncList = nil then
        SyncList := TList.Create;
        SyncProc.SyncRec := ASyncRec;
        SyncList.Add(@SyncProc);
        SignalSyncEvent;
        if Assigned(WakeMainThread) then
            WakeMainThread(SyncProc.SyncRec.FThread);
        LeaveCriticalSection(ThreadLock);
        try
            WaitForSingleObject(SyncProc.Signal, INFINITE);
        finally
            EnterCriticalSection(ThreadLock);
        end;
        finally
            LeaveCriticalSection(ThreadLock);
        end;
        finally
            CloseHandle(SyncProc.Signal);
        end;
        if Assigned(ASyncRec.FSynchronizeException) then
            raise ASyncRec.FSynchronizeException;
    end;
end;

q段代码略多一些,不过也不太复杂?br />首先是判断当前线E是否是ȝE,如果是,则简单地执行同步Ҏ后返回?br />如果不是ȝE,则准备开始同步过E?br />通过局部变量SyncProc记录U程交换数据Q参敎ͼ和一个Event HandleQ其记录l构如下Q?br />TSyncProc = record
SyncRec: PSynchronizeRecord;
Signal: THandle;
end;

然后创徏一个EventQ接着q入临界区(通过全局变量ThreadLockq行Q因为同时只能有一个线E进入Synchronize?br />态,所以可以用全局变量记录Q,然后是把这个记录数据存入SyncListq个列表中(如果q个列表不存在的话,?br />创徏它)。可见ThreadLockq个临界区就是ؓ了保护对SyncList的访问,q一点在后面介绍CheckSynchronize时会?br />ơ看到?/p>

再接下就是调用SignalSyncEventQ其代码在前面介lTThread的构造函数时已经介绍q了Q它的功能就是简单地?br />SyncEvent作一个Set的操作。关于这个SyncEvent的用途,在后面介绍WaitFor时再详述?/p>

接下来就是最主要的部分了Q调用WakeMainThread事gq行同步操作。WakeMainThread是一个TNotifyEventcd的全
局事g。这里之所以要用事件进行处理,是因为SynchronizeҎ本质上是通过消息Q将需要同步的q程攑ֈȝE中
执行Q如果在一些没有消息@环的应用中(如Console或DLLQ是无法使用的,所以要使用q个事gq行处理?br />而响应这个事件的是Application对象Q下面两个方法分别用于设|和清空WakeMainThread事g的响应(来自Forms单元Q:

procedure TApplication.HookSynchronizeWakeup;
begin
    Classes.WakeMainThread := WakeMainThread;
end;

procedure TApplication.UnhookSynchronizeWakeup;
begin
    Classes.WakeMainThread := nil;
end;

上面两个Ҏ分别是在TApplicationcȝ构造函数和析构函数中被调用?br />q就是在Application对象中WakeMainThread事g响应的代码,消息是在这里被发出的,它利用了一个空消息来实玎ͼ

procedure TApplication.WakeMainThread(Sender: TObject);
begin
    PostMessage(Handle, WM_NULL, 0, 0);
end;

而这个消息的响应也是在Application对象中,见下面的代码Q删除无关的部分Q:
procedure TApplication.WndProc(var Message: TMessage);
?br />begin
    try
        ?br />        with Message do
        case Msg of
        ?br />        WM_NULL:
        CheckSynchronize;
        ?br />    except
        HandleException(Self);
    end;
end;

其中的CheckSynchronize也是定义在Classes单元中的Q由于它比较复杂Q暂时不详细说明Q只要知道它是具体处?br />Synchronize功能的部分就好,现在l箋分析Synchronize的代码?br />在执行完WakeMainThread事g后,退Z界区Q然后调用WaitForSingleObject开始等待在q入临界区前创徏的那?br />Event。这个Event的功能是{待q个同步Ҏ的执行结束,关于q点Q在后面分析CheckSynchronize时会再说明?br />注意在WaitForSingleObject之后又重新进入界区Q但没有做Q何事退ZQ似乎没有意义,但这是必ȝQ?br />因ؓ临界区的Enter和Leave必须严格的一一对应。那么是否可以改成这样呢Q?/p>

if Assigned(WakeMainThread) then
    WakeMainThread(SyncProc.SyncRec.FThread);
    WaitForSingleObject(SyncProc.Signal, INFINITE);
    finally
        LeaveCriticalSection(ThreadLock);
end;

上面的代码和原来的代码最大的区别在于把WaitForSingleObject也纳入界区的限制中了。看上去没什么媄响,q
代码大大化了Q但真的可以吗?
事实上是不行Q?/p>

因ؓ我们知道Q在Enter临界区后Q如果别的线E要再进入,则会被挂赗而WaitForҎ则会挂v当前U程Q直到等
待别的线ESetEvent后才会被唤醒。如果改成上面那L代码的话Q如果那个SetEvent的线E也需要进入界区的话
Q死锁(DeadlockQ就发生了(关于死锁的理论,误行参考操作系l原理方面的资料Q?br />死锁是线E同步中最需要注意的斚w之一Q?br />最后释攑ּ始时创徏的EventQ如果被同步的方法返回异常的话,q会在这里再ơ抛出异常?/p>

回到前面CheckSynchronizeQ见下面的代码:

function CheckSynchronize(Timeout: Integer = 0): Boolean;
var
     SyncProc: PSyncProc;
     LocalSyncList: TList;
begin
     if GetCurrentThreadID <> MainThreadID then
          raise EThread.CreateResFmt(@SCheckSynchronizeError, [GetCurrentThreadID]);
     if Timeout > 0 then
          WaitForSyncEvent(Timeout)
     else
          ResetSyncEvent;
     LocalSyncList := nil;
     EnterCriticalSection(ThreadLock);
     try
          Integer(LocalSyncList) := InterlockedExchange(Integer(SyncList), Integer(LocalSyncList));
          try
               Result := (LocalSyncList <> nil) and (LocalSyncList.Count > 0);
               if Result then begin
                    while LocalSyncList.Count > 0 do begin
                         SyncProc := LocalSyncList[0];
                         LocalSyncList.Delete(0);
                         LeaveCriticalSection(ThreadLock);
                         try
                              try
                                   SyncProc.SyncRec.FMethod;
                              except
                                   SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject;
                              end;
                         finally
                              EnterCriticalSection(ThreadLock);
                         end;
                         SetEvent(SyncProc.signal);
                    end;
               end;
          finally
               LocalSyncList.Free;
          end;
     finally
          LeaveCriticalSection(ThreadLock);
     end;
end;

首先Q这个方法必dȝE中被调用(如前面通过消息传递到ȝE)Q否则就抛出异常?br />接下来调用ResetSyncEventQ它与前面SetSyncEvent对应的,之所以不考虑WaitForSyncEvent的情况,是因为只有在
Linux版下才会调用带参数的CheckSynchronizeQWindows版下都是调用默认参数0的CheckSynchronizeQ?br />现在可以看出SyncList的用途了Q它是用于记录所有未被执行的同步Ҏ的。因ZU程只有一个,而子U程可能?br />很多个,当多个子U程同时调用同步ҎӞȝE可能一时无法处理,所以需要一个列表来记录它们?br />在这里用一个局部变量LocalSyncList来交换SyncListQ这里用的也是一个原语:InterlockedExchange。同Pq里
也是用界区对SyncList的访问保护v来?br />只要LocalSyncList不ؓI,则通过一个@环来依次处理累积的所有同步方法调用。最后把处理完的LocalSyncList?br />放掉Q退Z界区?/p>

再来看对同步Ҏ的处理:首先是从列表中移出(取出q从列表中删除)W一个同步方法调用数据。然后退Z界区
Q原因当然也是ؓ了防止死锁)?br />接着是真正的调用同步方法了?br />如果同步Ҏ中出现异常,被捕获后存入同步方法数据记录中?br />重新q入临界区后Q调用SetEvent通知调用U程Q同步方法执行完成了Q详见前面Synchronize中的
WaitForSingleObject调用Q?br />xQ整个Synchronize的实Cl完成?/p>

最后来说一下WaitForQ它的功能就是等待线E执行结束。其代码如下Q?br />function TThread.WaitFor: LongWord;
var
    H: array[0..1] of THandle;
    WaitResult: Cardinal;
    Msg: TMsg;
begin
    H[0] := FHandle;
    if GetCurrentThreadID = MainThreadID then  begin
        WaitResult := 0;
        H[1] := SyncEvent;
        repeat
            { This prevents a potential deadlock if the background thread does a SendMessage to the foreground thread }
            if WaitResult = WAIT_OBJECT_0 + 2 then
                PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
            WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
            CheckThreadError(WaitResult <> WAIT_FAILED);
            if WaitResult = WAIT_OBJECT_0 + 1 then
                CheckSynchronize;
        until WaitResult = WAIT_OBJECT_0;
    end else
        WaitForSingleObject(H[0], INFINITE);
    CheckThreadError(GetExitCodeThread(H[0], Result));
end;

如果不是在主U程中执行WaitFor的话Q很单,只要调用WaitForSingleObject{待此线E的Handle为Signaled状?br />卛_?/p>

如果是在ȝE中执行WaitFor则比较麻烦。首先要在Handle数组中增加一个SyncEventQ然后@环等待,直到U程l?br />束(即MsgWaitForMultipleObjectsq回WAIT_OBJECT_0Q详见MSDN中关于此API的说明)?br />在@环等待中作如下处理:如果有消息发生,则通过PeekMessage取出此消息(但ƈ不把它从消息循环中移除)Q然?br />调用MsgWaitForMultipleObjects来等待线EHandle或SyncEvent出现Signaled状态,同时监听消息QQS_SENDMESSAGE
参数Q详见MSDN中关于此API的说明)。可以把此API当作一个可以同时等待多个Handle的WaitForSingleObject。如?br />是SyncEvent被SetEventQ返回WAIT_OBJECT_0 + 1Q,则调用CheckSynchronize处理同步Ҏ?br />Z么在ȝE中调用WaitFor必须用MsgWaitForMultipleObjectsQ而不能用WaitForSingleObject{待U程l束呢?
因ؓ防止死锁。由于在U程函数Execute中可能调用Synchronize处理同步ҎQ而同步方法是在主U程中执行的Q如
果用WaitForSingleObject{待的话Q则ȝE在q里被挂P同步Ҏ无法执行Q导致线E也被挂P于是发生死锁?br />而改用WaitForMultipleObjects则没有这个问题。首先,它的W三个参CؓFalseQ表C只要线EHandle或SyncEvent
中只要有一个Signaled卛_使主U程被唤醒,至于加上QS_SENDMESSAGE是因为Synchronize是通过消息传到ȝE来?br />Q所以还要防止消息被d。这P当线E中调用SynchronizeӞȝE就会被唤醒q处理同步调用,在调用完成后
l箋q入挂v{待状态,直到U程l束?br />xQ对U程cTThread的分析可以告一个段落了Q对前面的分析作一个ȝQ?br />1?U程cȝU程必须按正常的方式l束Q即Execute执行l束Q所以在其中的代码中必须在适当的地方加入够多
    的对Terminated标志的判断,q及旉出。如果必要“立即”退出,则不能用线E类Q而要改用API或RTL函数?br />2?对可视VCL的访问要攑֜Synchronize中,通过消息传递到ȝE中Q由ȝE处理?br />3?U程׃n数据的访问应该用临界行保护(当然用Synchronize也行Q?br />4?U程通信可以采用Eventq行Q当然也可以用Suspend/ResumeQ?br />5?当在多线E应用中使用多种U程同步方式Ӟ一定要心防止出现死锁?br />6?{待U程l束要用WaitForҎ?/p>



Khan's Notebook 2006-11-21 11:46 发表评论
]]>
关于Utf8~码的几个函?/title><link>http://www.shnenglu.com/Khan/archive/2006/01/19/2903.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 19 Jan 2006 07:06:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2006/01/19/2903.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2903.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2006/01/19/2903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2903.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2903.html</trackback:ping><description><![CDATA[<p><font face="Courier New">最q一D|间老弄Utf8~码,工作时写了几个函?l大家指正一?br><br></font></p><pre>//////////////////////////////////////////////<br>//---------取得utf8字符的长?--------------//<br>//<font color="#008080">Str</font>:<font color="#2e8b57"><b>String</b></font> 源字W串<br>//<font color="#804040"><b>Result</b></font>:<font color="#2e8b57"><b>Integer</b></font> utf8字符串长?br>class <font color="#804040"><b>function</b></font> TPduPush.getUTF8Len(<font color="#008080">Str</font>: <font color="#2e8b57"><b>string</b></font>): <font color="#2e8b57"><b>Integer</b></font>;<br><font color="#804040"><b>var</b></font><br> i: <font color="#2e8b57"><b>integer</b></font>;<br> tmpChar: <font color="#2e8b57"><b>Pchar</b></font>;<br><font color="#804040"><b>begin</b></font><br> tmpChar := <font color="#2e8b57"><b>pchar</b></font>(<font color="#008080">str</font>);<br> i := <font color="#ff00ff">0</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#ff00ff">0</font>;<br> <font color="#804040"><b>while</b></font> i < <font color="#008080">length</font>(tmpChar) <font color="#804040"><b>do</b></font> <font color="#804040"><b>begin</b></font><br> <font color="#804040"><b>if</b></font> <font color="#008080">ord</font>(tmpChar[i]) < $80 <font color="#804040"><b>then</b></font> <font color="#804040"><b>begin</b></font><br> i := i + <font color="#ff00ff">1</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#804040"><b>result</b></font> + <font color="#ff00ff">1</font>;<br> <font color="#804040"><b>end</b></font> <font color="#804040"><b>else</b></font> <font color="#804040"><b>begin</b></font><br> i := i + <font color="#ff00ff">2</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#804040"><b>result</b></font> + <font color="#ff00ff">3</font>;<br> <font color="#804040"><b>end</b></font>;<br> <font color="#804040"><b>end</b></font>;<br><font color="#804040"><b>end</b></font>;<br><br>////////////////////////////////////////////////<br>//----------取得字符串中的字W个?-----------//<br>//<font color="#008080">str</font>:<font color="#2e8b57"><b>String</b></font> 源字W串<br>//<font color="#804040"><b>Result</b></font>:<font color="#2e8b57"><b>Integer</b></font> 字符个数,兼容中文双字?br>class <font color="#804040"><b>function</b></font> TPduPush.getAnsiLen(<font color="#008080">Str</font>: <font color="#2e8b57"><b>string</b></font>): <font color="#2e8b57"><b>integer</b></font>;<br><font color="#804040"><b>var</b></font><br> i: <font color="#2e8b57"><b>integer</b></font>;<br> tmpChar: <font color="#2e8b57"><b>Pchar</b></font>;<br><font color="#804040"><b>begin</b></font><br> tmpChar := <font color="#2e8b57"><b>pchar</b></font>(<font color="#008080">str</font>);<br> i := <font color="#ff00ff">0</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#ff00ff">0</font>;<br> <font color="#804040"><b>while</b></font> i < <font color="#008080">length</font>(tmpChar) <font color="#804040"><b>do</b></font> <font color="#804040"><b>begin</b></font><br> <font color="#804040"><b>if</b></font> <font color="#008080">ord</font>(tmpChar[i]) < $80 <font color="#804040"><b>then</b></font><br> i := i + <font color="#ff00ff">1</font><br> <font color="#804040"><b>else</b></font><br> i := i + <font color="#ff00ff">2</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#804040"><b>result</b></font> + <font color="#ff00ff">1</font>;<br> <font color="#804040"><b>end</b></font>;<br><font color="#804040"><b>end</b></font>;<br><br><br>/////////////////////////////////////////////////<br>//---------截取指定长度的utf8字符?-----------//<br>//<font color="#008080">str</font>:<font color="#2e8b57"><b>string</b></font> 源字W串<br>//count:<font color="#2e8b57"><b>Integer</b></font> 指定长度 一个汉字占三个字节,长度只能?不能?br>//<font color="#804040"><b>Result</b></font>:<font color="#2e8b57"><b>string</b></font> 截取后的utf8字符?br>class <font color="#804040"><b>function</b></font> TPduPush.getUTF8String(<font color="#008080">Str</font>: <font color="#2e8b57"><b>string</b></font>; count: <font color="#2e8b57"><b>Integer</b></font>): <font color="#2e8b57"><b>string</b></font>;<br><font color="#804040"><b>var</b></font><br> i, j: <font color="#2e8b57"><b>integer</b></font>;<br> tmpChar: <font color="#2e8b57"><b>Pchar</b></font>;<br><font color="#804040"><b>begin</b></font><br> tmpChar := <font color="#2e8b57"><b>pchar</b></font>(<font color="#008080">str</font>);<br> i := <font color="#ff00ff">0</font>;<br> j := <font color="#ff00ff">0</font>;<br> <font color="#804040"><b>result</b></font> := <font color="#ff00ff">''</font>;<br><br> <font color="#804040"><b>while</b></font> i < <font color="#008080">length</font>(tmpChar) <font color="#804040"><b>do</b></font> <font color="#804040"><b>begin</b></font><br> <font color="#804040"><b>if</b></font> j >= count <font color="#804040"><b>then</b></font> <font color="#008080">break</font>; //英文转码后不能超q指定的位数<br> <font color="#804040"><b>if</b></font> <font color="#008080">ord</font>(tmpChar[i]) < $80 <font color="#804040"><b>then</b></font> <font color="#804040"><b>begin</b></font><br> <font color="#804040"><b>result</b></font> := <font color="#804040"><b>result</b></font> + <font color="#2e8b57"><b>string</b></font>(tmpChar[i]);<br> i := i + <font color="#ff00ff">1</font>;<br> j := j + <font color="#ff00ff">1</font>;<br> <font color="#804040"><b>end</b></font> <font color="#804040"><b>else</b></font> <font color="#804040"><b>begin</b></font><br> <font color="#804040"><b>if</b></font> j + <font color="#ff00ff">2</font> >= count <font color="#804040"><b>then</b></font> <font color="#008080">break</font>; //汉字转码后不能超q指定的位数<br> <font color="#804040"><b>result</b></font> := <font color="#804040"><b>result</b></font> + <font color="#2e8b57"><b>string</b></font>(tmpChar[i]) + <font color="#2e8b57"><b>string</b></font>(tmpChar[i + <font color="#ff00ff">1</font>]);<br> i := i + <font color="#ff00ff">2</font>;<br> j := j + <font color="#ff00ff">3</font>;<br> <font color="#804040"><b>end</b></font>;<br> <font color="#804040"><b>end</b></font>;<br><font color="#804040"><b>end</b></font>;</pre><font face="Courier New"></font><img src ="http://www.shnenglu.com/Khan/aggbug/2903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-19 15:06 <a href="http://www.shnenglu.com/Khan/archive/2006/01/19/2903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]今天在这个blog上找Cota bookmark的文?打算在我的程序里面加上发送ota bookmark的功?/title><link>http://www.shnenglu.com/Khan/archive/2006/01/12/2626.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 12 Jan 2006 01:56:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2006/01/12/2626.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2626.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2006/01/12/2626.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2626.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2626.html</trackback:ping><description><![CDATA[<p align="justify">首先需要写一个bookmark的xml文gQ这个格式可以去nokia|站下蝲。下面是一个例子:<br><?xml version="1.0"?> <br><!DOCTYPE CHARACTERISTIC-LIST PUBLIC "" "characteristic_list.dtd"> <br><CHARACTERISTIC-LIST><br>     <CHARACTERISTIC TYPE="BOOKMARK"><br>          <PARM NAME="NAME" VALUE="bookmark name"/><br>          <PARM NAME="URL" VALUE="<a /</a>><br>     </CHARACTERISTIC><br></CHARACTERISTIC-LIST></p> <p align="justify"><br>量让name和url短点Q这L码后可以攑ֈ一条短消息里面Q而不需要把一个设|拆分成多个短消息体。大致的一个封装是把xml文g转成wbxmlQ然后再在外面封装WSP层,最外面是WDP层?/p> <p align="justify">WDP的一般格式是?B0504C34FC002000304xxyy”,其中xx是整个数据包的ȝ断数目,而yy表示当前片断是第几个片断。D个例子,一个简单的bookmark全部攑֜一个sms中这样xxQ?1QyyQ?1?br>下面是每个byte的意?</p> <p align="justify"># 0B | User-Data-Header (UDHL) Length = 11 bytes<br># 05 | UDH IE identifier: Port numbers                        <br># 04 | UDH port number IE length                             <br># C3 | Destination port (high)                                      <br># 4F | Destination port (low)                                     <br># C0 | Originating port (high)                 <br># 02 | Originating port (low)                   <br># 00 | UDH IE identifier: SAR                 <br># 03 | UDH SAR IE length                      <br># 04 | Datagram ref no.                        <br>#<br># Two variable bytes, intentionally missing from WDP header, user must<br># calculate and add at send time.<br>#<br># xx | Total number of segments in datagram    <br># yy | Segment count                            </p> <p align="justify">bookmark的WSP层的格式一般是"01062D1F2A6170706C69636174696F6E2F782D7761702D70726F762E62726F777365722D626F6F6B6D61726B730081EA"<br>每个byte的具体意思是Q?/p> <p align="justify"># 01 | Transaction ID /                         <br># 06 | PDU type (push)                          <br># xx | Header length (content type headers)      <br># 1F | Value length quote length greater than 30<br># 2A | Value length (value name not used)        <br># xx | Mimetype encoded, variable bytes          | application/x-wap-prov.browser-{bookmarks | settings}<br># 00 | Null termination of content type string   |<br># 81 | Charset                                   | Well known PARM. (short integer)<br># EA | UTF-8 (using short integer)              <br>最里层是WBXML了,首先必须有个xml的头"01016A00"</p> <p align="justify"># 01 | Version                                   | WBXML 1.1<br># 01 | Unknown public identifier         |<br># 6A | Charset                                   | UTF-8<br># 00 | String table length                      |</p> 至于其他的具体编码可以去<a >http://www.forum.nokia.com</a>查看OTA_settings_general_7_0.pdfq个文档Q里面很详细的描qC每一个XML元素对应的十六进制。最后注意一点,发送的时候要?bit格式的发送,而不?bit格式?br><br><p> <a target="_new" >http://www.cnblogs.com/zhengyun_ustc/archive/2005/09/05/otawapbookmark.html</a> <br> <br>[SMS&WAP]实例讲解制作OTA短信来自动配|手机WAP书签[附源码] <br>摘要:OTAQ即Over The AirQ国内翻译ؓIZ下蝲? <br>OTA标准q立信和诺Z共同制订。OTA늛了许多范_比如Kjava中的应用E序下蝲也是通过OTA。我们这文章主要讲的是Q通过短信方式IZ下蝲配置信息Q参考的文档是OTA_settings_general_7_0.pdf? <br>规范中定义了三种SettingQ? <br>? 览器设|? <br>? 览器的书签讄 <br>? SyncML讄 <br>也就是说Q你通过发送短信可以帮助用h机配|这三种讄? <br> <br>原则上,你只要看了OTA_settings_general_7_0.pdfQƈ参照OTA_service_settings_example_v11.pdfQ就可以L地制作出W合规范的OTA短信? <br>但是Q本文档的目的就是让你简单粗暴地直奔主题Q看完这文档后Q就了解了OTA短信的概念,通过以下代码Q? <br>OTAMessage <br>OTAMessage message = new OTAMessage(); <br>txtOTAResult.Text = message.Get </p><br><a ></a><img src ="http://www.shnenglu.com/Khan/aggbug/2626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-12 09:56 <a href="http://www.shnenglu.com/Khan/archive/2006/01/12/2626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]在偶机器上找C个读cpu串号的代?delphi?记录一?x是h家的代码)http://www.shnenglu.com/Khan/archive/2006/01/12/2627.htmlKhan's NotebookKhan's NotebookThu, 12 Jan 2006 01:56:00 GMThttp://www.shnenglu.com/Khan/archive/2006/01/12/2627.htmlhttp://www.shnenglu.com/Khan/comments/2627.htmlhttp://www.shnenglu.com/Khan/archive/2006/01/12/2627.html#Feedback0http://www.shnenglu.com/Khan/comments/commentRss/2627.htmlhttp://www.shnenglu.com/Khan/services/trackbacks/2627.html
interface

uses
  SysUtils;

type
  TCPUID = array[1..4] of Longint;
  TVendor = array[0..11] of char;

function GetCPUID: TCPUID; assembler; register;
function GetCPUVendor: TVendor; assembler; register;
function GetCPUInfo: string;

implementation


function GetCPUID: TCPUID; assembler; register;
asm
 PUSH    EBX         {Save affected register}
 PUSH    EDI
 MOV     EDI,EAX      {@Resukt}
 MOV     EAX,1
 DW      $A20F        {CPUID Command}
 STOSD                {CPUID[1]}
 MOV     EAX,EBX
 STOSD                {CPUID[2]}
 MOV     EAX,ECX
 STOSD                {CPUID[3]}
 MOV     EAX,EDX
 STOSD                {CPUID[4]}
 POP     EDI          {Restore registers}
 POP     EBX
end;

function GetCPUVendor: TVendor; assembler; register;
asm
 PUSH    EBX          {Save affected register}
 PUSH    EDI
 MOV     EDI,EAX      {@Result (TVendor)}
 MOV     EAX,0
 DW      $A20F        {CPUID Command}
 MOV     EAX,EBX
 XCHG    EBX,ECX      {save ECX result}
 MOV     ECX,4
@1:
 STOSB
 SHR     EAX,8
 LOOP    @1
 MOV     EAX,EDX
 MOV     ECX,4
@2:
 STOSB
 SHR     EAX,8
 LOOP    @2
 MOV     EAX,EBX
 MOV     ECX,4
@3:
 STOSB
 SHR     EAX,8
 LOOP    @3
 POP     EDI          {Restore registers}
 POP     EBX
end;

function GetCPUInfo: string;
var
  CPUID: TCPUID;
  I: Integer;
  S: TVendor;
begin
  for I := Low(CPUID) to High(CPUID) do
    CPUID[I] := -1;

  CPUID := GetCPUID;

  S := GetCPUVendor;

  Result := S + IntToHex(CPUID[1], 8) + IntToHex(CPUID[2], 8)
    + IntToHex(CPUID[3], 8)
    + IntToHex(CPUID[4], 8);
end;


end.


以前中专d时候看ibm 8086/8088汇编有自己写q这些代码d,但是现在q了q么多年,退化到看不懂这些了

Khan's Notebook 2006-01-12 09:56 发表评论
]]>
[导入]l于搞定了异步通信?调试了两?发现偶还素犯了一个弱智错?/title><link>http://www.shnenglu.com/Khan/archive/2006/01/12/2632.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 12 Jan 2006 01:56:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2006/01/12/2632.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2632.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2006/01/12/2632.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2632.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2632.html</trackback:ping><description><![CDATA[<p>我把client的socket初始化内容写在了message响应函数里面?每次触发消息的时候就把客L的socket|??/p> <p> </p> <p>服务器端代码如下:</p> <p>׃比较?所以不贴注释了,如果有什么不懂d地方,大家对着<windows|络~程>d</windows|络~程></p> <p> </p> <p>unit Listener;</p> <p>interface</p> <p>uses<br>  SysUtils,  Controls, Forms, winsock, Classes, ComCtrls, StdCtrls;</p> <p><br>const ASYNC_EVENT = $0400 + 1;<br>  SO_CONDITIONAL_ACCEPT = $3002;<br>type</p> <p>  TCMSocketMessage = record //select 消息l构<br>    Msg: Cardinal; //pȝ消息<br>    Socket: TSocket; //产生消息的源socket 句柄<br>    SelectEvent: Word; //select消息<br>    SelectError: Word; //错误<br>    Result: Longint;<br>  end;</p> <p> </p> <p>type<br>  TMain = class(TForm)<br>    SBar: TStatusBar;<br>    Memo1: TMemo;<br>    procedure FormDestroy(Sender: TObject);<br>    procedure FormCreate(Sender: TObject);<br>  private<br>    s: TSocket;<br>    SClinent: TSocket;<br>    procedure bindAddr;<br>    procedure CMIncCount(var Msg: TCMSocketMessage); message ASYNC_EVENT;<br>    procedure listenAddr;<br>    { Private declarations }<br>  public<br>    { Public declarations }<br>  end;</p> <p>var<br>  Main: TMain;</p> <p>implementation</p> <p>{$R *.dfm}</p> <p>procedure TMain.FormDestroy(Sender: TObject);<br>begin<br>  closeSocket(s);<br>  WSACleanup();<br>end;</p> <p>procedure TMain.FormCreate(Sender: TObject);<br>var<br>  wsa: TWSaData;<br>  flag: integer;<br>begin<br>  SClinent := 0;<br>  //SysUtils.BoolToStr()<br>  flag := WSAStartup($0202, wsa); //加蝲winsock<br>  if flag <> 0 then begin<br>    SBar.Panels[2].Text := format('错误?%d', [WSAGetLastError()]);<br>    SBar.Panels[1].Text := 'Winsock库加载失?;<br>  end;</p> <p>  bindAddr;<br>  listenAddr;<br>end;</p> <p><br>procedure TMain.bindAddr;<br>var<br>  addr: TSockAddrIn;<br>  flag: integer;<br>begin<br>  s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服务器端的socket<br>  addr.sin_port := htons(45531);<br>  addr.sin_family := AF_INET;<br>  addr.sin_addr.S_addr := INADDR_ANY; //inet_addr(pchar(host));</p> <p>  flag := bind(s, addr, sizeof(addr));<br>  if flag = SOCKET_ERROR then begin<br>    SBar.Panels[2].Text := format('错误?%d', [WSAGetLastError()]);<br>    SBar.Panels[1].Text := 'IPl定错误';<br>  end else begin<br>    flag := WSAAsyncSelect(s, Handle, ASYNC_EVENT, FD_ACCEPT or FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE);<br>    if flag = SOCKET_ERROR then begin<br>      SBar.Panels[2].Text := format('错误?%d', [WSAGetLastError()]);<br>      SBar.Panels[1].Text := 'WSAAsyncSelect错误';<br>    end;<br>  end;<br>end;</p> <p>procedure TMain.listenAddr;<br>var flag: integer;<br>begin<br>  flag := listen(s, 10);<br>  if flag = SOCKET_ERROR then begin<br>    SBar.Panels[2].Text := format('错误?%d', [WSAGetLastError()]);<br>    SBar.Panels[1].Text := '监听p|';<br>  end;<br>end;</p> <p> </p> <p>procedure TMain.CMIncCount(var Msg: TCMSocketMessage);<br>var<br>  addr: TSockAddrIn;<br>  len: integer;<br>  SendBuf: array[1..1024] of AnsiChar;<br>  recvBuf: array[1..1024] of AnsiChar;<br>  str: string;<br>  OldOpenType {, NewOpenType}: integer;<br>begin<br>  len := 0;</p> <p>  str := '';</p> <p>  case Msg.SelectEvent of<br>    FD_READ: begin<br>        len := sizeof(recvBuf);<br>        ioctlsocket(SClinent, FIONREAD, Longint(len));<br>        fillchar(recvBuf, sizeof(recvBuf), 0);<br>        recv(SClinent, recvBuf, sizeof(recvBuf), 0);</p> <p>        Memo1.Lines.Add(string(recvBuf));<br>        Memo1.Lines.Add('read');<br>        if Memo1.Lines.Count > 10 then<br>          memo1.Clear;</p> <p>        sleep(10);<br>        fillchar(SendBuf, sizeof(SendBuf), 0);<br>        Strcopy(@SendBuf, pansichar('OK'));<br>        Send(SClinent, sendbuf, sizeof(sendbuf), 0);<br>      end;</p> <p>    FD_WRITE: begin</p> <p><br>        Memo1.Lines.Add('write');<br>      end;<br>    FD_ACCEPT: begin<br>        len := sizeof(OldOpenType);</p> <p>        if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len) = 0 then begin<br>          try<br>            len := sizeof(addr);<br>            SClinent := accept(s, @addr, @len);</p> <p>            if SClinent = INVALID_SOCKET then begin<br>              Memo1.Lines.Add('无效的socket:' + inttostr(SClinent));<br>            end;<br>            Memo1.Lines.Add('accept');<br>          finally<br>            len := sizeof(OldOpenType);<br>            setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len);<br>          end;<br>        end;<br>        WSAAsyncSelect(SClinent, handle, ASYNC_EVENT, $33);</p> <p>      end;<br>    FD_CONNECT: begin<br>        Memo1.Lines.Add('connect');<br>      end;<br>    FD_CLOSE: begin<br>        Memo1.Lines.Add('close');<br>      end;<br>  end;<br>end;</p> <p>end.<br>//׃服务器端没有~存机制,所以多个clientq接的时?W二个client的socket会覆盖前一个的,大家看情冉|改就行了,|络上大把代码都是用控g或者其他封装好dcL写d,所以资料郁h?</p> <p> </p> <p> </p> <p>客户端代?</p> <p>program Client;</p> <p>{$APPTYPE CONSOLE}</p> <p>uses<br>  SysUtils,<br>  windows,<br>  winsock;</p> <p>var<br>  addr: TSockAddrIn;<br>  wsa: TWSaData;<br>  flag: integer;<br>  s: TSocket;<br>  Host: string;<br>  Port: Word;<br>  BufSend: array[1..1024] of Ansichar; //中间信息<br>  BufRev: array[1..1024] of Ansichar;<br>  i: Integer;<br>begin<br>  { TODO -oUser -cConsole Main : Insert code here }</p> <p>  Host := '127.0.0.1';<br>  port := 45531;</p> <p>  flag := WSAStartup($0202, wsa); //加蝲winsock<br>  if flag <> 0 then begin<br>    Writeln(format('错误?%d', [WSAGetLastError()]));<br>    Writeln('Winsock库加载失?);<br>  end else begin<br>    Writeln('Winsock库加载成?)<br>  end;</p> <p>  //s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服务器端的socket<br>  s := socket(PF_INET, SOCK_STREAM, 0);<br>  FillChar(addr, sizeof(addr), 0); //初始化地址I间</p> <p>  addr.sin_port := htons(port);<br>  addr.sin_family := AF_INET;<br>  addr.sin_addr.S_addr := {INADDR_ANY; } inet_addr(pchar(host));</p> <p>  if connect(s, addr, sizeof(addr)) = 0 then begin<br>    Writeln('L:' + Host + ' q接成功')<br>  end else begin<br>    Writeln('L:' + Host + ' q接p|');<br>  end;</p> <p>  FillChar(BufSend, 1024, 0);</p> <p>  StrPCopy(@BufSend, '试信息?);<br>  for i := 0 to 100 do begin<br>    Writeln(inttostr(s));<br>    if Send(s, Bufsend, Length(BufSend), 0) <> SOCKET_ERROR then begin<br>      Writeln('消息已发?);<br>      sleep(500);</p> <p>      FillChar(BufRev, 1024, 0);<br>      //strcopy(bufsend,pansichar('a'))<br>      if recv(s, BufRev, Length(BufSend), 0) <> SOCKET_ERROR then begin<br>        writeln('接收到的信息:' + trim(string(BufRev)));<br>      end else begin<br>        Writeln('接收消息p|!')<br>      end;</p> <p>    end else begin<br>      Writeln('消息发送失?)<br>    end;<br>  end;</p> <p> </p> <p>  if closeSocket(s) = 0 then begin<br>    Writeln('已经关闭socket')<br>  end else begin<br>    Writeln('关闭socket 出错')<br>  end;</p> <p>  WSACleanup();<br>  Readln;<br>end.</p><a ></a><img src ="http://www.shnenglu.com/Khan/aggbug/2632.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-12 09:56 <a href="http://www.shnenglu.com/Khan/archive/2006/01/12/2632.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于delphi 的函数调用和参数传递方式深入研I之疑惑http://www.shnenglu.com/Khan/archive/2004/11/22/2642.htmlKhan's NotebookKhan's NotebookMon, 22 Nov 2004 14:14:00 GMThttp://www.shnenglu.com/Khan/archive/2004/11/22/2642.htmlhttp://www.shnenglu.com/Khan/comments/2642.htmlhttp://www.shnenglu.com/Khan/archive/2004/11/22/2642.html#Feedback0http://www.shnenglu.com/Khan/comments/commentRss/2642.htmlhttp://www.shnenglu.com/Khan/services/trackbacks/2642.html

关于delphi 的函数调用和参数传递方式深入研I?/p>

 

delphi 代码如下:

program Project1;

uses windows, SysUtils;


function a(d, dd: word; s, j, f: string): word;
begin
  d := d - 1;
  result := d + dd;
  messagebox(0, pchar(inttostr(d) + s), pchar(inttostr(dd)), $0);
end;

var s: string;

begin
  s := 'sssssssssss';
 { asm
    mov dx,$11
    mov ax,$33
    call a;
  end; }
  a($33, $11, 'sssss', s, s);
end.

 

汇编代码:
00407CA8   . 447C4000       DD Project1.00407C44
00407CAC > $ 55             PUSH EBP     //保存栈顶
00407CAD   . 8BEC           MOV EBP,ESP  //初始化堆?br>00407CAF   . 83C4 F0        ADD ESP,-10  //开?0个字节的?br>00407CB2   . B8 6C7C4000    MOV EAX,Project1.00407C6C
00407CB7   . E8 34C7FFFF    CALL Project1.004043F0
00407CBC   . 33C0           XOR EAX,EAX  //EAX?
00407CBE   . 55             PUSH EBP     //保存栈顶
00407CBF   . 68 037D4000    PUSH Project1.00407D03  //保存q回地址
00407CC4   . 64:FF30        PUSH DWORD PTR FS:[EAX]  //
00407CC7   . 64:8920        MOV DWORD PTR FS:[EAX],ESP  //
00407CCA   . B8 48984000    MOV EAX,Project1.00409848 
00407CCF   . BA 187D4000    MOV EDX,Project1.00407D18                ;  ASCII "sssssssssss"  //初始化局部变?br>00407CD4   . E8 2FB9FFFF    CALL Project1.00403608  
00407CD9   . 68 2C7D4000    PUSH Project1.00407D2C                   ;  ASCII "jjjjjjjjjj" 
00407CDE   . 68 407D4000    PUSH Project1.00407D40                   ;  ASCII "ffffffffffff"
00407CE3   . B9 587D4000    MOV ECX,Project1.00407D58                ;  ASCII "sssss"
00407CE8   . 66:BA 1100     MOV DX,11
00407CEC   . 66:B8 3300     MOV AX,33
00407CF0   . E8 9BFEFFFF    CALL Project1.00407B90                   //调用函数
00407CF5   . 33C0           XOR EAX,EAX
00407CF7   . 5A             POP EDX
00407CF8   . 59             POP ECX
00407CF9   . 59             POP ECX
00407CFA   . 64:8910        MOV DWORD PTR FS:[EAX],EDX
00407CFD   . 68 0A7D4000    PUSH Project1.00407D0A
00407D02   > C3             RETN                                     ;  RET used as a jump to 00407D0A

00407D03   .^E9 D4B2FFFF    JMP Project1.00402FDC
00407D08   .^EB F8          JMP SHORT Project1.00407D02
00407D0A     E8             DB E8
00407D0B     B5             DB B5
00407D0C     B7             DB B7
00407D0D     FF             DB FF
00407D0E     FF             DB FF
00407D0F     00             DB 00
00407D10   . FFFFFFFF       DD FFFFFFFF
00407D14   . 0B000000       DD 0000000B
00407D18   . 73 73 73 73 73>ASCII "sssssssssss",0
00407D24   . FFFFFFFF       DD FFFFFFFF
00407D28   . 0A000000       DD 0000000A
00407D2C   . 6A 6A 6A 6A 6A>ASCII "jjjjjjjjjj",0
00407D37     00             DB 00
00407D38   . FFFFFFFF       DD FFFFFFFF
00407D3C   . 0C000000       DD 0000000C
00407D40   . 66 66 66 66 66>ASCII "ffffffffffff",0
00407D4D     00             DB 00
00407D4E     00             DB 00
00407D4F     00             DB 00
00407D50   . FFFFFFFF       DD FFFFFFFF
00407D54   . 05000000       DD 00000005
00407D58   . 73 73 73 73 73>ASCII "sssss",0


function a(d, dd: word; s, j, f: string): word;
函数的代?

00407B90  /$ 55             PUSH EBP
00407B91  |. 8BEC           MOV EBP,ESP
00407B93  |. 6A 00          PUSH 0
00407B95  |. 6A 00          PUSH 0
00407B97  |. 6A 00          PUSH 0
00407B99  |. 53             PUSH EBX
00407B9A  |. 56             PUSH ESI
00407B9B  |. 57             PUSH EDI
00407B9C  |. 894D FC        MOV DWORD PTR SS:[EBP-4],ECX
00407B9F  |. 8BF2           MOV ESI,EDX
00407BA1  |. 8BD8           MOV EBX,EAX
00407BA3  |. 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
00407BA6  |. E8 49BDFFFF    CALL Project1.004038F4
00407BAB  |. 8B45 0C        MOV EAX,DWORD PTR SS:[EBP+C]
00407BAE  |. E8 41BDFFFF    CALL Project1.004038F4
00407BB3  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00407BB6  |. E8 39BDFFFF    CALL Project1.004038F4
00407BBB  |. 33C0           XOR EAX,EAX
00407BBD  |. 55             PUSH EBP
00407BBE  |. 68 317C4000    PUSH Project1.00407C31
00407BC3  |. 64:FF30        PUSH DWORD PTR FS:[EAX]
00407BC6  |. 64:8920        MOV DWORD PTR FS:[EAX],ESP
00407BC9  |. 4B             DEC EBX
00407BCA  |. 8D3C1E         LEA EDI,DWORD PTR DS:[ESI+EBX]
00407BCD  |. 6A 00          PUSH 0
00407BCF  |. 8D55 F8        LEA EDX,DWORD PTR SS:[EBP-8]
00407BD2  |. 0FB7C6         MOVZX EAX,SI
00407BD5  |. E8 5AD6FFFF    CALL Project1.00405234
00407BDA  |. 8B45 F8        MOV EAX,DWORD PTR SS:[EBP-8]
00407BDD  |. E8 22BDFFFF    CALL Project1.00403904
00407BE2  |. 50             PUSH EAX
00407BE3  |. 8D55 F4        LEA EDX,DWORD PTR SS:[EBP-C]
00407BE6  |. 0FB7C3         MOVZX EAX,BX
00407BE9  |. E8 46D6FFFF    CALL Project1.00405234
00407BEE  |. 8D45 F4        LEA EAX,DWORD PTR SS:[EBP-C]
00407BF1  |. 8B55 FC        MOV EDX,DWORD PTR SS:[EBP-4]
00407BF4  |. E8 33BCFFFF    CALL Project1.0040382C
00407BF9  |. 8B45 F4        MOV EAX,DWORD PTR SS:[EBP-C]
00407BFC  |. E8 03BDFFFF    CALL Project1.00403904
00407C01  |. 50             PUSH EAX                                 ; |Text
00407C02  |. 6A 00          PUSH 0                                   ; |hOwner = NULL
00407C04  |. E8 23C9FFFF    CALL <JMP.&user32.MessageBoxA>           ; \MessageBoxA  //q里stdcall方式调用messagebox
00407C09  |. 33C0           XOR EAX,EAX
00407C0B  |. 5A             POP EDX
00407C0C  |. 59             POP ECX
00407C0D  |. 59             POP ECX
00407C0E  |. 64:8910        MOV DWORD PTR FS:[EAX],EDX
00407C11  |. 68 387C4000    PUSH Project1.00407C38
00407C16  |> 8D45 F4        LEA EAX,DWORD PTR SS:[EBP-C]
00407C19  |. BA 03000000    MOV EDX,3
00407C1E  |. E8 B5B9FFFF    CALL Project1.004035D8
00407C23  |. 8D45 08        LEA EAX,DWORD PTR SS:[EBP+8]
00407C26  |. BA 02000000    MOV EDX,2
00407C2B  |. E8 A8B9FFFF    CALL Project1.004035D8
00407C30  \. C3             RETN

 

 

debug registers :
eax 00000000
ecx 00010101
edx ffffffff
ebx 7ffdf000
esp 0012ffc0  
ebp 0012fff0
esi 00000000
edi 0012d870
eip 00407cad project1.<ModuleEntryPoint>

00407CCA . B8 48984000 MOV EAX,Project1.00409848
00407CCF . BA 187D4000 MOV EDX,Project1.00407D18 ; ASCII "sssssssssss" //初始化局部变?
00407CD4 . E8 2FB9FFFF CALL Project1.00403608
00407CD9 . 68 2C7D4000 PUSH Project1.00407D2C ; ASCII "jjjjjjjjjj"
00407CDE . 68 407D4000 PUSH Project1.00407D40 ; ASCII "ffffffffffff"
00407CE3 . B9 587D4000 MOV ECX,Project1.00407D58 ; ASCII "sssss"
00407CE8 . 66:BA 1100 MOV DX,11
00407CEC . 66:B8 3300 MOV AX,33
00407CF0 . E8 9BFEFFFF CALL Project1.00407B90 //调用函数

函数原型为function a(d, dd: word; s, j, f: string): word;
他的执行序?先把J ,f 压栈 , ?s 存入 ecx ,然后,? dd,d 分别存入 dx ?ax ,delphi到底按照什么顺序来处理参数d?br>
Directive Parameter order Clean-upPasses parameters in registers?
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No

参数传递方?
Delphi中有自己的参C递方?而Windows API也有自己的参C递方?那么他们之间有什么不同呢,要如何做到兼容呢,其是在~写动态库?
(1)cdecl:
通常是C/C++所使用的参C递方?它的传递方式是由右到左,而且当被调用的函数结束之?会p用函数本w来清除堆栈上的参数数据.
(2)stdcall:
参数传递方?也是由右到左,但是当被调用的函数结束之?则是p调用函数来清除堆栈上的参数数?Win32API所有的输出函数都是采用此中参数传递方?
(3)pascal:
是Delphi1.0与win16API所使用的参C递方?它的传递方式是由左到右,而且p调用函数来清除堆栈上的参数数?
(4)fastcall:
是Delphi默认所使用的参C递方?此种方式在传递参数时把前三个参数攑֜CPU的EAX,EDX,ECX三个~存器种,剩下的参数则会由左到叛_被取出放到堆栈中,而当被调用的函数l束? ?则是p调用函数来清除堆栈上的参数数?
?所以在引用C++动态库中的函数?要注意参数的传递方?一般用stdcall.q要注意字符串类?C++在传递字W串?都是采用字符指针? cd(Char *),所以你在Delphi的程序中必 M用PCHARcd,而不是stringcd.

Delphi~译代码和一般的C~译代码不太一P比如调用U定中,C的thiscall用ECX传递this指针Q而Delphi的thiscall? EAX传递this指针QC的fastcall一般用ECX/EDX两个寄存器用于参C递,而Delphi则用三个EAX/EDX/ECXQ在使用点 数时QC通过压栈两个DWORD传递double参数Q而Delphi则用FLD和FSTP直接通过FPU传递参数。修饰名也不一Pq里不加叙述?



关于调用U定参?http://baby.homeip.net/patrick/archives/000142.php



目前的IDA不支持加蝲.MAP/.SYMW号信息Q根据DataRescue|站的说明,可以通过.IDC脚本加蝲Q?a target="_new" >http://www.ccso.com/faq.htmlQ。DeDe的IDA/SofticeW号输出中据说可以自动检运行的Soft-ICEq向其导入符P但实际用时不是很灵光,Ҏ.MAP文g格式可以写一个程序将其{换成.IDC脚本Q?



#!/usr/bin/perl

use strict;

sub dump_idc;



my $hex_pat = "[0-9A-Fa-f]+";



my $start;

my @entries;



while (<>) {

chop;

if ($start eq ''--fetch-next'') {

# start, length, name, class

($start) = m/$hex_pat:($hex_pat)\s+($hex_pat)H\s+(\w+)\s+(\w+)/;

if (!$start) {

print STDERR "Invalid .map file format!";

exit -1;

}

$start = hex($start);

next;

}



if (m/Start\s+Length\s+Name\s+Class/) {

$start = ''--fetch-next'';

next;

}



if (m/$hex_pat:($hex_pat)\s*(.*)$/) {

my ($offset, $entry) = (hex($1), $2);

my $rva = $offset + $start;

push @entries, [$rva, $entry];

}

}



@entries = sort { $a->[0] cmp $b->[0] } @entries;



&dump_idc;



sub dump_idc {

print "static main() {\n";



foreach (@entries) {

my ($rva, $entry) = @$_;

#$rva = hex($rva);



$entry =~ s/^\*/\$/;

$entry =~ s/^[<>\-]*//;

$entry =~ s/\(.*$//;

$entry =~ s/:.*$//;

$entry =~ s/\./?/;

$entry =~ s/\[([0-9]+)\]/_$1/g;

$entry =~ s/\[.*$/_$rva/;

$entry =~ s/;.*$//;



$entry =~ s/^\s *//;

next if !$entry;



printf "MakeName(0x%x, \"$entry\");\n", $rva, $entry;

}



print "}\n";

}



1;



有些E序在检验注册码旉过抛出异常{行为确定是否注册成功,关于异常Matt Pietrek有一著名文?a target="_new" >http://www.microsoft.com/msj/0197/Exception/Exception.aspx值得一?/a>。从汇编代码上看Q所有try/catch块都有类似的l构Q?



CODE:004BDE4C xor eax, eax

CODE:004BDE4E push ebp

CODE:004BDE4F push offset loc_4BDE92

CODE:004BDE54 push dword ptr fs:[eax] ; 保存上一个handler

CODE:004BDE57 mov fs:[eax], esp



CODE:004BDE92 loc_4BDE92:

CODE:004BDE92 jmp _Any2_Handler_DevErr?

CODE:004BDE97 jmp short loc_4BDE89



CODE:004BDEEA pop edx ; 上一个handler

CODE:004BDEEB pop ecx

CODE:004BDEEC pop ecx

CODE:004BDEED mov fs:[eax], edx ; 恢复



注意?BDE97H处代码未被执行,q是怎么回事呢?原来它是finally对应的块QSEH内核会根据push offset loc_4BDE92自动得到4BDE97H的finally入口地址。因此在调试有异常处理的E序Ӟ有时需要在handler和finally的处? E序处也讄断点?



今天先到q里Q可能的话下ơ再贴?

在周爱民的著作《DELPHI源代码分析》中Q对此有描述?br>


Khan's Notebook 2004-11-22 22:14 发表评论
]]>
昨天开始打写cmpp3.0的网?于是拿了华ؓ的demo反编译了一?发现n多汉字都~程了unicode~码,于是自己写了一个unicode转汉字的E序,sharel大?/title><link>http://www.shnenglu.com/Khan/archive/2004/11/19/2643.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 18 Nov 2004 21:44:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2004/11/19/2643.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2643.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2004/11/19/2643.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2643.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2643.html</trackback:ping><description><![CDATA[几个转码的函?unicode string utf8 anscii 之间的{?delphi<img src="http://blog.codelphi.com/liukun966123/aggbug/29139.aspx" height="1" width="1"><br><br><p><font face="Courier New">/** ȝ?包含几个转码的函?/font></p> <p><font face="Courier New">*   作?刘昆 </font></p> <p><font face="Courier New">*   最后修Ҏ?  2004-11-18 </font></p> <p><font face="Courier New">*   以上代码免费,若直接引用一下代码请告知,q保留此注释</font></p> <p><font face="Courier New">*   作ؓ一名程序员应该有最基本的职业道?/</font></p> <p>unit MainForm;</p> <p>interface</p> <p>uses<br>  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br>  Dialogs, StdCtrls, ExtCtrls;</p> <p>type<br>  TFormMain = class(TForm)<br>    Panel1: TPanel;<br>    Memo1: TMemo;<br>    ComboBox1: TComboBox;<br>    Button1: TButton;<br>    Memo2: TMemo;<br>    procedure Button1Click(Sender: TObject);<br>  private<br>    function StrToUTF8(str: WideString): string;<br>    function StrToASC(Str: string): string;<br>    function GB2Unicode(Str: WideString): string; overload;<br>    //function GB2Unicode(Str: string): string; overload;<br>    function U2GB(Str: string): string;<br>    function UTF8ToStr(const str: UTF8String): string;<br>    function HexToInt(const Str: string): integer;<br>    function HexIndex(const c: Char): Integer;<br>    { Private declarations }<br>  public<br>    { Public declarations }<br>  end;</p> <p>var<br>  FormMain: TFormMain;</p> <p>implementation</p> <p>{$R *.dfm}</p> <p>{ TFormMain }</p> <p>function TFormMain.StrToASC(Str: string): string;<br>var<br>  TmpStr: string;<br>  TmpPchar: Pchar;<br>  i: integer;<br>begin<br>  result := '';<br>  TmpStr := '';<br>  TmpPchar := pchar(Str);<br>  for i := 0 to length(TmpPchar) - 1 do<br>    TmpStr := TmpStr + format('%2.2x', [ord(TmpPchar[i])]);</p> <p>  result := TmpStr;<br>end;</p> <p>function TFormMain.StrToUTF8(str: WideString): string;<br>var<br>  s: pchar;<br>  i: integer;<br>  tmp: string;<br>begin<br>  tmp := '';<br>  result := '';<br>  s := pchar(Utf8encode(str));<br>  for i := 0 to strlen(s) do begin<br>    tmp := tmp + format('%2.2x', [ord(s[i])]);<br>  end;<br>  result := tmp;<br>end;</p> <p><br>function TFormMain.UTF8ToStr(const str: UTF8String): string;<br>var<br>  s: pchar;<br>  i: integer;<br>  tmp: string;<br>begin<br>  tmp := '';<br>  result := '';<br>  s := PChar(str);<br>  i := 0;<br>  while i < length(s) do begin<br>    tmp := tmp + chr(HexToInt(s[i] + s[i + 1]));<br>    inc(i, 2);<br>  end;<br>  result := Utf8Decode(tmp);<br>end;</p> <p>function TFormMain.GB2Unicode(Str: WideString): string;<br>var<br>  i: Integer;<br>begin<br>  Result := '';<br>  for i := 1 to Length(Str) do<br>    Result := Result + Format('%4.4x', [ord(Str[i])]);<br>end;</p> <p><br>procedure TFormMain.Button1Click(Sender: TObject);<br>begin<br>  case ComboBox1.ItemIndex of<br>    0: memo2.Lines.Add(GB2Unicode(memo1.Lines.Text));<br>    1: memo2.Lines.Add(StrToUTF8(memo1.Lines.Text));<br>    2: memo2.Lines.Add(UTF8ToStr(memo1.Lines.Text));<br>    3: memo2.Lines.Add(U2GB(StringReplace(memo1.Lines.Text, '\u', '', [rfReplaceAll])));<br>    4: memo2.Lines.Add(StrToASC(memo1.Lines.Text));<br>  end;<br>end;</p> <p>function TFormMain.HexToInt(const Str: string): integer;<br>var p: pchar;</p> <p>begin<br>  result := -1;<br>  if length(str) > 2 then exit;<br>  p := pchar(str);</p> <p>  if (HexIndex(p[0]) <> -1) and (HexIndex(p[1]) <> -1) then<br>    result := HexIndex(p[0]) * $10 + HexIndex(p[1]);<br>end;</p> <p>function TFormMain.HexIndex(const c: Char): Integer;<br>const Digits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');<br>var i: integer;<br>begin<br>  result := -1;<br>  if (not (UpCase(c) in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'])) then<br>    exit;</p> <p>  for i := 0 to high(digits) do<br>    if Digits[i] = UpCase(c) then begin<br>      result := i;<br>      break;<br>    end;<br>end;</p> <p><br>function TFormMain.U2GB(Str: string): string;<br>var s: pchar;<br>  i: integer;<br>  tmp: string;<br>begin<br>  tmp := '';<br>  result := '';<br>  s := PChar(str);<br>  i := 0;<br>  while i < length(s) do begin<br>    tmp := tmp + chr(HexToInt(s[i + 2] + s[i + 3])) + chr(HexToInt(s[i] + s[i + 1]));//unicode转换?高低位互?br>    inc(i, 4);<br>  end;<br>  result := widechartostring(pWideChar(tmp + #0#0#0#0));<br>end;</p> <p>end.</p><br><img src ="http://www.shnenglu.com/Khan/aggbug/2643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-19 05:44 <a href="http://www.shnenglu.com/Khan/archive/2004/11/19/2643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>起因源于之前忘记一个adsl的端?惛_一个端口探工?止于sp的订购关pd?/title><link>http://www.shnenglu.com/Khan/archive/2004/11/12/2644.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 11 Nov 2004 19:25:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2004/11/12/2644.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2644.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2004/11/12/2644.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2644.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2644.html</trackback:ping><description><![CDATA[虽然只有q么点东?但我q是做了3?老了<br><br> 一个sp用的wap订购关系包调试检工?img src="http://blog.codelphi.com/liukun966123/aggbug/28600.aspx" height="1" width="1"><br><br> <p> </p> <p><font face="Courier New">/** E序的核?一个postU程,用于提交xml数据?/font></p> <p><font face="Courier New">*   作?刘昆 </font></p> <p><font face="Courier New">*   最后修Ҏ?  2004-9-23 </font></p> <p><font face="Courier New">*   以上代码免费,若直接引用一下代码请告知,q保留此注释</font></p> <p><font face="Courier New">*   作ؓ一名程序员应该有最基本的职业道?/</font></p> <p><font face="Courier New">unit HTTPGetThread;</font></p> <p><font face="Courier New">interface<br>uses classes, SysUtils, wininet, windows;</font></p> <p><br><font face="Courier New">type<br>  TOnProgressEvent = procedure(TotalSize, Readed: Integer) of object;</font></p> <p><br><font face="Courier New">  THTTPGetThread = class(TThread)</font></p> <p><font face="Courier New">  private<br>    FTAcceptTypes: string; //接收文gcd *.*<br>    FTAgent: string; //览器名  Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.02<br>    FTURL: string; // url<br>    FTFileName: string; //文g?br>    FTStringResult: AnsiString;<br>    FTUserName: string; //用户?br>    FTPassword: string; //密码<br>    FTPostQuery: string; //Ҏ?post或者get<br>    FTReferer: string;<br>    FTBinaryData: Boolean;<br>    FTUseCache: Boolean; //是否从缓存读数据<br>    FTMimeType: string; //Mimecd</font></p> <p><font face="Courier New">    FTResult: Boolean;<br>    FTFileSize: Integer;<br>    FTToFile: Boolean; //是否文g</font></p> <p><font face="Courier New">    BytesToRead, BytesReaded: LongWord;</font></p> <p><font face="Courier New">    FTProgress: TOnProgressEvent;<br>    procedure ParseURL(URL: string; var HostName, FileName: string; var portNO: integer); //取得url的主机名和文件名<br>    procedure UpdateProgress;<br>  protected<br>    procedure Execute; override;<br>  public<br>    procedure setResult(FResult: boolean);<br>    function getResult(): boolean;<br>    function getFileName(): string;<br>    function getToFile(): boolean;<br>    function getFileSize(): integer;<br>    function getStringResult(): AnsiString;<br>    constructor Create(aAcceptTypes, aMimeType, aAgent, aURL, aFileName, aUserName, aPassword, aPostQuery, aReferer: string; aBinaryData, aUseCache: Boolean; aProgress: TOnProgressEvent; aToFile: Boolean);</font></p> <p><font face="Courier New">  end;</font></p> <p><font face="Courier New">implementation</font></p> <p><font face="Courier New">{ THTTPGetThread }</font></p> <p><font face="Courier New">constructor THTTPGetThread.Create(aAcceptTypes, aMimeType, aAgent, aURL, aFileName, aUserName, aPassword, aPostQuery, aReferer: string; aBinaryData, aUseCache: Boolean; aProgress: TOnProgressEvent; aToFile: Boolean);<br>begin<br>  FreeOnTerminate := True;<br>  inherited Create(True);</font></p> <p><font face="Courier New">  FTAcceptTypes := aAcceptTypes;<br>  FTAgent := aAgent;<br>  FTURL := aURL;<br>  FTFileName := aFileName;<br>  FTUserName := aUserName;<br>  FTPassword := aPassword;</font></p> <p><font face="Courier New">  //FTPostQuery := aPostQuery;</font></p> <p><font face="Courier New">  FTPostQuery := StringReplace(aPostQuery, #13#10, '', [rfReplaceAll]);</font></p> <p><font face="Courier New">  FTReferer := aReferer;<br>  FTProgress := aProgress;<br>  FTBinaryData := aBinaryData;<br>  FTUseCache := aUseCache;<br>  FTMimeType := aMimeType;</font></p> <p><font face="Courier New">  FTToFile := aToFile;<br>  Resume;<br>end;</font></p> <p><font face="Courier New">procedure THTTPGetThread.Execute;<br>var<br>  hSession: hInternet; //回话句柄<br>  hConnect: hInternet; //q接句柄<br>  hRequest: hInternet; //h句柄<br>  Host_Name: string; //L?br>  File_Name: string; //文g?br>  port_no: integer;</font></p> <p><font face="Courier New">  RequestMethod: PChar;<br>  InternetFlag: longWord;<br>  AcceptType: PAnsiChar;<br>  dwBufLen, dwIndex: longword;<br>  Buf: Pointer; //~冲?br>  f: file;<br>  Data: array[0..$400] of Char;<br>  TempStr: AnsiString;<br>  mime_Head: string;</font></p> <p><font face="Courier New">  procedure CloseHandles;<br>  begin<br>    InternetCloseHandle(hRequest);<br>    InternetCloseHandle(hConnect);<br>    InternetCloseHandle(hSession);<br>  end;</font></p> <p><font face="Courier New">begin<br>  inherited;<br>  buf := nil;<br>  try<br>    try<br>      ParseURL(FTURL, Host_Name, File_Name, port_no);</font></p> <p><font face="Courier New">      if Terminated then begin<br>        FTResult := False;<br>        Exit;<br>      end;<br>     //建立会话<br>      hSession := InternetOpen(pchar(FTAgent), //lpszCallerName指定正在使用|络函数的应用程?br>        INTERNET_OPEN_TYPE_PRECONFIG, //参数dwAccessType指定讉Kcd<br>        nil, //服务器名QlpszProxyNameQ?accesstype为GATEWAY_PROXY_INTERNET_ACCESS和CERN_PROXY_ACCESS?br>        nil, //NProxyPort参数用在CERN_PROXY_INTERNET_ACCESS中用来指定用的端口数。用INTERNET_INVALID_PORT_NUMBER相当于提供却省的端口数?br>        0); //讄额外的选择。你可以使用INTERNET_FLAG_ASYNC标志LCZ用返回句句柄的将来的Internet函数ؓ回调函数发送状态信息,使用InternetSetStatusCallbackq行此项讄</font></p> <p><font face="Courier New">     //建立q接<br>      hConnect := InternetConnect(hSession, //会话句柄<br>        PChar(Host_Name), //指向包含Internet服务器的L名称Q如</font><a ><font face="Courier New">http://www.mit.edu</font></a><font face="Courier New">Q或IP地址Q如202.102.13.141Q的字符?br>        port_no, //INTERNET_DEFAULT_HTTP_PORT, //是将要连l到的TCP/IP的端口号<br>        PChar(FTUserName), //用户?br>        PChar(FTPassword), //密码<br>        INTERNET_SERVICE_HTTP, //协议<br>        0, // 可选标讎ͼ讄为INTERNET_FLAG_SECUREQ表CZ用SSL/PCT协议完成事务<br>        0); //应用E序定义的|用来回的句柄标识应用E序讑֤场境</font></p> <p><font face="Courier New">      if FTPostQuery = '' then RequestMethod := 'GET'<br>      else RequestMethod := 'POST';</font></p> <p><font face="Courier New">      if FTUseCache then InternetFlag := 0<br>      else InternetFlag := INTERNET_FLAG_RELOAD;</font></p> <p><font face="Courier New">      AcceptType := PChar('Accept: ' + FTAcceptTypes);</font></p> <p><font face="Courier New">    //建立一个httph句柄<br>      hRequest := HttpOpenRequest(hConnect, //InternetConnectq回的HTTP会话句柄<br>        RequestMethod, //指向在申请中使用?动词"的字W串Q如果设|ؓNULLQ则使用"GET"<br>        PChar(File_Name), //指向包含动词的目标对象名U的字符Ԍ通常是文件名U、可执行模块或搜索说明符<br>        'HTTP/1.0', //指向包含HTTP版本的字W串Q如果ؓNULLQ则默认?HTTP/1.0"Q?br>        PChar(FTReferer), //指向包含文档地址QURLQ的字符Ԍ甌的URL必须是从该文档获取的<br>        @AcceptType, //指向客户接收的内容的cd<br>        InternetFlag,<br>        0);<br>      mime_Head := 'Content-Type: ' + FTMimeType;<br>      if FTPostQuery = '' then<br>        FTResult := HttpSendRequest(hRequest, nil, 0, nil, 0)<br>      else<br>    //发送一个指定请求到httpserver<br>        FTResult := HttpSendRequest(hRequest,<br>          pchar(mime_Head), //mime ?br>          length(mime_Head), //头长?br>          PChar(FTPostQuery), //附加数据~冲区,可ؓI?br>          strlen(PChar(FTPostQuery))); //附加数据~冲区长?/font></p> <p><font face="Courier New">      if Terminated then<br>      begin<br>      //CloseHandles;<br>        FTResult := False;<br>        Exit;<br>      end;</font></p> <p><font face="Courier New">      dwIndex := 0;<br>      dwBufLen := 1024;<br>      GetMem(Buf, dwBufLen);</font></p> <p><font face="Courier New">    //接收header信息和一个httph<br>      FTResult := HttpQueryInfo(hRequest,<br>        HTTP_QUERY_CONTENT_LENGTH,<br>        Buf, //指向一个接收请求信息的~冲区的指针<br>        dwBufLen, //HttpQueryInfo内容的大?br>        dwIndex); //d的字节数</font></p> <p><font face="Courier New">      if Terminated then begin<br>        FTResult := False;<br>        Exit;<br>      end;</font></p> <p><font face="Courier New">      if FTResult or not FTBinaryData then begin //如果h<br>        if FTResult then<br>          FTFileSize := StrToInt(StrPas(Buf));</font></p> <p><font face="Courier New">        BytesReaded := 0;</font></p> <p><font face="Courier New">        if FTToFile then begin<br>          AssignFile(f, FTFileName);<br>          Rewrite(f, 1);<br>        end else FTStringResult := '';</font></p> <p><font face="Courier New">        while True do begin<br>          if Terminated then begin<br>            FTResult := False;<br>            Exit;<br>          end;</font></p> <p><font face="Courier New">          if not InternetReadFile(hRequest,<br>            @Data, //数据内容<br>            SizeOf(Data), //大小<br>            BytesToRead) //d的字节数<br>            then Break<br>          else<br>            if BytesToRead = 0 then Break<br>            else begin<br>              if FTToFile then<br>                BlockWrite(f, Data, BytesToRead) //读出的数据写入文g<br>              else begin<br>                TempStr := Data;<br>                SetLength(TempStr, BytesToRead);<br>                FTStringResult := FTStringResult + TempStr;<br>              end;</font></p> <p><font face="Courier New">              inc(BytesReaded, BytesToRead);</font></p> <p><font face="Courier New">              if Assigned(FTProgress) then //执行回调函数<br>                Synchronize(UpdateProgress);</font></p> <p><font face="Courier New">            end;<br>        end;</font></p> <p><font face="Courier New">        if FTToFile then<br>          FTResult := FTFileSize = Integer(BytesReaded)<br>        else begin<br>         // SetLength(FTStringResult, BytesReaded);<br>          FTResult := BytesReaded <> 0;<br>        end;</font></p> <p><font face="Courier New">      end;<br>    except<br>    end;<br>  finally<br>    if FTToFile then CloseFile(f);</font></p> <p><font face="Courier New">    if assigned(Buf) then FreeMem(Buf);<br>    CloseHandles;<br>  end;<br>end;</font></p> <p> </p> <p><font face="Courier New">function THTTPGetThread.getFileName: string;<br>begin<br>  result := FTFileName;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getFileSize: integer;<br>begin<br>  result := FTFileSize;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getResult: boolean;<br>begin<br>  result := FTResult;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getStringResult: AnsiString;<br>begin<br>  result := FTStringResult;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getToFile: boolean;<br>begin<br>  result := FTToFile;<br>end;</font></p> <p><font face="Courier New">procedure THTTPGetThread.ParseURL(URL: string; var HostName, FileName: string; var portNO: integer);<br>var<br>  i: Integer;<br>begin<br>  if Pos('http://', LowerCase(URL)) <> 0 then<br>    Delete(URL, 1, 7);</font></p> <p><font face="Courier New">  i := Pos('/', URL);<br>  HostName := Copy(URL, 1, i);<br>  FileName := Copy(URL, i, Length(URL) - i + 1);</font></p> <p><font face="Courier New">  i := pos(':', hostName);<br>  if i <> 0 then begin<br>    portNO := strtoint(copy(hostName, i + 1, length(hostName) - i - 1));<br>    hostName := copy(hostName, 1, i - 1);<br>  end else portNO := 80;</font></p> <p><font face="Courier New">  if (Length(HostName) > 0) and (HostName[Length(HostName)] = '/') then SetLength(HostName, Length(HostName) - 1);<br>end;</font></p> <p><br><font face="Courier New">procedure THTTPGetThread.setResult(FResult: boolean);<br>begin<br>  FTResult := FResult;<br>end;</font></p> <p><font face="Courier New">procedure THTTPGetThread.UpdateProgress;<br>begin<br>  FTProgress(FTFileSize, BytesReaded);<br>end;</font></p> <p><font face="Courier New">end.</font></p> <p> </p> <p><font face="Courier New">/** 主要用来做线E和界面的交?/font></p> <p><font face="Courier New">*   作?刘昆 </font></p> <p><font face="Courier New">*   最后修Ҏ?  2004-9-23 </font></p> <p><font face="Courier New">*   以上代码免费,若直接引用一下代码请告知,q保留此注释</font></p> <p><font face="Courier New">*   作ؓ一名程序员应该有最基本的职业道?/</font></p> <p><font face="Courier New">unit MyHttpGet;</font></p> <p><font face="Courier New">interface</font></p> <p><font face="Courier New">uses HTTPGetThread, windows;</font></p> <p><font face="Courier New">type<br>  TOnDoneFileEvent = procedure(FileName: string; FileSize: Integer) of object;<br>  TOnDoneStringEvent = procedure(Result: AnsiString) of object;</font></p> <p><br><font face="Courier New">  THttpGet = class<br>  private<br>    F_URL: string; //目标url<br>    F_GetURLThread: THTTPGetThread; //取数据的U程</font></p> <p><font face="Courier New">    F_Accept_Types: string;<br>    F_Agent: string;<br>    F_Binary_Data: Boolean;<br>    F_Use_Cache: Boolean; //是否ȝ?br>    F_File_Name: string;<br>    F_User_Name: string; //用户?br>    F_Password: string; //密码<br>    F_PostQuery: string; //Ҏ?br>    F_Referer: string;<br>    F_Mime_Type: string;</font></p> <p><font face="Courier New">    F_Wait_Thread: Boolean;</font></p> <p><font face="Courier New">    FResult: Boolean;</font></p> <p><font face="Courier New">    FProgress: TOnProgressEvent;<br>    FDoneFile: TOnDoneFileEvent;<br>    FDoneString: TOnDoneStringEvent;</font></p> <p><font face="Courier New">    procedure ThreadDone(Sender: TObject);</font></p> <p><font face="Courier New">  public<br>    constructor Create();<br>    destructor Destroy(); override;<br>    procedure getFile();<br>    procedure GetString();<br>    procedure Abort();<br>  published<br>    property WaitThread: Boolean read F_Wait_Thread write F_Wait_Thread;<br>    property AcceptTypes: string read F_Accept_Types write F_Accept_Types;<br>    property Agent: string read F_Agent write F_Agent;<br>    property BinaryData: Boolean read F_Binary_Data write F_Binary_Data;<br>    property URL: string read F_URL write F_URL;<br>    property UseCache: Boolean read F_Use_Cache write F_Use_Cache;<br>    property FileName: string read F_File_Name write F_File_Name;<br>    property UserName: string read F_User_Name write F_User_Name;<br>    property Password: string read F_Password write F_Password;<br>    property PostQuery: string read F_PostQuery write F_PostQuery;<br>    property Referer: string read F_Referer write F_Referer;<br>    property MimeType: string read F_Mime_Type write F_Mime_Type;</font></p> <p><font face="Courier New">    property OnDoneFile: TOnDoneFileEvent read FDoneFile write FDoneFile;<br>    property OnDoneString: TOnDoneStringEvent read FDoneString write FDoneString;<br>  end;</font></p> <p><font face="Courier New">implementation</font></p> <p> </p> <p><font face="Courier New">{ THttpGet }</font></p> <p><font face="Courier New">procedure THttpGet.Abort;<br>begin<br>  if Assigned(F_GetURLThread) then<br>  begin<br>    F_GetURLThread.Terminate;<br>    F_GetURLThread.setResult(false);<br>  end;<br>end;</font></p> <p><font face="Courier New">constructor THttpGet.Create;<br>begin<br>  F_Accept_Types := '*/*';<br>  F_Agent := 'Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.02';<br>end;</font></p> <p><font face="Courier New">destructor THttpGet.Destroy;<br>begin</font></p> <p><font face="Courier New">end;</font></p> <p><font face="Courier New">procedure THttpGet.getFile;<br>var<br>  Msg: TMsg;<br>begin<br>  if not Assigned(F_GetURLThread) then<br>  begin<br>    F_GetURLThread := THTTPGetThread.Create(F_Accept_Types,F_Mime_Type, F_Agent, F_URL, F_File_Name, F_User_Name, F_Password, F_PostQuery, F_Referer, F_Binary_Data, F_Use_Cache, FProgress, true);<br>    F_GetURLThread.OnTerminate := ThreadDone;<br>    if F_Wait_Thread then<br>      while Assigned(F_GetURLThread) do<br>        while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do<br>        begin<br>          TranslateMessage(Msg);<br>          DispatchMessage(Msg);<br>        end;<br>  end<br>end;</font></p> <p><font face="Courier New">procedure THttpGet.GetString;<br>var<br>  Msg: TMsg;<br>begin<br>  if not Assigned(F_GetURLThread) then<br>  begin<br>    F_GetURLThread := THTTPGetThread.Create(F_Accept_Types,F_Mime_Type,F_Agent, F_URL, F_File_Name, F_User_Name, F_Password, F_PostQuery, F_Referer, F_Binary_Data, F_Use_Cache, FProgress, False);<br>    F_GetURLThread.OnTerminate := ThreadDone;<br>    if F_Wait_Thread then<br>      while Assigned(F_GetURLThread) do<br>        while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin<br>          TranslateMessage(Msg);<br>          DispatchMessage(Msg);<br>        end;<br>  end<br>end;</font></p> <p><font face="Courier New">procedure THttpGet.ThreadDone(Sender: TObject);<br>begin<br>  FResult := F_GetURLThread.getResult;<br>  if FResult then<br>    if F_GetURLThread.getToFile then begin<br>      if Assigned(FDoneFile) then FDoneFile(F_GetURLThread.getFileName, F_GetURLThread.getFileSize)<br>    end else<br>      if Assigned(FDoneString) then FDoneString(F_GetURLThread.getStringResult);</font></p> <p><font face="Courier New">    //end else if Assigned(FError) then FError(Self);<br>  F_GetURLThread := nil;<br>end;</font></p> <p><font face="Courier New">end.</font></p> <p> </p> <p><font face="Courier New">/** E序ȝ?/font></p> <p><font face="Courier New">*   作?刘昆 </font></p> <p><font face="Courier New">*   最后修Ҏ?  2004-9-23 </font></p> <p><font face="Courier New">*   以上代码免费,若直接引用一下代码请告知,q保留此注释</font></p> <p><font face="Courier New">*   作ؓ一名程序员应该有最基本的职业道?/</font></p> <p><font face="Courier New">unit MainForm;</font></p> <p><font face="Courier New">interface</font></p> <p><font face="Courier New">uses<br>  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br>  Dialogs, StdCtrls, ExtCtrls, MyHttpGet;</font></p> <p><font face="Courier New">type<br>  TMain = class(TForm)<br>    Panel1: TPanel;<br>    Edit1: TEdit;<br>    Label1: TLabel;<br>    Panel2: TPanel;<br>    Panel3: TPanel;<br>    GroupBox1: TGroupBox;<br>    MeSend: TMemo;<br>    GroupBox2: TGroupBox;<br>    MeReceive: TMemo;<br>    Button1: TButton;<br>    CbSave: TCheckBox;<br>    Edit2: TEdit;<br>    Label2: TLabel;<br>    procedure Button1Click(Sender: TObject);<br>  private<br>    { Private declarations }<br>    procedure onGetString(Result: AnsiString);<br>    procedure onGetFile(FileName: string; FileSize: Integer);</font></p> <p><font face="Courier New">  public<br>    { Public declarations }<br>  end;</font></p> <p><font face="Courier New">var<br>  Main: TMain;</font></p> <p><font face="Courier New">implementation</font></p> <p><font face="Courier New">{$R *.dfm}</font></p> <p><br><font face="Courier New">procedure TMain.Button1Click(Sender: TObject);<br>var hg: THttpGet;<br>  strs: TStrings;<br>  i: Integer;<br>begin<br>  hg := nil;<br>  strs := nil;<br>  try<br>    strs := TStringList.Create;<br>    hg := THttpGet.Create;<br>    hg.WaitThread := false;<br>    hg.AcceptTypes := '*.*';</font></p> <p><font face="Courier New">    hg.Agent := 'Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.02';<br>    hg.BinaryData := false;<br>    hg.URL := 'Http://' + Edit1.Text;<br>    hg.UseCache := false;<br>    hg.FileName := 'provison.xml';<br>    hg.UserName := '';<br>    hg.Password := '';</font></p> <p><font face="Courier New">    for i := 0 to MeSend.Lines.Count - 1 do<br>      strs.Add(trim(MeSend.Lines[i]));</font></p> <p><font face="Courier New">    hg.PostQuery := strs.Text;<br>    hg.Referer := 'Http://' + Edit1.Text; //text/plain<br>    hg.MimeType := Edit2.Text;<br>    hg.OnDoneString := onGetString;<br>    hg.OnDoneFile := onGetFile;</font></p> <p><font face="Courier New">    hg.GetString;<br>  finally<br>    strs.Free;<br>    hg.Free;<br>  end;<br>end;</font></p> <p><br><font face="Courier New">procedure TMain.onGetFile(FileName: string; FileSize: Integer);<br>begin</font></p> <p><font face="Courier New">end;</font></p> <p><font face="Courier New">procedure TMain.onGetString(Result: AnsiString);<br>begin<br>  MeReceive.Lines.Text := Result;<br>end;</font></p> <p><font face="Courier New">end.</font></p><br><br><img src ="http://www.shnenglu.com/Khan/aggbug/2644.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-12 03:25 <a href="http://www.shnenglu.com/Khan/archive/2004/11/12/2644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>每个月都有那么几天让偶心?H然惛_一个控制modem或者adsl modem发传真的东西http://www.shnenglu.com/Khan/archive/2004/11/09/2645.htmlKhan's NotebookKhan's NotebookTue, 09 Nov 2004 13:45:00 GMThttp://www.shnenglu.com/Khan/archive/2004/11/09/2645.htmlhttp://www.shnenglu.com/Khan/comments/2645.htmlhttp://www.shnenglu.com/Khan/archive/2004/11/09/2645.html#Feedback1http://www.shnenglu.com/Khan/comments/commentRss/2645.htmlhttp://www.shnenglu.com/Khan/services/trackbacks/2645.html
       原因q因ؓ我家里有一部传真机,我想把他当打印机?仔细在网上找了一?发现没有什么资?只有一些Y件或控g.

        我发?要让q些把技术拽在手里饿?

        ?能写个把软g了不起啊,

        q个写完了以?照旧开?照旧不用W三Ҏ件或class



Khan's Notebook 2004-11-09 21:45 发表评论
]]>
关于delphi的log的class已经完成,一如既往的open ?/title><link>http://www.shnenglu.com/Khan/archive/2004/11/09/2646.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Tue, 09 Nov 2004 11:10:00 GMT</pubDate><guid>http://www.shnenglu.com/Khan/archive/2004/11/09/2646.html</guid><wfw:comment>http://www.shnenglu.com/Khan/comments/2646.html</wfw:comment><comments>http://www.shnenglu.com/Khan/archive/2004/11/09/2646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Khan/comments/commentRss/2646.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Khan/services/trackbacks/2646.html</trackback:ping><description><![CDATA[delphi ,日志class,临界?文g操作<img src="http://blog.codelphi.com/liukun966123/aggbug/28356.aspx" height="1" width="1"><br><br><br><p>如果你引用或者修改以下代?请不要去掉注?q个涉及C个程序员的职业道德问?/p><p>转蝲h?/p><p>/** 本代码ؓ日志class</p><p>*   作?刘昆 </p><p>*   最后修Ҏ?  2004-9-23 </p><p>*   以上代码免费,若直接引用一下代码请告知,q保留此注释</p><p>*   作ؓ一名程序员应该有最基本的职业道?/</p><p>unit pushLog;</p><p>interface</p><p>uses classes, sysutils, windows;</p><p>var<br>  ThreadLock: TRTLCriticalSection; //临界?/p><p><br>const PathDelim = '\';<br>  DriveDelim = ':';</p><p>type<br>  Tlog = class<br>  private<br>    //logfile: file;<br>    fileName: string;</p><p>    function dirExist(const DirName: string): boolean;<br>    function getDirName(const fileName: string): string;<br>    function LastDelimiter(const Delimiters, S: string): Integer;</p><p>    procedure createLogDir();</p><p><br>  public<br>    constructor Create(const filename: string);<br>    destructor Destroy(); override;</p><p>    procedure addLog(p: Pchar);<br>  end;</p><p>implementation</p><p><br>{ Tlog }</p><p>procedure Tlog.addLog(p: Pchar);<br>var log_Line: pchar;<br>  log_len: integer;<br>  handle: Thandle;<br>  des_Len: longword;<br>begin<br>  EnterCriticalSection(ThreadLock);<br>  log_Line := nil;<br>  handle := $0;<br>  des_Len := $0;<br>  try<br>    createLogDir;<br>    log_len := strlen(p);<br>    getmem(log_Line, log_len);<br>    strcopy(log_Line, p);</p><p>    handle := createfile(<br>      pchar(fileName), //文g?br>      GENERIC_READ or GENERIC_WRITE, //期望存取模式 通用d<br>      FILE_SHARE_READ or FILE_SHARE_WRITE, //׃n模式<br>      nil, //定义文g安全Ҏ的指针Q前提:操作pȝ支持Q?br>      OPEN_ALWAYS, //打开和创建文件方式?br>      FILE_ATTRIBUTE_NORMAL or FILE_FLAG_RANDOM_ACCESS, //要打开文g的标志和属性(如:隐藏Q系l等Q?br>      0); //模板文g句柄</p><p>    if handle <> INVALID_HANDLE_VALUE then begin<br>      SetFilePointer(handle, 0, nil, FILE_END);<br>      WriteFile(handle, log_Line^, log_len, des_Len, nil);</p><p>    end;<br>  finally<br>    CloseHandle(handle);<br>    freeMem(log_Line);<br>    LeaveCriticalSection(ThreadLock);<br>  end;<br>end;</p><p> </p><p>constructor Tlog.Create(const filename: string);<br>begin<br>  self.fileName := filename;<br>end;</p><p> </p><p><br>procedure Tlog.createLogDir;<br>var dir_Name: string;<br>begin<br>  dir_Name := getDirName(fileName) + '\log';<br>  if not DirExist(dir_Name) then begin //日志目录是否存?br>    mkdir(dir_Name);<br>  end;<br>end;</p><p> </p><p>destructor Tlog.Destroy;<br>begin<br>  inherited;<br>end;</p><p> </p><p>function Tlog.DirExist(const DirName: string): boolean;<br>var<br>  Handle: THandle;<br>  FindData: TWin32FindData;<br>begin<br>  result := false;<br>  Handle := FindFirstFile(PChar(DirName), FindData);<br>  if Handle <> INVALID_HANDLE_VALUE then begin<br>    FindClose(Handle);<br>    if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = $10 then begin<br>      result := true;<br>    end;<br>  end;<br>end;</p><p> </p><p>function Tlog.getDirName(const fileName: string): string;<br>var<br>  I: Integer;<br>begin<br>  I := LastDelimiter(':\', Filename);<br>  if (I > 1) and (FileName[I] = PathDelim) and (((FileName[I - 1] <> PathDelim) and (FileName[I - 1] <> DriveDelim)) or (ByteType(FileName, I - 1) = mbTrailByte)) then<br>    Dec(I);<br>  while (ByteType(FileName, I - 1) = mbTrailByte) and (I > 0) do<br>    Dec(I);<br>  Result := Copy(FileName, 1, I);<br>end;</p><p> </p><p> </p><p><br>function Tlog.LastDelimiter(const Delimiters, S: string): Integer;<br>var<br>  P: PChar;<br>begin<br>  Result := Length(S);<br>  P := PChar(Delimiters);<br>  while Result > 0 do<br>  begin<br>    if (S[Result] <> #0) and (StrScan(P, S[Result]) <> nil) then // 最后一个字W是否ؓ '\'或?:'<br>      if (ByteType(S, Result) = mbTrailByte) then<br>        Dec(Result)<br>      else<br>        Exit;<br>    Dec(Result);<br>  end;<br>end;</p><p> </p><p><br>initialization<br>  InitializeCriticalSection(ThreadLock);<br>finalization<br>  DeleteCriticalSection(ThreadLock);<br>end.<br></p><p> </p><p> </p><p>调用Ҏ</p><p>procedure TMain.Button1Click(Sender: TObject);<br>var<br>  log: Tlog;<br>begin</p><p>  log := Tlog.Create(ExtractFileDir(Application.Exename) + '\' + 'aa.log');<br>  log.addLog(pchar('好的' + #13#10));<br>  log.addLog(pchar('aaaaaaaaaaaaaaaaaaaa' + #13#10));<br>  log.Free;<br>end;</p><br><img src ="http://www.shnenglu.com/Khan/aggbug/2646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-09 19:10 <a href="http://www.shnenglu.com/Khan/archive/2004/11/09/2646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天H然惛_一个关于日志文件的class,用pascal,以前用java几简?pascal的这块反而没有接触过http://www.shnenglu.com/Khan/archive/2004/11/08/2647.htmlKhan's NotebookKhan's NotebookMon, 08 Nov 2004 13:27:00 GMThttp://www.shnenglu.com/Khan/archive/2004/11/08/2647.htmlhttp://www.shnenglu.com/Khan/comments/2647.htmlhttp://www.shnenglu.com/Khan/archive/2004/11/08/2647.html#Feedback1http://www.shnenglu.com/Khan/comments/commentRss/2647.htmlhttp://www.shnenglu.com/Khan/services/trackbacks/2647.html

文本文g是由若干行组成的Q若q个字符串组成一行,一行的l尾由回车换行符表示。如果对文本文gq行操作Q则首先应通过调用AssignFileq? E徏立文件变量与外部文g的联p,q且使用Reset或ReWrite或AppendҎ打开。由于文本文件是以行为单位进行读写操作的Qƈ且每一行的? 度不一定相同,所以不能计出指定行在文g中的准确位置Q因此对于文件只能顺序的d。要Ҏ件进行读写操作,必须相应的对文gq行以读或写的方式打开Q? 也就是对一个文本文件只能单独进行读或写的操作,而不能同时进行?/p>

1?以添加方式打开文g(Append)

通过调用函数Append可打开一个已l存在的文g以便在文件末添加文本。如果在文g最后的128个字节块中,存在字符〈ctrl?〈z〉(ASCII26Q,那么文g在字节处插入,q且覆盖该字W?/p>

Appendq程的声明如下:
procedure Append(var F:text);

? 中F是一个Q意文件类型的变量Qƈ且必d用AssignFile函数打开的外部文件相联系Q如果指定的文g不存在,则会产生错误Q如果指定的文g已经? 开Q则先关闭再重新打开。当前文件的位置讄在文件末。如果分配给F的是一个空名字Q则在调用Append函数后,文g变量QFQ将同将同标准输出文? 建立联系?/p>


2 、文本文件的d和写?/p>

文本文g通过调用q程Reset后以只读方式打开后,可以用Read或Readlnq程来读取文件数据了。文本文仉过调用Write或Writelnq程来打开一文g后就可以使用或过E来写入数据?/p>

(1) 用Readq程d数据

通过调用Readq程可以从文本文件中d或数字。其声明如下Q?br>Procedure Read([var F:text;]v1 [,v2,?vn,]);

? 中F是一个文件变量,v1 ,v2,?vn用于存储d的数据,其必Mؓ相同的类型。当v1 ,v2,?vn定义为字W串型或字符型变量时Q则Readq程按照定义的长度d字符。当v1 ,v2,?vn定义为整数或实数变量Ӟ则Readq程以I格作ؓ分隔W,如果在数字中出现逗号、分h其他字符生异常?/p>

(2) 用Readlnq程d数据

通过调用Readln q程可以从文本文件中d字符丌Ӏ字W或数字Q直C行结束。其声明如下Q?br>Procedure readln([var F:text;]v1 [,v2 ,…]);

其中F是一个文件变量,v1 ,v2,?vn用于存储d的数?/p>

(3) 用Writeq程写入数据

通过调用Writeq程可以向文件中写入数据。其声明如下Q?br>Procedure Write([var F:text;]p1[,p2,…]);

其中F是一个文件变量,p1 ,p2,?pn用于存储写入的数?/p>


(4) Writeln用过E写入数?/p>

通过调用Writelnq程可以向文件中写入一行数据,q在l尾处输入回车符。声明如下:
Procedure Writeln([var F:text;]P1[,P2,…]):


3?文g的基本操?/p>

Ҏ本文件进行操作的基本函数与过E见表:

Ҏ                                                                                  说明
Procedure AssignPrn(var F:text);                                       建立文本文g同打印机的联p?nbsp;
Function Eoln(var F:text):Boolean;                                    文件指针是否指向行?nbsp;
Procedure Flush(var F:text);                                             清空以输出方式(ReWite或AppendQ打开的文件缓冲区Q以保写入的文件字W都被写入外部文?nbsp;
Function SeekEof(var F:text): boolean;                             q回文g?nbsp;
Function SeekEoln(var F:text):boolean;                             q回文g行尾状?nbsp;
Procedure SetTextBuf(var F :text;var buf [;size:integer]);   讄文g~冲?/p>


Khan's Notebook 2004-11-08 21:27 发表评论
]]>
þþƷһ| Ʒһþ㽶߿| Ļþþþ| Ʒٸavþ| þþžоƷ23ٻӰԺ| þһ99| 97Ʒ97þþþþ| Ʒ18þþþþvr | 97Ʒ˾þþô߽97| þ99ƷþֻоƷ| ŷþþþþҹƷ| þù޸ۿ| þԭƷ| 99þþƷҹһ| þһѵ| ˾Ʒһþ| þóۺɫۺ| ޹˾þһþ| þùƷþþƷ| þоƷ| Ʒþþþһ| þ99ۺϾƷ| պһþ99| þ99Ʒһ | ޾ƷŮþþþ99| þþþþùƷŮ | ?VþþƷ| þþƷ鶹| þۺ| þþwww˳ɾƷ| ԾþþӰԺ| ˾þۺij| 99þù뾫ƷѾþþþ| պþþþþ| þþþƷþþþӰԺ| ŷþþþþ| 99þùں;Ʒ1ӳ| ɫþþþþþС˵| þþƷAVþþ| þĻ| Ʒ˾þþ|