﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-GCC/GNU/Linux Delphi/Window Java/Anywhere-随笔分类-Delphi</title><link>http://www.cppblog.com/Khan/category/773.html</link><description>路漫漫，长修远，我们不能没有钱</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 13:13:02 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 13:13:02 GMT</pubDate><ttl>60</ttl><item><title>昨天玩delphi线程,找到一篇文章,强烈推荐大家看看,tthread代码分析</title><link>http://www.cppblog.com/Khan/archive/2006/11/21/15503.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Tue, 21 Nov 2006 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2006/11/21/15503.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/15503.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2006/11/21/15503.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/15503.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/15503.html</trackback:ping><description><![CDATA[ <div class="main"><div class="postbody"><p>Delphi中的线程类 <br /> <br />转贴于 华夏黑客同盟 <a href="http://www.77169.orgdelphi/"><font color="#223355">http://www.77169.org</font></a></p><p>Delphi中有一个线程类TThread是用来实现多线程编程的，这个绝大多数Delphi书藉都有说到，但基本上都是对</p><p>TThread类的几个成员作一简单介绍，再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编<br />程的全部，我写此文的目的在于对此作一个补充。</p><p>线程本质上是进程中一段并发运行的代码。一个进程至少有一个线程，即所谓的主线程。同时还可以有多个子线程。<br />当一个进程中用到超过一个线程时，就是所谓的“多线程”。<br />那么这个所谓的“一段代码”是如何定义的呢？其实就是一个函数或过程（对Delphi而言）。<br />如果用Windows API来创建线程的话，是通过一个叫做CreateThread的API函数来实现的，它的定义为：<br />HANDLE CreateThread(<br />    LPSECURITY_ATTRIBUTES lpThreadAttributes, <br />    DWORD dwStackSize, <br />    LPTHREAD_START_ROUTINE lpStartAddress, <br />    LPVOID lpParameter, <br />    DWORD dwCreationFlags, <br />    LPDWORD lpThreadId <br />);</p><p>其各参数如它们的名称所说，分别是：线程属性（用于在NT下进行线程的安全属性设置，在9X下无效），堆栈大小，<br />起始地址，参数，创建标志（用于设置线程创建时的状态），线程ID，最后返回线程Handle。其中的起始地址就是线<br />程函数的入口，直至线程函数结束，线程也就结束了。</p><p>因为CreateThread参数很多，而且是Windows的API，所以在C Runtime Library里提供了一个通用的线程函数（理论上<br />可以在任何支持线程的OS中使用）：<br />unsigned long _beginthread(void (_USERENTRY *__start)(void *), unsigned __stksize, void *__arg);</p><p>Delphi也提供了一个相同功能的类似函数：<br />function BeginThread(<br />    SecurityAttributes: Pointer; <br />    StackSize: LongWord; <br />    ThreadFunc: TThreadFunc; <br />    Parameter: Pointer; <br />    CreationFlags: LongWord; <br />    var ThreadId: LongWord<br />): Integer;</p><p> </p><p>这三个函数的功能是基本相同的，它们都是将线程函数中的代码放到一个独立的线程中执行。线程函数与一般函数的<br />最大不同在于，线程函数一启动，这三个线程启动函数就返回了，主线程继续向下执行，而线程函数在一个独立的线<br />程中执行，它要执行多久，什么时候返回，主线程是不管也不知道的。<br />正常情况下，线程函数返回后，线程就终止了。但也有其它方式：</p><p>Windows API：<br />VOID ExitThread( DWORD dwExitCode );</p><p>C Runtime Library：<br />void _endthread(void);</p><p>Delphi Runtime Library：<br />procedure EndThread(ExitCode: Integer);</p><p>为了记录一些必要的线程数据（状态/属性等），OS会为线程创建一个内部Object，如在Windows中那个Handle便是这<br />个内部Object的Handle，所以在线程结束的时候还应该释放这个Object。</p><p>虽然说用API或RTL(Runtime Library)已经可以很方便地进行多线程编程了，但是还是需要进行较多的细节处理，为此<br />Delphi在Classes单元中对线程作了一个较好的封装，这就是VCL的线程类：TThread<br />使用这个类也很简单，大多数的Delphi书籍都有说，基本用法是：先从TThread派生一个自己的线程类（因为TThread<br />是一个抽象类，不能生成实例），然后是Override抽象方法：Execute（这就是线程函数，也就是在线程中执行的代码<br />部分），如果需要用到可视VCL对象，还需要通过Synchronize过程进行。关于之方面的具体细节，这里不再赘述，请<br />参考相关书籍。</p><p>本文接下来要讨论的是TThread类是如何对线程进行封装的，也就是深入研究一下TThread类的实现。因为只是真正地<br />了解了它，才更好地使用它。<br />下面是DELPHI7中TThread类的声明（本文只讨论在Windows平台下的实现，所以去掉了所有有关Linux平台部分的代码<br />）：</p><p>TThread = class<br />private<br />    FHandle: THandle;<br />    FThreadID: THandle;<br />    FCreateSuspended: Boolean;<br />    FTerminated: Boolean;<br />    FSuspended: Boolean;<br />    FFreeOnTerminate: Boolean;<br />    FFinished: Boolean;<br />    FReturnValue: Integer;<br />    FOnTerminate: TNotifyEvent;<br />    FSynchronize: TSynchronizeRecord;<br />    FFatalException: TObject;<br />    procedure CallOnTerminate;<br />    class procedure Synchronize(ASyncRec: PSynchronizeRecord); overload;<br />    function GetPriority: TThreadPriority;<br />    procedure SetPriority(Value: TThreadPriority);<br />    procedure SetSuspended(Value: Boolean);<br />protected<br />    procedure CheckThreadError(ErrCode: Integer); overload;<br />    procedure CheckThreadError(Success: Boolean); overload;<br />    procedure DoTerminate; virtual;<br />    procedure Execute; virtual; abstract;<br />    procedure Synchronize(Method: TThreadMethod); overload;<br />    property ReturnValue: Integer read FReturnValue write FReturnValue;<br />    property Terminated: Boolean read FTerminated;<br />public<br />    constructor Create(CreateSuspended: Boolean);<br />    destructor Destroy; override;<br />    procedure AfterConstruction; override;<br />    procedure Resume;<br />    procedure Suspend;<br />    procedure Terminate;<br />    function WaitFor: LongWord;<br />    class procedure Synchronize(AThread: TThread; AMethod: TThreadMethod); overload;<br />    class procedure StaticSynchronize(AThread: TThread; AMethod: TThreadMethod);<br />    property FatalException: TObject read FFatalException;<br />    property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;<br />    property Handle: THandle read FHandle;<br />    property Priority: TThreadPriority read GetPriority write SetPriority;<br />    property Suspended: Boolean read FSuspended write SetSuspended;<br />    property ThreadID: THandle read FThreadID;<br />    property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;<br />end;</p><p>TThread类在Delphi的RTL里算是比较简单的类，类成员也不多，类属性都很简单明白，本文将只对几个比较重要的类<br />成员方法和唯一的事件：OnTerminate作详细分析。<br />首先就是构造函数：<br />constructor TThread.Create(CreateSuspended: Boolean);<br />begin<br />    inherited Create;<br />    AddThread;<br />    FSuspended := CreateSuspended;<br />    FCreateSuspended := CreateSuspended;<br />    FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);<br />    if FHandle = 0 then<br />        raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);<br />end;<br />虽然这个构造函数没有多少代码，但却可以算是最重要的一个成员，因为线程就是在这里被创建的。<br />在通过Inherited调用TObject.Create后，第一句就是调用一个过程：AddThread，其源码如下：<br />procedure AddThread;<br />begin<br />    InterlockedIncrement(ThreadCount);<br />end;</p><p>同样有一个对应的RemoveThread：<br />procedure RemoveThread;<br />begin<br />    InterlockedDecrement(ThreadCount);<br />end;<br />它们的功能很简单，就是通过增减一个全局变量来统计进程中的线程数。只是这里用于增减变量的并不是常用的<br />Inc/Dec过程，而是用了InterlockedIncrement/InterlockedDecrement这一对过程，它们实现的功能完全一样，都是<br />对变量加一或减一。但它们有一个最大的区别，那就是InterlockedIncrement/InterlockedDecrement是线程安全的。<br />即它们在多线程下能保证执行结果正确，而Inc/Dec不能。或者按操作系统理论中的术语来说，这是一对“原语”操作。</p><p>以加一为例来说明二者实现细节上的不同：<br />一般来说，对内存数据加一的操作分解以后有三个步骤：<br />1、 从内存中读出数据<br />2、 数据加一<br />3、 存入内存<br />现在假设在一个两个线程的应用中用Inc进行加一操作可能出现的一种情况：<br />1、 线程A从内存中读出数据（假设为3）<br />2、 线程B从内存中读出数据（也是3）<br />3、 线程A对数据加一（现在是4）<br />4、 线程B对数据加一（现在也是4）<br />5、 线程A将数据存入内存（现在内存中的数据是4）<br />6、 线程B也将数据存入内存（现在内存中的数据还是4，但两个线程都对它加了一，应该是5才对，所以这里出现了<br />错误的结果）</p><p> </p><p>而用InterlockIncrement过程则没有这个问题，因为所谓“原语”是一种不可中断的操作，即操作系统能保证在一个<br />“原语”执行完毕前不会进行线程切换。所以在上面那个例子中，只有当线程A执行完将数据存入内存后，线程B才可<br />以开始从中取数并进行加一操作，这样就保证了即使是在多线程情况下，结果也一定会是正确的。</p><p>前面那个例子也说明一种“线程访问冲突”的情况，这也就是为什么线程之间需要“同步”（Synchronize），关于这<br />个，在后面说到同步时还会再详细讨论。</p><p>说到同步，有一个题外话：加拿大滑铁卢大学的教授李明曾就Synchronize一词在“线程同步”中被译作“同步”提出<br />过异议，个人认为他说的其实很有道理。在中文中“同步”的意思是“同时发生”，而“线程同步”目的就是避免这<br />种“同时发生”的事情。而在英文中，Synchronize的意思有两个：一个是传统意义上的同步（To occur at the same <br />time），另一个是“协调一致”（To operate in unison）。在“线程同步”中的Synchronize一词应该是指后面一种<br />意思，即“保证多个线程在访问同一数据时，保持协调一致，避免出错”。不过像这样译得不准的词在IT业还有很多<br />，既然已经是约定俗成了，本文也将继续沿用，只是在这里说明一下，因为软件开发是一项细致的工作，该弄清楚的<br />，绝不能含糊。</p><p>扯远了，回到TThread的构造函数上，接下来最重要就是这句了：<br />FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);<br />这里就用到了前面说到的Delphi RTL函数BeginThread，它有很多参数，关键的是第三、四两个参数。第三个参数就是<br />前面说到的线程函数，即在线程中执行的代码部分。第四个参数则是传递给线程函数的参数，在这里就是创建的线程<br />对象（即Self）。其它的参数中，第五个是用于设置线程在创建后即挂起，不立即执行（启动线程的工作是在<br />AfterConstruction中根据CreateSuspended标志来决定的），第六个是返回线程ID。</p><p>现在来看TThread的核心：线程函数ThreadProc。有意思的是这个线程类的核心却不是线程的成员，而是一个全局函数<br />（因为BeginThread过程的参数约定只能用全局函数）。下面是它的代码：</p><p>function ThreadProc(Thread: TThread): Integer;<br />var<br />    FreeThread: Boolean;<br />begin<br />      try<br />            if not Thread.Terminated then<br />            try<br />                Thread.Execute;<br />            except<br />                Thread.FFatalException := AcquireExceptionObject;<br />            end;<br />      finally<br />            FreeThread := Thread.FFreeOnTerminate;<br />            Result := Thread.FReturnValue;<br />            Thread.DoTerminate;<br />            Thread.FFinished := True;<br />            SignalSyncEvent;<br />            if FreeThread then Thread.Free;<br />            EndThread(Result);<br />      end;<br />end;<br />虽然也没有多少代码，但却是整个TThread中最重要的部分，因为这段代码是真正在线程中执行的代码。下面对代码作<br />逐行说明：<br />首先判断线程类的Terminated标志，如果未被标志为终止，则调用线程类的Execute方法执行线程代码，因为TThread<br />是抽象类，Execute方法是抽象方法，所以本质上是执行派生类中的Execute代码。</p><p>所以说，Execute就是线程类中的线程函数，所有在Execute中的代码都需要当作线程代码来考虑，如防止访问冲突等。<br />如果Execute发生异常，则通过AcquireExceptionObject取得异常对象，并存入线程类的FFatalException成员中。<br />最后是线程结束前做的一些收尾工作。局部变量FreeThread记录了线程类的FreeOnTerminated属性的设置，然后将线<br />程返回值设置为线程类的返回值属性的值。然后执行线程类的DoTerminate方法。</p><p>DoTerminate方法的代码如下：<br />procedure TThread.DoTerminate;<br />begin<br />    if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);<br />end;</p><p>很简单，就是通过Synchronize来调用CallOnTerminate方法，而CallOnTerminate方法的代码如下，就是简单地调用<br />OnTerminate事件：<br />procedure TThread.CallOnTerminate;<br />begin<br />    if Assigned(FOnTerminate) then FOnTerminate(Self);<br />end;</p><p>因为OnTerminate事件是在Synchronize中执行的，所以本质上它并不是线程代码，而是主线程代码（具体见后面对<br />Synchronize的分析）。</p><p>执行完OnTerminate后，将线程类的FFinished标志设置为True。接下来执行SignalSyncEvent过程，其代码如下：<br />procedure SignalSyncEvent;<br />begin<br />    SetEvent(SyncEvent);<br />end;</p><p>也很简单，就是设置一下一个全局Event：SyncEvent，关于Event的使用，本文将在后文详述，而SyncEvent的用途将<br />在WaitFor过程中说明。</p><p>然后根据FreeThread中保存的FreeOnTerminate设置决定是否释放线程类，在线程类释放时，还有一些些操作，详见接<br />下来的析构函数实现。<br />最后调用EndThread结束线程，返回线程返回值。至此，线程完全结束。<br />说完构造函数，再来看析构函数：<br />destructor TThread.Destroy;<br />begin<br />  if (FThreadID &lt;&gt; 0) and not FFinished then  begin<br />      Terminate;<br />      if FCreateSuspended then<br />          Resume;<br />      WaitFor;<br />  end;<br />  if FHandle &lt;&gt; 0 then CloseHandle(FHandle);<br />  inherited Destroy;<br />  FFatalException.Free;<br />  RemoveThread;<br />end;</p><p>在线程对象被释放前，首先要检查线程是否还在执行中，如果线程还在执行中（线程ID不为0，并且线程结束标志未设<br />置），则调用Terminate过程结束线程。Terminate过程只是简单地设置线程类的Terminated标志，如下面的代码：</p><p>procedure TThread.Terminate;<br />begin<br />    FTerminated := True;<br />end;</p><p>所以线程仍然必须继续执行到正常结束后才行，而不是立即终止线程，这一点要注意。</p><p>在这里说一点题外话：很多人都问过我，如何才能“立即”终止线程（当然是指用TThread创建的线程）。结果当然是<br />不行！终止线程的唯一办法就是让Execute方法执行完毕，所以一般来说，要让你的线程能够尽快终止，必须在<br />Execute方法中在较短的时间内不断地检查Terminated标志，以便能及时地退出。这是设计线程代码的一个很重要的原<br />则！</p><p>当然如果你一定要能“立即”退出线程，那么TThread类不是一个好的选择，因为如果用API强制终止线程的话，最终<br />会导致TThread线程对象不能被正确释放，在对象析构时出现Access Violation。这种情况你只能用API或RTL函数来创<br />建线程。</p><p>如果线程处于启动挂起状态，则将线程转入运行状态，然后调用WaitFor进行等待，其功能就是等待到线程结束后才继<br />续向下执行。关于WaitFor的实现，将放到后面说明。</p><p>线程结束后，关闭线程Handle（正常线程创建的情况下Handle都是存在的），释放操作系统创建的线程对象。<br />然后调用TObject.Destroy释放本对象，并释放已经捕获的异常对象，最后调用RemoveThread减小进程的线程数。</p><p>其它关于Suspend/Resume及线程优先级设置等方面，不是本文的重点，不再赘述。下面要讨论的是本文的另两个重点<br />：Synchronize和WaitFor。</p><p>但是在介绍这两个函数之前，需要先介绍另外两个线程同步技术：事件和临界区。</p><p>事件（Event）与Delphi中的事件有所不同。从本质上说，Event其实相当于一个全局的布尔变量。它有两个赋值操作<br />：Set和Reset，相当于把它设置为True或False。而检查它的值是通过WaitFor操作进行。对应在Windows平台上，是三<br />个API函数：SetEvent、ResetEvent、WaitForSingleObject（实现WaitFor功能的API还有几个，这是最简单的一个）。</p><p>这三个都是原语，所以Event可以实现一般布尔变量不能实现的在多线程中的应用。Set和Reset的功能前面已经说过了<br />，现在来说一下WaitFor的功能：</p><p>WaitFor的功能是检查Event的状态是否是Set状态（相当于True），如果是则立即返回，如果不是，则等待它变为Set<br />状态，在等待期间，调用WaitFor的线程处于挂起状态。另外WaitFor有一个参数用于超时设置，如果此参数为0，则不<br />等待，立即返回Event的状态，如果是INFINITE则无限等待，直到Set状态发生，若是一个有限的数值，则等待相应的<br />毫秒数后返回Event的状态。</p><p>当Event从Reset状态向Set状态转换时，唤醒其它由于WaitFor这个Event而挂起的线程，这就是它为什么叫Event的原<br />因。所谓“事件”就是指“状态的转换”。通过Event可以在线程间传递这种“状态转换”信息。</p><p>当然用一个受保护（见下面的临界区介绍）的布尔变量也能实现类似的功能，只要用一个循环检查此布尔值的代码来<br />代替WaitFor即可。从功能上说完全没有问题，但实际使用中就会发现，这样的等待会占用大量的CPU资源，降低系统<br />性能，影响到别的线程的执行速度，所以是不经济的，有的时候甚至可能会有问题。所以不建议这样用。</p><p>临界区（CriticalSection）则是一项共享数据访问保护的技术。它其实也是相当于一个全局的布尔变量。但对它的操<br />作有所不同，它只有两个操作：Enter和Leave，同样可以把它的两个状态当作True和False，分别表示现在是否处于临<br />界区中。这两个操作也是原语，所以它可以用于在多线程应用中保护共享数据，防止访问冲突。</p><p>用临界区保护共享数据的方法很简单：在每次要访问共享数据之前调用Enter设置进入临界区标志，然后再操作数据，<br />最后调用Leave离开临界区。它的保护原理是这样的：当一个线程进入临界区后，如果此时另一个线程也要访问这个数<br />据，则它会在调用Enter时，发现已经有线程进入临界区，然后此线程就会被挂起，等待当前在临界区的线程调用<br />Leave离开临界区，当另一个线程完成操作，调用Leave离开后，此线程就会被唤醒，并设置临界区标志，开始操作数<br />据，这样就防止了访问冲突。</p><p>以前面那个InterlockedIncrement为例，我们用CriticalSection（Windows API）来实现它：<br />Var<br />InterlockedCrit : TRTLCriticalSection;<br />Procedure InterlockedIncrement( var aValue : Integer );<br />Begin<br />    EnterCriticalSection( InterlockedCrit );<br />    Inc( aValue );<br />    LeaveCriticalSection( InterlockedCrit );<br />End;</p><p>现在再来看前面那个例子：<br />1. 线程A进入临界区（假设数据为3）<br />2. 线程B进入临界区，因为A已经在临界区中，所以B被挂起<br />3. 线程A对数据加一（现在是4）<br />4. 线程A离开临界区，唤醒线程B（现在内存中的数据是4）<br />5. 线程B被唤醒，对数据加一（现在就是5了）<br />6. 线程B离开临界区，现在的数据就是正确的了。</p><p>临界区就是这样保护共享数据的访问。</p><p>关于临界区的使用，有一点要注意：即数据访问时的异常情况处理。因为如果在数据操作时发生异常，将导致Leave操<br />作没有被执行，结果将使本应被唤醒的线程未被唤醒，可能造成程序的没有响应。所以一般来说，如下面这样使用临<br />界区才是正确的做法：</p><p>EnterCriticalSection<br />Try<br />// 操作临界区数据<br />Finally<br />    LeaveCriticalSection<br />End;</p><p>最后要说明的是，Event和CriticalSection都是操作系统资源，使用前都需要创建，使用完后也同样需要释放。如<br />TThread类用到的一个全局Event：SyncEvent和全局CriticalSection：TheadLock，都是在<br />InitThreadSynchronization和DoneThreadSynchronization中进行创建和释放的，而它们则是在Classes单元的<br />Initialization和Finalization中被调用的。</p><p>由于在TThread中都是用API来操作Event和CriticalSection的，所以前面都是以API为例，其实Delphi已经提供了对它<br />们的封装，在SyncObjs单元中，分别是TEvent类和TCriticalSection类。用法也与前面用API的方法相差无几。因为<br />TEvent的构造函数参数过多，为了简单起见，Delphi还提供了一个用默认参数初始化的Event类：TSimpleEvent。</p><p>顺便再介绍一下另一个用于线程同步的类：TMultiReadExclusiveWriteSynchronizer，它是在SysUtils单元中定义的<br />。据我所知，这是Delphi RTL中定义的最长的一个类名，还好它有一个短的别名：TMREWSync。至于它的用处，我想光<br />看名字就可以知道了，我也就不多说了。</p><p>有了前面对Event和CriticalSection的准备知识，可以正式开始讨论Synchronize和WaitFor了。<br />我们知道，Synchronize是通过将部分代码放到主线程中执行来实现线程同步的，因为在一个进程中，只有一个主线程<br />。先来看看Synchronize的实现：</p><p>procedure TThread.Synchronize(Method: TThreadMethod);<br />begin<br />    FSynchronize.FThread := Self;<br />    FSynchronize.FSynchronizeException := nil;<br />    FSynchronize.FMethod := Method;<br />    Synchronize(@FSynchronize);<br />end;</p><p>其中FSynchronize是一个记录类型：<br />PSynchronizeRecord = ^TSynchronizeRecord;<br />TSynchronizeRecord = record<br />    FThread: TObject;<br />    FMethod: TThreadMethod;<br />    FSynchronizeException: TObject;<br />end;</p><p>用于进行线程和主线程之间进行数据交换，包括传入线程类对象，同步方法及发生的异常。<br />在Synchronize中调用了它的一个重载版本，而且这个重载版本比较特别，它是一个“类方法”。所谓类方法，是一种<br />特殊的类成员方法，它的调用并不需要创建类实例，而是像构造函数那样，通过类名调用。之所以会用类方法来实现<br />它，是因为为了可以在线程对象没有创建时也能调用它。不过实际中是用它的另一个重载版本（也是类方法）和另一<br />个类方法StaticSynchronize。下面是这个Synchronize的代码：</p><p>class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);<br />var<br />    SyncProc: TSyncProc;<br />begin<br />    if GetCurrentThreadID = MainThreadID then<br />        ASyncRec.FMethod<br />    else begin<br />    SyncProc.Signal := CreateEvent(nil, True, False, nil);<br />    try<br />    EnterCriticalSection(ThreadLock);<br />    try<br />    if SyncList = nil then<br />        SyncList := TList.Create;<br />        SyncProc.SyncRec := ASyncRec;<br />        SyncList.Add(@SyncProc);<br />        SignalSyncEvent;<br />        if Assigned(WakeMainThread) then<br />            WakeMainThread(SyncProc.SyncRec.FThread);<br />        LeaveCriticalSection(ThreadLock);<br />        try<br />            WaitForSingleObject(SyncProc.Signal, INFINITE);<br />        finally<br />            EnterCriticalSection(ThreadLock);<br />        end;<br />        finally<br />            LeaveCriticalSection(ThreadLock);<br />        end;<br />        finally<br />            CloseHandle(SyncProc.Signal);<br />        end;<br />        if Assigned(ASyncRec.FSynchronizeException) then <br />            raise ASyncRec.FSynchronizeException;<br />    end;<br />end;</p><p>这段代码略多一些，不过也不算太复杂。<br />首先是判断当前线程是否是主线程，如果是，则简单地执行同步方法后返回。<br />如果不是主线程，则准备开始同步过程。<br />通过局部变量SyncProc记录线程交换数据（参数）和一个Event Handle，其记录结构如下：<br />TSyncProc = record<br />SyncRec: PSynchronizeRecord;<br />Signal: THandle;<br />end;</p><p>然后创建一个Event，接着进入临界区（通过全局变量ThreadLock进行，因为同时只能有一个线程进入Synchronize状<br />态，所以可以用全局变量记录），然后就是把这个记录数据存入SyncList这个列表中（如果这个列表不存在的话，则<br />创建它）。可见ThreadLock这个临界区就是为了保护对SyncList的访问，这一点在后面介绍CheckSynchronize时会再<br />次看到。</p><p>再接下就是调用SignalSyncEvent，其代码在前面介绍TThread的构造函数时已经介绍过了，它的功能就是简单地将<br />SyncEvent作一个Set的操作。关于这个SyncEvent的用途，将在后面介绍WaitFor时再详述。</p><p>接下来就是最主要的部分了：调用WakeMainThread事件进行同步操作。WakeMainThread是一个TNotifyEvent类型的全<br />局事件。这里之所以要用事件进行处理，是因为Synchronize方法本质上是通过消息，将需要同步的过程放到主线程中<br />执行，如果在一些没有消息循环的应用中（如Console或DLL）是无法使用的，所以要使用这个事件进行处理。<br />而响应这个事件的是Application对象，下面两个方法分别用于设置和清空WakeMainThread事件的响应（来自Forms单元）：</p><p>procedure TApplication.HookSynchronizeWakeup;<br />begin<br />    Classes.WakeMainThread := WakeMainThread;<br />end;</p><p>procedure TApplication.UnhookSynchronizeWakeup;<br />begin<br />    Classes.WakeMainThread := nil;<br />end;</p><p>上面两个方法分别是在TApplication类的构造函数和析构函数中被调用。<br />这就是在Application对象中WakeMainThread事件响应的代码，消息就是在这里被发出的，它利用了一个空消息来实现：</p><p>procedure TApplication.WakeMainThread(Sender: TObject);<br />begin<br />    PostMessage(Handle, WM_NULL, 0, 0);<br />end;</p><p>而这个消息的响应也是在Application对象中，见下面的代码（删除无关的部分）：<br />procedure TApplication.WndProc(var Message: TMessage);<br />…<br />begin<br />    try<br />        …<br />        with Message do<br />        case Msg of<br />        …<br />        WM_NULL:<br />        CheckSynchronize;<br />        …<br />    except<br />        HandleException(Self);<br />    end;<br />end;</p><p>其中的CheckSynchronize也是定义在Classes单元中的，由于它比较复杂，暂时不详细说明，只要知道它是具体处理<br />Synchronize功能的部分就好，现在继续分析Synchronize的代码。<br />在执行完WakeMainThread事件后，就退出临界区，然后调用WaitForSingleObject开始等待在进入临界区前创建的那个<br />Event。这个Event的功能是等待这个同步方法的执行结束，关于这点，在后面分析CheckSynchronize时会再说明。<br />注意在WaitForSingleObject之后又重新进入临界区，但没有做任何事就退出了，似乎没有意义，但这是必须的！<br />因为临界区的Enter和Leave必须严格的一一对应。那么是否可以改成这样呢：</p><p>if Assigned(WakeMainThread) then<br />    WakeMainThread(SyncProc.SyncRec.FThread);<br />    WaitForSingleObject(SyncProc.Signal, INFINITE);<br />    finally<br />        LeaveCriticalSection(ThreadLock);<br />end;</p><p>上面的代码和原来的代码最大的区别在于把WaitForSingleObject也纳入临界区的限制中了。看上去没什么影响，还使<br />代码大大简化了，但真的可以吗？<br />事实上是不行！</p><p>因为我们知道，在Enter临界区后，如果别的线程要再进入，则会被挂起。而WaitFor方法则会挂起当前线程，直到等<br />待别的线程SetEvent后才会被唤醒。如果改成上面那样的代码的话，如果那个SetEvent的线程也需要进入临界区的话<br />，死锁（Deadlock）就发生了（关于死锁的理论，请自行参考操作系统原理方面的资料）。<br />死锁是线程同步中最需要注意的方面之一！<br />最后释放开始时创建的Event，如果被同步的方法返回异常的话，还会在这里再次抛出异常。</p><p>回到前面CheckSynchronize，见下面的代码：</p><p>function CheckSynchronize(Timeout: Integer = 0): Boolean;<br />var<br />     SyncProc: PSyncProc;<br />     LocalSyncList: TList;<br />begin<br />     if GetCurrentThreadID &lt;&gt; MainThreadID then<br />          raise EThread.CreateResFmt(@SCheckSynchronizeError, [GetCurrentThreadID]);<br />     if Timeout &gt; 0 then<br />          WaitForSyncEvent(Timeout)<br />     else<br />          ResetSyncEvent;<br />     LocalSyncList := nil;<br />     EnterCriticalSection(ThreadLock);<br />     try<br />          Integer(LocalSyncList) := InterlockedExchange(Integer(SyncList), Integer(LocalSyncList));<br />          try<br />               Result := (LocalSyncList &lt;&gt; nil) and (LocalSyncList.Count &gt; 0);<br />               if Result then begin<br />                    while LocalSyncList.Count &gt; 0 do begin<br />                         SyncProc := LocalSyncList[0];<br />                         LocalSyncList.Delete(0);<br />                         LeaveCriticalSection(ThreadLock);<br />                         try<br />                              try<br />                                   SyncProc.SyncRec.FMethod;<br />                              except<br />                                   SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject;<br />                              end;<br />                         finally<br />                              EnterCriticalSection(ThreadLock);<br />                         end;<br />                         SetEvent(SyncProc.signal);<br />                    end;<br />               end;<br />          finally<br />               LocalSyncList.Free;<br />          end;<br />     finally<br />          LeaveCriticalSection(ThreadLock);<br />     end;<br />end;</p><p>首先，这个方法必须在主线程中被调用（如前面通过消息传递到主线程），否则就抛出异常。<br />接下来调用ResetSyncEvent（它与前面SetSyncEvent对应的，之所以不考虑WaitForSyncEvent的情况，是因为只有在<br />Linux版下才会调用带参数的CheckSynchronize，Windows版下都是调用默认参数0的CheckSynchronize）。<br />现在可以看出SyncList的用途了：它是用于记录所有未被执行的同步方法的。因为主线程只有一个，而子线程可能有<br />很多个，当多个子线程同时调用同步方法时，主线程可能一时无法处理，所以需要一个列表来记录它们。<br />在这里用一个局部变量LocalSyncList来交换SyncList，这里用的也是一个原语：InterlockedExchange。同样，这里<br />也是用临界区将对SyncList的访问保护起来。<br />只要LocalSyncList不为空，则通过一个循环来依次处理累积的所有同步方法调用。最后把处理完的LocalSyncList释<br />放掉，退出临界区。</p><p>再来看对同步方法的处理：首先是从列表中移出（取出并从列表中删除）第一个同步方法调用数据。然后退出临界区<br />（原因当然也是为了防止死锁）。<br />接着就是真正的调用同步方法了。<br />如果同步方法中出现异常，将被捕获后存入同步方法数据记录中。<br />重新进入临界区后，调用SetEvent通知调用线程，同步方法执行完成了（详见前面Synchronize中的<br />WaitForSingleObject调用）。<br />至此，整个Synchronize的实现介绍完成。</p><p>最后来说一下WaitFor，它的功能就是等待线程执行结束。其代码如下：<br />function TThread.WaitFor: LongWord;<br />var<br />    H: array[0..1] of THandle;<br />    WaitResult: Cardinal;<br />    Msg: TMsg;<br />begin<br />    H[0] := FHandle;<br />    if GetCurrentThreadID = MainThreadID then  begin<br />        WaitResult := 0;<br />        H[1] := SyncEvent;<br />        repeat<br />            { This prevents a potential deadlock if the background thread does a SendMessage to the foreground thread }<br />            if WaitResult = WAIT_OBJECT_0 + 2 then<br />                PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);<br />            WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);<br />            CheckThreadError(WaitResult &lt;&gt; WAIT_FAILED);<br />            if WaitResult = WAIT_OBJECT_0 + 1 then<br />                CheckSynchronize;<br />        until WaitResult = WAIT_OBJECT_0;<br />    end else <br />        WaitForSingleObject(H[0], INFINITE);<br />    CheckThreadError(GetExitCodeThread(H[0], Result));<br />end;</p><p>如果不是在主线程中执行WaitFor的话，很简单，只要调用WaitForSingleObject等待此线程的Handle为Signaled状态<br />即可。</p><p>如果是在主线程中执行WaitFor则比较麻烦。首先要在Handle数组中增加一个SyncEvent，然后循环等待，直到线程结<br />束（即MsgWaitForMultipleObjects返回WAIT_OBJECT_0，详见MSDN中关于此API的说明）。<br />在循环等待中作如下处理：如果有消息发生，则通过PeekMessage取出此消息（但并不把它从消息循环中移除），然后<br />调用MsgWaitForMultipleObjects来等待线程Handle或SyncEvent出现Signaled状态，同时监听消息（QS_SENDMESSAGE<br />参数，详见MSDN中关于此API的说明）。可以把此API当作一个可以同时等待多个Handle的WaitForSingleObject。如果<br />是SyncEvent被SetEvent（返回WAIT_OBJECT_0 + 1），则调用CheckSynchronize处理同步方法。<br />为什么在主线程中调用WaitFor必须用MsgWaitForMultipleObjects，而不能用WaitForSingleObject等待线程结束呢？<br />因为防止死锁。由于在线程函数Execute中可能调用Synchronize处理同步方法，而同步方法是在主线程中执行的，如<br />果用WaitForSingleObject等待的话，则主线程在这里被挂起，同步方法无法执行，导致线程也被挂起，于是发生死锁。<br />而改用WaitForMultipleObjects则没有这个问题。首先，它的第三个参数为False，表示只要线程Handle或SyncEvent<br />中只要有一个Signaled即可使主线程被唤醒，至于加上QS_SENDMESSAGE是因为Synchronize是通过消息传到主线程来的<br />，所以还要防止消息被阻塞。这样，当线程中调用Synchronize时，主线程就会被唤醒并处理同步调用，在调用完成后<br />继续进入挂起等待状态，直到线程结束。<br />至此，对线程类TThread的分析可以告一个段落了，对前面的分析作一个总结：<br />1、 线程类的线程必须按正常的方式结束，即Execute执行结束，所以在其中的代码中必须在适当的地方加入足够多<br />    的对Terminated标志的判断，并及时退出。如果必须要“立即”退出，则不能使用线程类，而要改用API或RTL函数。<br />2、 对可视VCL的访问要放在Synchronize中，通过消息传递到主线程中，由主线程处理。<br />3、 线程共享数据的访问应该用临界区进行保护（当然用Synchronize也行）。<br />4、 线程通信可以采用Event进行（当然也可以用Suspend/Resume）。<br />5、 当在多线程应用中使用多种线程同步方式时，一定要小心防止出现死锁。<br />6、 等待线程结束要用WaitFor方法。</p></div></div><img src ="http://www.cppblog.com/Khan/aggbug/15503.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2006-11-21 11:46 <a href="http://www.cppblog.com/Khan/archive/2006/11/21/15503.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Utf8编码的几个函数</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2006/01/19/2903.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2903.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2006/01/19/2903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2903.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2903.html</trackback:ping><description><![CDATA[<p><font face="Courier New">最近一段时间老弄Utf8编码,工作时写了几个函数,给大家指正一下<br><br></font></p><pre>//////////////////////////////////////////////<br>//---------取得utf8字符的长度---------------//<br>//<font color="#008080">Str</font>:<font color="#2e8b57"><b>String</b></font> 源字符串<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 &lt; <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]) &lt; $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>//----------取得字符串中的字符个数------------//<br>//<font color="#008080">str</font>:<font color="#2e8b57"><b>String</b></font> 源字符串<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 &lt; <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]) &lt; $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> 源字符串<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 &lt; <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 &gt;= count <font color="#804040"><b>then</b></font> <font color="#008080">break</font>;  //英文转码后不能超过指定的位数<br>          <font color="#804040"><b>if</b></font> <font color="#008080">ord</font>(tmpChar[i]) &lt; $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> &gt;= count <font color="#804040"><b>then</b></font> <font color="#008080">break</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]) + <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.cppblog.com/Khan/aggbug/2903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-19 15:06 <a href="http://www.cppblog.com/Khan/archive/2006/01/19/2903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]今天在这个blog上找到了ota bookmark的文档,打算在我的程序里面加上发送ota bookmark的功能</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2006/01/12/2626.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2626.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2006/01/12/2626.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2626.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2626.html</trackback:ping><description><![CDATA[<p align="justify">首先需要写一个bookmark的xml文件，这个格式可以去nokia网站下载。下面是一个例子：<br>&lt;?xml version="1.0"?&gt; <br>&lt;!DOCTYPE CHARACTERISTIC-LIST PUBLIC "" "characteristic_list.dtd"&gt; <br>&lt;CHARACTERISTIC-LIST&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;CHARACTERISTIC TYPE="BOOKMARK"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;PARM NAME="NAME" VALUE="bookmark name"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;PARM NAME="URL" VALUE="<a href="http://blog.codelphi.com/liukun966123/archive/2005/06/14/%27http://www.bookmark.com">http://www.bookmark.com"/</a>&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;/CHARACTERISTIC&gt;<br>&lt;/CHARACTERISTIC-LIST&gt;</p> <p align="justify"><br>尽量让name和url短点，这样编码后可以放到一条短消息里面，而不需要把一个设置拆分成多个短消息体。大致的一个封装是把xml文件转成wbxml，然后再在外面封装WSP层，最外面是WDP层。</p> <p align="justify">WDP的一般格式是“0B0504C34FC002000304xxyy”，其中xx就是整个数据包的总片断数目，而yy表示当前片断是第几个片断。举个例子，一个简单的bookmark全部放在一个sms中这样xx＝01，yy＝01。<br>下面是每个byte的意思:</p> <p align="justify"># 0B | User-Data-Header (UDHL) Length = 11 bytes<br># 05 | UDH IE identifier: Port numbers&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 04 | UDH port number IE length&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># C3 | Destination port (high)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br># 4F | Destination port (low)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># C0 | Originating port (high)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 02 | Originating port (low)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 00 | UDH IE identifier: SAR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 03 | UDH SAR IE length&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 04 | Datagram ref no.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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&nbsp;&nbsp;&nbsp;&nbsp;<br># yy | Segment count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p> <p align="justify">bookmark的WSP层的格式一般是"01062D1F2A6170706C69636174696F6E2F782D7761702D70726F762E62726F777365722D626F6F6B6D61726B730081EA"<br>每个byte的具体意思是：</p> <p align="justify"># 01 | Transaction ID /&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># 06 | PDU type (push)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br># xx | Header length (content type headers)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br># 1F | Value length quote length greater than 30<br># 2A | Value length (value name not used)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br># xx | Mimetype encoded, variable bytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | application/x-wap-prov.browser-{bookmarks | settings}<br># 00 | Null termination of content type string&nbsp;&nbsp; |<br># 81 | Charset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Well known PARM. (short integer)<br># EA | UTF-8 (using short integer)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>最里层就是WBXML了，首先必须有个xml的头"01016A00"</p> <p align="justify"># 01 | Version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | WBXML 1.1<br># 01 | Unknown public identifier&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br># 6A | Charset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | UTF-8<br># 00 | String table length&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |</p> 至于其他的具体编码可以去<a href="http://www.forum.nokia.com/">http://www.forum.nokia.com</a>查看OTA_settings_general_7_0.pdf这个文档，里面很详细的描述了每一个XML元素对应的十六进制。最后注意一点，发送的时候要按8bit格式的发送，而不是7bit格式。<br><br><p>
				<a target="_new" href="http://www.cnblogs.com/zhengyun_ustc/archive/2005/09/05/otawapbookmark.html">http://www.cnblogs.com/zhengyun_ustc/archive/2005/09/05/otawapbookmark.html</a>
<br>
<br>[SMS&amp;WAP]实例讲解制作OTA短信来自动配置手机WAP书签[附源码]
<br>摘要:OTA，即Over The Air，国内翻译为空中下载。 
<br>OTA标准由爱立信和诺基亚共同制订。OTA涵盖了许多范围，比如Kjava中的应用程序下载也是通过OTA。我们这篇文章主要讲的是，通过短信方式空中下载配置信息，参考的文档是OTA_settings_general_7_0.pdf。 
<br>规范中定义了三种Setting： 
<br>? 浏览器设置 
<br>? 浏览器的书签设置 
<br>? SyncML设置 
<br>也就是说，你通过发送短信可以帮助用户手机配置这三种设置。 
<br>
<br>原则上，你只要看了OTA_settings_general_7_0.pdf，并参照OTA_service_settings_example_v11.pdf，就可以轻松地制作出符合规范的OTA短信。 
<br>但是，本文档的目的就是让你简单粗暴地直奔主题，看完这篇文档后，就了解了OTA短信的概念，通过以下代码： 
<br>OTAMessage 
<br>OTAMessage message = new OTAMessage(); 
<br>txtOTAResult.Text = message.Get
				
			</p><br><a href="http://blog.codelphi.com/liukun966123/archive/2005/06/14/44430.aspx"></a><img src ="http://www.cppblog.com/Khan/aggbug/2626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-12 09:56 <a href="http://www.cppblog.com/Khan/archive/2006/01/12/2626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]在偶机器上找到一个读cpu串号的代码,delphi的,记录一下(申明是人家的代码)</title><link>http://www.cppblog.com/Khan/archive/2006/01/12/2627.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.cppblog.com/Khan/archive/2006/01/12/2627.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2627.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2006/01/12/2627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2627.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2627.html</trackback:ping><description><![CDATA[unit CPU;<br> <br> interface<br> <br> uses<br> &nbsp; SysUtils;<br> <br> type<br> &nbsp; TCPUID = array[1..4] of Longint;<br> &nbsp; TVendor = array[0..11] of char;<br> <br> function GetCPUID: TCPUID; assembler; register;<br> function GetCPUVendor: TVendor; assembler; register;<br> function GetCPUInfo: string;<br> <br> implementation<br> <br> <br> function GetCPUID: TCPUID; assembler; register;<br> asm<br> &nbsp;PUSH&nbsp;&nbsp;&nbsp; EBX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {Save affected register}<br> &nbsp;PUSH&nbsp;&nbsp;&nbsp; EDI<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EDI,EAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {@Resukt}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,1<br> &nbsp;DW&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $A20F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID Command}<br> &nbsp;STOSD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID[1]}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,EBX<br> &nbsp;STOSD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID[2]}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,ECX<br> &nbsp;STOSD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID[3]}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,EDX<br> &nbsp;STOSD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID[4]}<br> &nbsp;POP&nbsp;&nbsp;&nbsp;&nbsp; EDI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {Restore registers}<br> &nbsp;POP&nbsp;&nbsp;&nbsp;&nbsp; EBX<br> end;<br> <br> function GetCPUVendor: TVendor; assembler; register;<br> asm<br> &nbsp;PUSH&nbsp;&nbsp;&nbsp; EBX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {Save affected register}<br> &nbsp;PUSH&nbsp;&nbsp;&nbsp; EDI<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EDI,EAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {@Result (TVendor)}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,0<br> &nbsp;DW&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $A20F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {CPUID Command}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,EBX<br> &nbsp;XCHG&nbsp;&nbsp;&nbsp; EBX,ECX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {save ECX result}<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; ECX,4<br> @1:<br> &nbsp;STOSB<br> &nbsp;SHR&nbsp;&nbsp;&nbsp;&nbsp; EAX,8<br> &nbsp;LOOP&nbsp;&nbsp;&nbsp; @1<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,EDX<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; ECX,4<br> @2:<br> &nbsp;STOSB<br> &nbsp;SHR&nbsp;&nbsp;&nbsp;&nbsp; EAX,8<br> &nbsp;LOOP&nbsp;&nbsp;&nbsp; @2<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; EAX,EBX<br> &nbsp;MOV&nbsp;&nbsp;&nbsp;&nbsp; ECX,4<br> @3:<br> &nbsp;STOSB<br> &nbsp;SHR&nbsp;&nbsp;&nbsp;&nbsp; EAX,8<br> &nbsp;LOOP&nbsp;&nbsp;&nbsp; @3<br> &nbsp;POP&nbsp;&nbsp;&nbsp;&nbsp; EDI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {Restore registers}<br> &nbsp;POP&nbsp;&nbsp;&nbsp;&nbsp; EBX<br> end;<br> <br> function GetCPUInfo: string;<br> var<br> &nbsp; CPUID: TCPUID;<br> &nbsp; I: Integer;<br> &nbsp; S: TVendor;<br> begin<br> &nbsp; for I := Low(CPUID) to High(CPUID) do<br> &nbsp;&nbsp;&nbsp; CPUID[I] := -1;<br> <br> &nbsp; CPUID := GetCPUID;<br> <br> &nbsp; S := GetCPUVendor;<br> <br> &nbsp; Result := S + IntToHex(CPUID[1], 8) + IntToHex(CPUID[2], 8)<br> &nbsp;&nbsp;&nbsp; + IntToHex(CPUID[3], 8)<br> &nbsp;&nbsp;&nbsp; + IntToHex(CPUID[4], 8);<br> end;<br> <br> <br> end.<br> <br> <br> 以前中专d时候看ibm 8086/8088汇编有自己写过这些代码d,但是现在过了这么多年,退化到看不懂这些了<a href="http://blog.codelphi.com/liukun966123/archive/2005/05/26/39932.aspx"></a><img src ="http://www.cppblog.com/Khan/aggbug/2627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-12 09:56 <a href="http://www.cppblog.com/Khan/archive/2006/01/12/2627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]终于搞定了异步通信了,调试了两天,发现偶还素犯了一个弱智错误</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2006/01/12/2632.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2632.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2006/01/12/2632.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2632.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2632.html</trackback:ping><description><![CDATA[<p>我把client的socket初始化内容写在了message响应函数里面了,每次触发消息的时候就把客户端的socket置0了</p> <p>&nbsp;</p> <p>服务器端代码如下:</p> <p>由于比较简单,所以不贴注释了,如果有什么不懂d地方,大家对着<windows网络编程>翻吧</windows网络编程></p> <p>&nbsp;</p> <p>unit Listener;</p> <p>interface</p> <p>uses<br>&nbsp; SysUtils,&nbsp; Controls, Forms, winsock, Classes, ComCtrls, StdCtrls;</p> <p><br>const ASYNC_EVENT = $0400 + 1;<br>&nbsp; SO_CONDITIONAL_ACCEPT = $3002;<br>type</p> <p>&nbsp; TCMSocketMessage = record //select 消息结构<br>&nbsp;&nbsp;&nbsp; Msg: Cardinal; //系统消息<br>&nbsp;&nbsp;&nbsp; Socket: TSocket; //产生消息的源socket 句柄<br>&nbsp;&nbsp;&nbsp; SelectEvent: Word; //select消息<br>&nbsp;&nbsp;&nbsp; SelectError: Word; //错误<br>&nbsp;&nbsp;&nbsp; Result: Longint;<br>&nbsp; end;</p> <p>&nbsp;</p> <p>type<br>&nbsp; TMain = class(TForm)<br>&nbsp;&nbsp;&nbsp; SBar: TStatusBar;<br>&nbsp;&nbsp;&nbsp; Memo1: TMemo;<br>&nbsp;&nbsp;&nbsp; procedure FormDestroy(Sender: TObject);<br>&nbsp;&nbsp;&nbsp; procedure FormCreate(Sender: TObject);<br>&nbsp; private<br>&nbsp;&nbsp;&nbsp; s: TSocket;<br>&nbsp;&nbsp;&nbsp; SClinent: TSocket;<br>&nbsp;&nbsp;&nbsp; procedure bindAddr;<br>&nbsp;&nbsp;&nbsp; procedure CMIncCount(var Msg: TCMSocketMessage); message ASYNC_EVENT;<br>&nbsp;&nbsp;&nbsp; procedure listenAddr;<br>&nbsp;&nbsp;&nbsp; { Private declarations }<br>&nbsp; public<br>&nbsp;&nbsp;&nbsp; { Public declarations }<br>&nbsp; end;</p> <p>var<br>&nbsp; Main: TMain;</p> <p>implementation</p> <p>{$R *.dfm}</p> <p>procedure TMain.FormDestroy(Sender: TObject);<br>begin<br>&nbsp; closeSocket(s);<br>&nbsp; WSACleanup();<br>end;</p> <p>procedure TMain.FormCreate(Sender: TObject);<br>var<br>&nbsp; wsa: TWSaData;<br>&nbsp; flag: integer;<br>begin<br>&nbsp; SClinent := 0;<br>&nbsp; //SysUtils.BoolToStr()<br>&nbsp; flag := WSAStartup($0202, wsa); //加载winsock<br>&nbsp; if flag &lt;&gt; 0 then begin<br>&nbsp;&nbsp;&nbsp; SBar.Panels[2].Text := format('错误号:%d', [WSAGetLastError()]);<br>&nbsp;&nbsp;&nbsp; SBar.Panels[1].Text := 'Winsock库加载失败';<br>&nbsp; end;</p> <p>&nbsp; bindAddr;<br>&nbsp; listenAddr;<br>end;</p> <p><br>procedure TMain.bindAddr;<br>var<br>&nbsp; addr: TSockAddrIn;<br>&nbsp; flag: integer;<br>begin<br>&nbsp; s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服务器端的socket<br>&nbsp; addr.sin_port := htons(45531);<br>&nbsp; addr.sin_family := AF_INET;<br>&nbsp; addr.sin_addr.S_addr := INADDR_ANY; //inet_addr(pchar(host));</p> <p>&nbsp; flag := bind(s, addr, sizeof(addr));<br>&nbsp; if flag = SOCKET_ERROR then begin<br>&nbsp;&nbsp;&nbsp; SBar.Panels[2].Text := format('错误号:%d', [WSAGetLastError()]);<br>&nbsp;&nbsp;&nbsp; SBar.Panels[1].Text := 'IP绑定错误';<br>&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp; flag := WSAAsyncSelect(s, Handle, ASYNC_EVENT, FD_ACCEPT or FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE);<br>&nbsp;&nbsp;&nbsp; if flag = SOCKET_ERROR then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SBar.Panels[2].Text := format('错误号:%d', [WSAGetLastError()]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SBar.Panels[1].Text := 'WSAAsyncSelect错误';<br>&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end;<br>end;</p> <p>procedure TMain.listenAddr;<br>var flag: integer;<br>begin<br>&nbsp; flag := listen(s, 10);<br>&nbsp; if flag = SOCKET_ERROR then begin<br>&nbsp;&nbsp;&nbsp; SBar.Panels[2].Text := format('错误号:%d', [WSAGetLastError()]);<br>&nbsp;&nbsp;&nbsp; SBar.Panels[1].Text := '监听失败';<br>&nbsp; end;<br>end;</p> <p>&nbsp;</p> <p>procedure TMain.CMIncCount(var Msg: TCMSocketMessage);<br>var<br>&nbsp; addr: TSockAddrIn;<br>&nbsp; len: integer;<br>&nbsp; SendBuf: array[1..1024] of AnsiChar;<br>&nbsp; recvBuf: array[1..1024] of AnsiChar;<br>&nbsp; str: string;<br>&nbsp; OldOpenType {, NewOpenType}: integer;<br>begin<br>&nbsp; len := 0;</p> <p>&nbsp; str := '';</p> <p>&nbsp; case Msg.SelectEvent of<br>&nbsp;&nbsp;&nbsp; FD_READ: begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len := sizeof(recvBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ioctlsocket(SClinent, FIONREAD, Longint(len));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fillchar(recvBuf, sizeof(recvBuf), 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recv(SClinent, recvBuf, sizeof(recvBuf), 0);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add(string(recvBuf));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('read');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Memo1.Lines.Count &gt; 10 then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memo1.Clear;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(10);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fillchar(SendBuf, sizeof(SendBuf), 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Strcopy(@SendBuf, pansichar('OK'));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Send(SClinent, sendbuf, sizeof(sendbuf), 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</p> <p>&nbsp;&nbsp;&nbsp; FD_WRITE: begin</p> <p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('write');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp; FD_ACCEPT: begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len := sizeof(OldOpenType);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len) = 0 then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len := sizeof(addr);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SClinent := accept(s, @addr, @len);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if SClinent = INVALID_SOCKET then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('无效的socket:' + inttostr(SClinent));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('accept');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len := sizeof(OldOpenType);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WSAAsyncSelect(SClinent, handle, ASYNC_EVENT, $33);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp; FD_CONNECT: begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('connect');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp; FD_CLOSE: begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Memo1.Lines.Add('close');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end;<br>end;</p> <p>end.<br>//由于服务器端没有缓存机制,所以多个client连接的时候,第二个client的socket会覆盖前一个的,大家看情况改改就行了,网络上大把代码都是用控件或者其他封装好d类来写d,所以资料郁闷死了.</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>客户端代码:</p> <p>program Client;</p> <p>{$APPTYPE CONSOLE}</p> <p>uses<br>&nbsp; SysUtils,<br>&nbsp; windows,<br>&nbsp; winsock;</p> <p>var<br>&nbsp; addr: TSockAddrIn;<br>&nbsp; wsa: TWSaData;<br>&nbsp; flag: integer;<br>&nbsp; s: TSocket;<br>&nbsp; Host: string;<br>&nbsp; Port: Word;<br>&nbsp; BufSend: array[1..1024] of Ansichar; //中间信息<br>&nbsp; BufRev: array[1..1024] of Ansichar;<br>&nbsp; i: Integer;<br>begin<br>&nbsp; { TODO -oUser -cConsole Main : Insert code here }</p> <p>&nbsp; Host := '127.0.0.1';<br>&nbsp; port := 45531;</p> <p>&nbsp; flag := WSAStartup($0202, wsa); //加载winsock<br>&nbsp; if flag &lt;&gt; 0 then begin<br>&nbsp;&nbsp;&nbsp; Writeln(format('错误号:%d', [WSAGetLastError()]));<br>&nbsp;&nbsp;&nbsp; Writeln('Winsock库加载失败');<br>&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp; Writeln('Winsock库加载成功')<br>&nbsp; end;</p> <p>&nbsp; //s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服务器端的socket<br>&nbsp; s := socket(PF_INET, SOCK_STREAM, 0);<br>&nbsp; FillChar(addr, sizeof(addr), 0); //初始化地址空间</p> <p>&nbsp; addr.sin_port := htons(port);<br>&nbsp; addr.sin_family := AF_INET;<br>&nbsp; addr.sin_addr.S_addr := {INADDR_ANY; } inet_addr(pchar(host));</p> <p>&nbsp; if connect(s, addr, sizeof(addr)) = 0 then begin<br>&nbsp;&nbsp;&nbsp; Writeln('主机:' + Host + ' 连接成功')<br>&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp; Writeln('主机:' + Host + ' 连接失败');<br>&nbsp; end;</p> <p>&nbsp; FillChar(BufSend, 1024, 0);</p> <p>&nbsp; StrPCopy(@BufSend, '测试信息包');<br>&nbsp; for i := 0 to 100 do begin<br>&nbsp;&nbsp;&nbsp; Writeln(inttostr(s));<br>&nbsp;&nbsp;&nbsp; if Send(s, Bufsend, Length(BufSend), 0) &lt;&gt; SOCKET_ERROR then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writeln('消息已发送');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(500);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FillChar(BufRev, 1024, 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //strcopy(bufsend,pansichar('a'))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if recv(s, BufRev, Length(BufSend), 0) &lt;&gt; SOCKET_ERROR then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writeln('接收到的信息:' + trim(string(BufRev)));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writeln('接收消息失败!')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</p> <p>&nbsp;&nbsp;&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Writeln('消息发送失败')<br>&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end;</p> <p>&nbsp;</p> <p>&nbsp; if closeSocket(s) = 0 then begin<br>&nbsp;&nbsp;&nbsp; Writeln('已经关闭socket')<br>&nbsp; end else begin<br>&nbsp;&nbsp;&nbsp; Writeln('关闭socket 出错')<br>&nbsp; end;</p> <p>&nbsp; WSACleanup();<br>&nbsp; Readln;<br>end.</p><a href="http://blog.codelphi.com/liukun966123/archive/2005/03/16/35712.aspx"></a><img src ="http://www.cppblog.com/Khan/aggbug/2632.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2006-01-12 09:56 <a href="http://www.cppblog.com/Khan/archive/2006/01/12/2632.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于delphi 的函数调用和参数传递方式深入研究之疑惑</title><link>http://www.cppblog.com/Khan/archive/2004/11/22/2642.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Mon, 22 Nov 2004 14:14:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2004/11/22/2642.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2642.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/22/2642.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2642.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2642.html</trackback:ping><description><![CDATA[希望大家帮忙解答. delphi的函数 的参数传递方式 从我反汇编的代码来看好像不光是简单的压栈,涉及到了多个寄存器<img src="http://blog.codelphi.com/liukun966123/aggbug/29380.aspx" height="1" width="1"><br><br><p>关于delphi 的函数调用和参数传递方式深入研究</p> <p>&nbsp;</p> <p>delphi 代码如下:</p> <p>program Project1;</p> <p>uses windows, SysUtils;</p> <p><br>function a(d, dd: word; s, j, f: string): word;<br>begin<br>&nbsp; d := d - 1;<br>&nbsp; result := d + dd;<br>&nbsp; messagebox(0, pchar(inttostr(d) + s), pchar(inttostr(dd)), $0);<br>end;</p> <p>var s: string;</p> <p>begin<br>&nbsp; s := 'sssssssssss';<br>&nbsp;{ asm<br>&nbsp;&nbsp;&nbsp; mov dx,$11<br>&nbsp;&nbsp;&nbsp; mov ax,$33<br>&nbsp;&nbsp;&nbsp; call a;<br>&nbsp; end; }<br>&nbsp; a($33, $11, 'sssss', s, s);<br>end.</p> <p>&nbsp;</p> <p>汇编代码:<br>00407CA8&nbsp;&nbsp; . 447C4000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD Project1.00407C44<br>00407CAC &gt; $ 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EBP&nbsp;&nbsp;&nbsp;&nbsp; //保存栈顶<br>00407CAD&nbsp;&nbsp; . 8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EBP,ESP&nbsp; //初始化堆栈<br>00407CAF&nbsp;&nbsp; . 83C4 F0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ADD ESP,-10&nbsp; //开辟10个字节的栈<br>00407CB2&nbsp;&nbsp; . B8 6C7C4000&nbsp;&nbsp;&nbsp; MOV EAX,Project1.00407C6C<br>00407CB7&nbsp;&nbsp; . E8 34C7FFFF&nbsp;&nbsp;&nbsp; CALL Project1.004043F0<br>00407CBC&nbsp;&nbsp; . 33C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XOR EAX,EAX&nbsp; //EAX清0<br>00407CBE&nbsp;&nbsp; . 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EBP&nbsp;&nbsp;&nbsp;&nbsp; //保存栈顶<br>00407CBF&nbsp;&nbsp; . 68 037D4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407D03&nbsp; //保存返回地址<br>00407CC4&nbsp;&nbsp; . 64:FF30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH DWORD PTR FS:[EAX]&nbsp; //<br>00407CC7&nbsp;&nbsp; . 64:8920&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV DWORD PTR FS:[EAX],ESP&nbsp; //<br>00407CCA&nbsp;&nbsp; . B8 48984000&nbsp;&nbsp;&nbsp; MOV EAX,Project1.00409848&nbsp; <br>00407CCF&nbsp;&nbsp; . BA 187D4000&nbsp;&nbsp;&nbsp; MOV EDX,Project1.00407D18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp; ASCII "sssssssssss"&nbsp; //初始化局部变量<br>00407CD4&nbsp;&nbsp; . E8 2FB9FFFF&nbsp;&nbsp;&nbsp; CALL Project1.00403608&nbsp;&nbsp; <br>00407CD9&nbsp;&nbsp; . 68 2C7D4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407D2C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp; ASCII "jjjjjjjjjj"&nbsp; <br>00407CDE&nbsp;&nbsp; . 68 407D4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407D40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp; ASCII "ffffffffffff"<br>00407CE3&nbsp;&nbsp; . B9 587D4000&nbsp;&nbsp;&nbsp; MOV ECX,Project1.00407D58&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp; ASCII "sssss"<br>00407CE8&nbsp;&nbsp; . 66:BA 1100&nbsp;&nbsp;&nbsp;&nbsp; MOV DX,11<br>00407CEC&nbsp;&nbsp; . 66:B8 3300&nbsp;&nbsp;&nbsp;&nbsp; MOV AX,33<br>00407CF0&nbsp;&nbsp; . E8 9BFEFFFF&nbsp;&nbsp;&nbsp; CALL Project1.00407B90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //调用函数<br>00407CF5&nbsp;&nbsp; . 33C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XOR EAX,EAX<br>00407CF7&nbsp;&nbsp; . 5A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP EDX<br>00407CF8&nbsp;&nbsp; . 59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP ECX<br>00407CF9&nbsp;&nbsp; . 59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP ECX<br>00407CFA&nbsp;&nbsp; . 64:8910&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV DWORD PTR FS:[EAX],EDX<br>00407CFD&nbsp;&nbsp; . 68 0A7D4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407D0A<br>00407D02&nbsp;&nbsp; &gt; C3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp; RET used as a jump to 00407D0A</p> <p>00407D03&nbsp;&nbsp; .^E9 D4B2FFFF&nbsp;&nbsp;&nbsp; JMP Project1.00402FDC<br>00407D08&nbsp;&nbsp; .^EB F8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JMP SHORT Project1.00407D02<br>00407D0A&nbsp;&nbsp;&nbsp;&nbsp; E8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB E8<br>00407D0B&nbsp;&nbsp;&nbsp;&nbsp; B5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB B5<br>00407D0C&nbsp;&nbsp;&nbsp;&nbsp; B7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB B7<br>00407D0D&nbsp;&nbsp;&nbsp;&nbsp; FF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB FF<br>00407D0E&nbsp;&nbsp;&nbsp;&nbsp; FF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB FF<br>00407D0F&nbsp;&nbsp;&nbsp;&nbsp; 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB 00<br>00407D10&nbsp;&nbsp; . FFFFFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD FFFFFFFF<br>00407D14&nbsp;&nbsp; . 0B000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD 0000000B<br>00407D18&nbsp;&nbsp; . 73 73 73 73 73&gt;ASCII "sssssssssss",0<br>00407D24&nbsp;&nbsp; . FFFFFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD FFFFFFFF<br>00407D28&nbsp;&nbsp; . 0A000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD 0000000A<br>00407D2C&nbsp;&nbsp; . 6A 6A 6A 6A 6A&gt;ASCII "jjjjjjjjjj",0<br>00407D37&nbsp;&nbsp;&nbsp;&nbsp; 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB 00<br>00407D38&nbsp;&nbsp; . FFFFFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD FFFFFFFF<br>00407D3C&nbsp;&nbsp; . 0C000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD 0000000C<br>00407D40&nbsp;&nbsp; . 66 66 66 66 66&gt;ASCII "ffffffffffff",0<br>00407D4D&nbsp;&nbsp;&nbsp;&nbsp; 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB 00<br>00407D4E&nbsp;&nbsp;&nbsp;&nbsp; 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB 00<br>00407D4F&nbsp;&nbsp;&nbsp;&nbsp; 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DB 00<br>00407D50&nbsp;&nbsp; . FFFFFFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD FFFFFFFF<br>00407D54&nbsp;&nbsp; . 05000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DD 00000005<br>00407D58&nbsp;&nbsp; . 73 73 73 73 73&gt;ASCII "sssss",0</p> <p><br>function a(d, dd: word; s, j, f: string): word;<br>函数的代码:</p> <p>00407B90&nbsp; /$ 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EBP<br>00407B91&nbsp; |. 8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EBP,ESP<br>00407B93&nbsp; |. 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH 0<br>00407B95&nbsp; |. 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH 0<br>00407B97&nbsp; |. 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH 0<br>00407B99&nbsp; |. 53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EBX<br>00407B9A&nbsp; |. 56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH ESI<br>00407B9B&nbsp; |. 57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EDI<br>00407B9C&nbsp; |. 894D FC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV DWORD PTR SS:[EBP-4],ECX<br>00407B9F&nbsp; |. 8BF2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV ESI,EDX<br>00407BA1&nbsp; |. 8BD8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EBX,EAX<br>00407BA3&nbsp; |. 8B45 FC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EAX,DWORD PTR SS:[EBP-4]<br>00407BA6&nbsp; |. E8 49BDFFFF&nbsp;&nbsp;&nbsp; CALL Project1.004038F4<br>00407BAB&nbsp; |. 8B45 0C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EAX,DWORD PTR SS:[EBP+C]<br>00407BAE&nbsp; |. E8 41BDFFFF&nbsp;&nbsp;&nbsp; CALL Project1.004038F4<br>00407BB3&nbsp; |. 8B45 08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EAX,DWORD PTR SS:[EBP+8]<br>00407BB6&nbsp; |. E8 39BDFFFF&nbsp;&nbsp;&nbsp; CALL Project1.004038F4<br>00407BBB&nbsp; |. 33C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XOR EAX,EAX<br>00407BBD&nbsp; |. 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EBP<br>00407BBE&nbsp; |. 68 317C4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407C31<br>00407BC3&nbsp; |. 64:FF30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH DWORD PTR FS:[EAX]<br>00407BC6&nbsp; |. 64:8920&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV DWORD PTR FS:[EAX],ESP<br>00407BC9&nbsp; |. 4B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEC EBX<br>00407BCA&nbsp; |. 8D3C1E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EDI,DWORD PTR DS:[ESI+EBX]<br>00407BCD&nbsp; |. 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH 0<br>00407BCF&nbsp; |. 8D55 F8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EDX,DWORD PTR SS:[EBP-8]<br>00407BD2&nbsp; |. 0FB7C6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOVZX EAX,SI<br>00407BD5&nbsp; |. E8 5AD6FFFF&nbsp;&nbsp;&nbsp; CALL Project1.00405234<br>00407BDA&nbsp; |. 8B45 F8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EAX,DWORD PTR SS:[EBP-8]<br>00407BDD&nbsp; |. E8 22BDFFFF&nbsp;&nbsp;&nbsp; CALL Project1.00403904<br>00407BE2&nbsp; |. 50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EAX<br>00407BE3&nbsp; |. 8D55 F4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EDX,DWORD PTR SS:[EBP-C]<br>00407BE6&nbsp; |. 0FB7C3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOVZX EAX,BX<br>00407BE9&nbsp; |. E8 46D6FFFF&nbsp;&nbsp;&nbsp; CALL Project1.00405234<br>00407BEE&nbsp; |. 8D45 F4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EAX,DWORD PTR SS:[EBP-C]<br>00407BF1&nbsp; |. 8B55 FC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EDX,DWORD PTR SS:[EBP-4]<br>00407BF4&nbsp; |. E8 33BCFFFF&nbsp;&nbsp;&nbsp; CALL Project1.0040382C<br>00407BF9&nbsp; |. 8B45 F4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV EAX,DWORD PTR SS:[EBP-C]<br>00407BFC&nbsp; |. E8 03BDFFFF&nbsp;&nbsp;&nbsp; CALL Project1.00403904<br>00407C01&nbsp; |. 50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH EAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; |Text<br>00407C02&nbsp; |. 6A 00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUSH 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; |hOwner = NULL<br>00407C04&nbsp; |. E8 23C9FFFF&nbsp;&nbsp;&nbsp; CALL &lt;JMP.&amp;user32.MessageBoxA&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ; \MessageBoxA&nbsp; //这里stdcall方式调用messagebox<br>00407C09&nbsp; |. 33C0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XOR EAX,EAX<br>00407C0B&nbsp; |. 5A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP EDX<br>00407C0C&nbsp; |. 59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP ECX<br>00407C0D&nbsp; |. 59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; POP ECX<br>00407C0E&nbsp; |. 64:8910&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MOV DWORD PTR FS:[EAX],EDX<br>00407C11&nbsp; |. 68 387C4000&nbsp;&nbsp;&nbsp; PUSH Project1.00407C38<br>00407C16&nbsp; |&gt; 8D45 F4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EAX,DWORD PTR SS:[EBP-C]<br>00407C19&nbsp; |. BA 03000000&nbsp;&nbsp;&nbsp; MOV EDX,3<br>00407C1E&nbsp; |. E8 B5B9FFFF&nbsp;&nbsp;&nbsp; CALL Project1.004035D8<br>00407C23&nbsp; |. 8D45 08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEA EAX,DWORD PTR SS:[EBP+8]<br>00407C26&nbsp; |. BA 02000000&nbsp;&nbsp;&nbsp; MOV EDX,2<br>00407C2B&nbsp; |. E8 A8B9FFFF&nbsp;&nbsp;&nbsp; CALL Project1.004035D8<br>00407C30&nbsp; \. C3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETN</p> <p>&nbsp;</p> <p>&nbsp;</p> debug registers :<br>eax 00000000<br>ecx 00010101<br>edx ffffffff<br>ebx 7ffdf000<br>esp 0012ffc0&nbsp;&nbsp; <br>ebp 0012fff0<br>esi 00000000<br>edi 0012d870<br>eip 00407cad project1.&lt;ModuleEntryPoint&gt;<br><br>
				00407CCA   . B8 48984000    MOV EAX,Project1.00409848  
<br>00407CCF   . BA 187D4000    MOV EDX,Project1.00407D18                ;  ASCII "sssssssssss"  //初始化局部变量
<br>00407CD4   . E8 2FB9FFFF    CALL Project1.00403608   
<br>00407CD9   . 68 2C7D4000    PUSH Project1.00407D2C                   ;  ASCII "jjjjjjjjjj"  
<br>00407CDE   . 68 407D4000    PUSH Project1.00407D40                   ;  ASCII "ffffffffffff"
<br>00407CE3   . B9 587D4000    MOV ECX,Project1.00407D58                ;  ASCII "sssss"
<br>00407CE8   . 66:BA 1100     MOV DX,11
<br>00407CEC   . 66:B8 3300     MOV AX,33
<br>00407CF0   . E8 9BFEFFFF    CALL Project1.00407B90                   //调用函数
<br>
<br>函数原型为function a(d, dd: word; s, j, f: string): word;
<br>他的执行顺序是 先把J ,f 压栈 , 把 s 存入 ecx ,然后,将  dd,d 分别存入 dx 和 ax ,delphi到底按照什么顺序来处理参数d啊<br><br>
				Directive Parameter order Clean-upPasses parameters in registers?
<br>register   Left-to-right     Routine   Yes
<br>pascal     Left-to-right     Routine   No
<br>cdecl       Right-to-left     Caller       No
<br>stdcall     Right-to-left     Routine   No
<br>safecall   Right-to-left     Routine   No<br><br>参数传递方式:
<br>         Delphi中有自己的参数传递方式,而Windows API也有自己的参数传递方式,那么他们之间有什么不同呢,要如何做到兼容呢,尤其是在编写动态库时?
<br>  (1)cdecl:
<br>     通常是C/C++所使用的参数传递方式,它的传递方式是由右到左,而且当被调用的函数结束之后,将会由调用函数本身来清除堆栈上的参数数据.
<br>  (2)stdcall:
<br>     参数传递方式,也是由右到左,但是当被调用的函数结束之后,则是由被调用函数来清除堆栈上的参数数据,Win32API所有的输出函数都是采用此中参数传递方式
<br>  (3)pascal:
<br>     是Delphi1.0与win16API所使用的参数传递方式,它的传递方式是由左到右,而且由被调用函数来清除堆栈上的参数数据.
<br>  (4)fastcall:
<br>     是Delphi默认所使用的参数传递方式,此种方式在传递参数时把前三个参数放在CPU的EAX,EDX,ECX三个缓存器种,剩下的参数则会由左到右地被取出放到堆栈中,而当被调用的函数结束之       后,则是由被调用函数来清除堆栈上的参数数据.
<br>
注:所以在引用C++动态库中的函数时,要注意参数的传递方式,一般使用stdcall.还要注意字符串类型,C++在传递字符串时,都是采用字符指针的
类型(Char *),所以你在Delphi的程序中就必 须使用PCHAR类型,而不是string类型.<br><br>Delphi编译代码和一般的C编译代码不太一样，比如调用约定中，C的thiscall用ECX传递this指针，而Delphi的thiscall用
EAX传递this指针；C的fastcall一般用ECX/EDX两个寄存器用于参数传递，而Delphi则用三个EAX/EDX/ECX；在使用浮点
数时，C通过压栈两个DWORD传递double参数，而Delphi则用FLD和FSTP直接通过FPU传递参数。修饰名也不一样，这里不加叙述。
<br>
<br> 
<br>
<br>关于调用约定参考 <a target="_new" href="http://baby.homeip.net/patrick/archives/000142.php">http://baby.homeip.net/patrick/archives/000142.php</a>
<br>
<br> 
<br>
<br>目前的IDA尚不支持加载.MAP/.SYM符号信息，根据DataRescue网站的说明，可以通过.IDC脚本加载（<a target="_new" href="http://www.ccso.com/faq.html">http://www.ccso.com/faq.html</a>）。DeDe的IDA/Softice符号输出中据说可以自动检测运行的Soft-ICE并向其导入符号，但实际使用时不是很灵光，根据.MAP文件格式可以写一个程序将其转换成.IDC脚本：
<br>
<br> 
<br>
<br>#!/usr/bin/perl
<br>
<br>use strict; 
<br>
<br>sub dump_idc;
<br>
<br> 
<br>
<br>my $hex_pat = "[0-9A-Fa-f]+"; 
<br>
<br> 
<br>
<br>my $start; 
<br>
<br>my @entries; 
<br>
<br> 
<br>
<br>while (&lt;&gt;) {
<br>
<br>    chop; 
<br>
<br>    if ($start eq ''--fetch-next'') {
<br>
<br>       # start, length, name, class
<br>
<br>        ($start) = m/$hex_pat:($hex_pat)\s+($hex_pat)H\s+(\w+)\s+(\w+)/; 
<br>
<br>        if (!$start) {
<br>
<br>           print STDERR "Invalid .map file format!"; 
<br>
<br>           exit -1; 
<br>
<br>       }
<br>
<br>        $start = hex($start); 
<br>
<br>        next; 
<br>
<br>    }
<br>
<br> 
<br>
<br>    if (m/Start\s+Length\s+Name\s+Class/) {
<br>
<br>        $start = ''--fetch-next''; 
<br>
<br>        next; 
<br>
<br>    }
<br>
<br>    
<br>
<br>    if (m/$hex_pat:($hex_pat)\s*(.*)$/) {
<br>
<br>        my ($offset, $entry) = (hex($1), $2); 
<br>
<br>        my $rva = $offset + $start; 
<br>
<br>        push @entries, [$rva, $entry]; 
<br>
<br>    }
<br>
<br>}
<br>
<br> 
<br>
<br>@entries = sort { $a-&gt;[0] cmp $b-&gt;[0] } @entries; 
<br>
<br> 
<br>
<br>&amp;dump_idc; 
<br>
<br> 
<br>
<br>sub dump_idc {
<br>
<br>    print "static main() {\n"; 
<br>
<br>    
<br>
<br>    foreach (@entries) {
<br>
<br>        my ($rva, $entry) = @$_; 
<br>
<br>        #$rva = hex($rva); 
<br>
<br>       
<br>
<br>        $entry =~ s/^\*/\$/; 
<br>
<br>        $entry =~ s/^[&lt;&gt;\-]*//; 
<br>
<br>        $entry =~ s/\(.*$//; 
<br>
<br>        $entry =~ s/:.*$//; 
<br>
<br>        $entry =~ s/\./?/; 
<br>
<br>        $entry =~ s/\[([0-9]+)\]/_$1/g; 
<br>
<br>        $entry =~ s/\[.*$/_$rva/; 
<br>
<br>        $entry =~ s/;.*$//; 
<br>
<br> 
<br>
<br>        $entry =~ s/^\s *//; 
<br>
<br>        next if !$entry; 
<br>
<br>       
<br>
<br>        printf "MakeName(0x%x, \"$entry\");\n", $rva, $entry; 
<br>
<br>    }
<br>
<br>    
<br>
<br>    print "}\n"; 
<br>
<br>}
<br>
<br> 
<br>
<br>1;
<br>
<br> 
<br>
<br>有些程序在检验注册码时通过抛出异常等行为确定是否注册成功，关于异常Matt Pietrek有一篇著名文章<a target="_new" href="http://www.microsoft.com/msj/0197/Exception/Exception.aspx%E5%80%BC%E5%BE%97%E4%B8%80%E8%AF%BB">http://www.microsoft.com/msj/0197/Exception/Exception.aspx值得一读</a>。从汇编代码上看，所有try/catch块都有类似的结构：
<br>
<br> 
<br>
<br>CODE:004BDE4C          xor     eax, eax
<br>
<br>CODE:004BDE4E          push    ebp
<br>
<br>CODE:004BDE4F          push    offset loc_4BDE92
<br>
<br>CODE:004BDE54          push    dword ptr fs:[eax]    ; 保存上一个handler
<br>
<br>CODE:004BDE57          mov     fs:[eax], esp
<br>
<br> 
<br>
<br>CODE:004BDE92 loc_4BDE92: 
<br>
<br>CODE:004BDE92          jmp     _Any2_Handler_DevErr?
<br>
<br>CODE:004BDE97          jmp     short loc_4BDE89
<br>
<br> 
<br>
<br>CODE:004BDEEA          pop     edx               ; 上一个handler
<br>
<br>CODE:004BDEEB          pop     ecx
<br>
<br>CODE:004BDEEC          pop     ecx
<br>
<br>CODE:004BDEED          mov     fs:[eax], edx    ; 恢复
<br>
<br> 
<br>
<br>注意到4BDE97H处代码未被执行，这是怎么回事呢？原来它是finally对应的块，SEH内核会根据push offset
loc_4BDE92自动得到4BDE97H的finally入口地址。因此在调试有异常处理的程序时，有时需要在handler和finally的处理
程序处也设置断点。
<br>
<br> 
<br>
<br>今天先到这里，可能的话下次再贴。
<br><br>
				在周爱民的著作《DELPHI源代码分析》中，对此有描述。<br><br><img src ="http://www.cppblog.com/Khan/aggbug/2642.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-22 22:14 <a href="http://www.cppblog.com/Khan/archive/2004/11/22/2642.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>昨天开始打算写cmpp3.0的网关,于是拿了华为的demo反编译了一下,发现n多汉字都编程了unicode编码,于是自己写了一个unicode转汉字的程序,share给大家</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2004/11/19/2643.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2643.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/19/2643.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2643.html</wfw:commentRss><trackback:ping>http://www.cppblog.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">*&nbsp;&nbsp; 作者:刘昆 </font></p> <p><font face="Courier New">*&nbsp;&nbsp; 最后修改日期:&nbsp; 2004-11-18&nbsp;</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 以上代码免费,若直接引用一下代码请告知,并保留此注释</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作为一名程序员应该有最基本的职业道德*/</font></p> <p>unit MainForm;</p> <p>interface</p> <p>uses<br>&nbsp; Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br>&nbsp; Dialogs, StdCtrls, ExtCtrls;</p> <p>type<br>&nbsp; TFormMain = class(TForm)<br>&nbsp;&nbsp;&nbsp; Panel1: TPanel;<br>&nbsp;&nbsp;&nbsp; Memo1: TMemo;<br>&nbsp;&nbsp;&nbsp; ComboBox1: TComboBox;<br>&nbsp;&nbsp;&nbsp; Button1: TButton;<br>&nbsp;&nbsp;&nbsp; Memo2: TMemo;<br>&nbsp;&nbsp;&nbsp; procedure Button1Click(Sender: TObject);<br>&nbsp; private<br>&nbsp;&nbsp;&nbsp; function StrToUTF8(str: WideString): string;<br>&nbsp;&nbsp;&nbsp; function StrToASC(Str: string): string;<br>&nbsp;&nbsp;&nbsp; function GB2Unicode(Str: WideString): string; overload;<br>&nbsp;&nbsp;&nbsp; //function GB2Unicode(Str: string): string; overload;<br>&nbsp;&nbsp;&nbsp; function U2GB(Str: string): string;<br>&nbsp;&nbsp;&nbsp; function UTF8ToStr(const str: UTF8String): string;<br>&nbsp;&nbsp;&nbsp; function HexToInt(const Str: string): integer;<br>&nbsp;&nbsp;&nbsp; function HexIndex(const c: Char): Integer;<br>&nbsp;&nbsp;&nbsp; { Private declarations }<br>&nbsp; public<br>&nbsp;&nbsp;&nbsp; { Public declarations }<br>&nbsp; end;</p> <p>var<br>&nbsp; FormMain: TFormMain;</p> <p>implementation</p> <p>{$R *.dfm}</p> <p>{ TFormMain }</p> <p>function TFormMain.StrToASC(Str: string): string;<br>var<br>&nbsp; TmpStr: string;<br>&nbsp; TmpPchar: Pchar;<br>&nbsp; i: integer;<br>begin<br>&nbsp; result := '';<br>&nbsp; TmpStr := '';<br>&nbsp; TmpPchar := pchar(Str);<br>&nbsp; for i := 0 to length(TmpPchar) - 1 do<br>&nbsp;&nbsp;&nbsp; TmpStr := TmpStr + format('%2.2x', [ord(TmpPchar[i])]);</p> <p>&nbsp; result := TmpStr;<br>end;</p> <p>function TFormMain.StrToUTF8(str: WideString): string;<br>var<br>&nbsp; s: pchar;<br>&nbsp; i: integer;<br>&nbsp; tmp: string;<br>begin<br>&nbsp; tmp := '';<br>&nbsp; result := '';<br>&nbsp; s := pchar(Utf8encode(str));<br>&nbsp; for i := 0 to strlen(s) do begin<br>&nbsp;&nbsp;&nbsp; tmp := tmp + format('%2.2x', [ord(s[i])]);<br>&nbsp; end;<br>&nbsp; result := tmp;<br>end;</p> <p><br>function TFormMain.UTF8ToStr(const str: UTF8String): string;<br>var<br>&nbsp; s: pchar;<br>&nbsp; i: integer;<br>&nbsp; tmp: string;<br>begin<br>&nbsp; tmp := '';<br>&nbsp; result := '';<br>&nbsp; s := PChar(str);<br>&nbsp; i := 0;<br>&nbsp; while i &lt; length(s) do begin<br>&nbsp;&nbsp;&nbsp; tmp := tmp + chr(HexToInt(s[i] + s[i + 1]));<br>&nbsp;&nbsp;&nbsp; inc(i, 2);<br>&nbsp; end;<br>&nbsp; result := Utf8Decode(tmp);<br>end;</p> <p>function TFormMain.GB2Unicode(Str: WideString): string;<br>var<br>&nbsp; i: Integer;<br>begin<br>&nbsp; Result := '';<br>&nbsp; for i := 1 to Length(Str) do<br>&nbsp;&nbsp;&nbsp; Result := Result + Format('%4.4x', [ord(Str[i])]);<br>end;</p> <p><br>procedure TFormMain.Button1Click(Sender: TObject);<br>begin<br>&nbsp; case ComboBox1.ItemIndex of<br>&nbsp;&nbsp;&nbsp; 0: memo2.Lines.Add(GB2Unicode(memo1.Lines.Text));<br>&nbsp;&nbsp;&nbsp; 1: memo2.Lines.Add(StrToUTF8(memo1.Lines.Text));<br>&nbsp;&nbsp;&nbsp; 2: memo2.Lines.Add(UTF8ToStr(memo1.Lines.Text));<br>&nbsp;&nbsp;&nbsp; 3: memo2.Lines.Add(U2GB(StringReplace(memo1.Lines.Text, '\u', '', [rfReplaceAll])));<br>&nbsp;&nbsp;&nbsp; 4: memo2.Lines.Add(StrToASC(memo1.Lines.Text));<br>&nbsp; end;<br>end;</p> <p>function TFormMain.HexToInt(const Str: string): integer;<br>var p: pchar;</p> <p>begin<br>&nbsp; result := -1;<br>&nbsp; if length(str) &gt; 2 then exit;<br>&nbsp; p := pchar(str);</p> <p>&nbsp; if (HexIndex(p[0]) &lt;&gt; -1) and (HexIndex(p[1]) &lt;&gt; -1) then<br>&nbsp;&nbsp;&nbsp; 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>&nbsp; result := -1;<br>&nbsp; if (not (UpCase(c) in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'])) then<br>&nbsp;&nbsp;&nbsp; exit;</p> <p>&nbsp; for i := 0 to high(digits) do<br>&nbsp;&nbsp;&nbsp; if Digits[i] = UpCase(c) then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result := i;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp; end;<br>end;</p> <p><br>function TFormMain.U2GB(Str: string): string;<br>var s: pchar;<br>&nbsp; i: integer;<br>&nbsp; tmp: string;<br>begin<br>&nbsp; tmp := '';<br>&nbsp; result := '';<br>&nbsp; s := PChar(str);<br>&nbsp; i := 0;<br>&nbsp; while i &lt; length(s) do begin<br>&nbsp;&nbsp;&nbsp; tmp := tmp + chr(HexToInt(s[i + 2] + s[i + 3])) + chr(HexToInt(s[i] + s[i + 1]));//unicode转换时,高低位互换<br>&nbsp;&nbsp;&nbsp; inc(i, 4);<br>&nbsp; end;<br>&nbsp; result := widechartostring(pWideChar(tmp + #0#0#0#0));<br>end;</p> <p>end.</p><br><img src ="http://www.cppblog.com/Khan/aggbug/2643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-19 05:44 <a href="http://www.cppblog.com/Khan/archive/2004/11/19/2643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>起因源于之前忘记一个adsl的端口,想写一个端口探测工具,止于sp的订购关系包检测</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2004/11/12/2644.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2644.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/12/2644.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2644.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2644.html</trackback:ping><description><![CDATA[虽然只有这么点东西,但我还是做了3天,老了<br><br>&nbsp;一个sp用的wap订购关系包调试检测工具<img src="http://blog.codelphi.com/liukun966123/aggbug/28600.aspx" height="1" width="1"><br><br>  <p>&nbsp;</p> <p><font face="Courier New">/** 程序的核心,一个post线程,用于提交xml数据包</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作者:刘昆 </font></p> <p><font face="Courier New">*&nbsp;&nbsp; 最后修改日期:&nbsp; 2004-9-23&nbsp;</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 以上代码免费,若直接引用一下代码请告知,并保留此注释</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作为一名程序员应该有最基本的职业道德*/</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>&nbsp; TOnProgressEvent = procedure(TotalSize, Readed: Integer) of object;</font></p> <p><br><font face="Courier New">&nbsp; THTTPGetThread = class(TThread)</font></p> <p><font face="Courier New">&nbsp; private<br>&nbsp;&nbsp;&nbsp; FTAcceptTypes: string; //接收文件类型 *.*<br>&nbsp;&nbsp;&nbsp; FTAgent: string; //浏览器名&nbsp; Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.02<br>&nbsp;&nbsp;&nbsp; FTURL: string; // url<br>&nbsp;&nbsp;&nbsp; FTFileName: string; //文件名<br>&nbsp;&nbsp;&nbsp; FTStringResult: AnsiString;<br>&nbsp;&nbsp;&nbsp; FTUserName: string; //用户名<br>&nbsp;&nbsp;&nbsp; FTPassword: string; //密码<br>&nbsp;&nbsp;&nbsp; FTPostQuery: string; //方法名,post或者get<br>&nbsp;&nbsp;&nbsp; FTReferer: string;<br>&nbsp;&nbsp;&nbsp; FTBinaryData: Boolean;<br>&nbsp;&nbsp;&nbsp; FTUseCache: Boolean; //是否从缓存读数据<br>&nbsp;&nbsp;&nbsp; FTMimeType: string; //Mime类型</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; FTResult: Boolean;<br>&nbsp;&nbsp;&nbsp; FTFileSize: Integer;<br>&nbsp;&nbsp;&nbsp; FTToFile: Boolean; //是否文件</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; BytesToRead, BytesReaded: LongWord;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; FTProgress: TOnProgressEvent;<br>&nbsp;&nbsp;&nbsp; procedure ParseURL(URL: string; var HostName, FileName: string; var portNO: integer); //取得url的主机名和文件名<br>&nbsp;&nbsp;&nbsp; procedure UpdateProgress;<br>&nbsp; protected<br>&nbsp;&nbsp;&nbsp; procedure Execute; override;<br>&nbsp; public<br>&nbsp;&nbsp;&nbsp; procedure setResult(FResult: boolean);<br>&nbsp;&nbsp;&nbsp; function getResult(): boolean;<br>&nbsp;&nbsp;&nbsp; function getFileName(): string;<br>&nbsp;&nbsp;&nbsp; function getToFile(): boolean;<br>&nbsp;&nbsp;&nbsp; function getFileSize(): integer;<br>&nbsp;&nbsp;&nbsp; function getStringResult(): AnsiString;<br>&nbsp;&nbsp;&nbsp;
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">&nbsp; 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>&nbsp; FreeOnTerminate := True;<br>&nbsp; inherited Create(True);</font></p> <p><font face="Courier New">&nbsp; FTAcceptTypes := aAcceptTypes;<br>&nbsp; FTAgent := aAgent;<br>&nbsp; FTURL := aURL;<br>&nbsp; FTFileName := aFileName;<br>&nbsp; FTUserName := aUserName;<br>&nbsp; FTPassword := aPassword;</font></p> <p><font face="Courier New">&nbsp; //FTPostQuery := aPostQuery;</font></p> <p><font face="Courier New">&nbsp; FTPostQuery := StringReplace(aPostQuery, #13#10, '', [rfReplaceAll]);</font></p> <p><font face="Courier New">&nbsp; FTReferer := aReferer;<br>&nbsp; FTProgress := aProgress;<br>&nbsp; FTBinaryData := aBinaryData;<br>&nbsp; FTUseCache := aUseCache;<br>&nbsp; FTMimeType := aMimeType;</font></p> <p><font face="Courier New">&nbsp; FTToFile := aToFile;<br>&nbsp; Resume;<br>end;</font></p> <p><font face="Courier New">procedure THTTPGetThread.Execute;<br>var<br>&nbsp; hSession: hInternet; //回话句柄<br>&nbsp; hConnect: hInternet; //连接句柄<br>&nbsp; hRequest: hInternet; //请求句柄<br>&nbsp; Host_Name: string; //主机名<br>&nbsp; File_Name: string; //文件名<br>&nbsp; port_no: integer;</font></p> <p><font face="Courier New">&nbsp; RequestMethod: PChar;<br>&nbsp; InternetFlag: longWord;<br>&nbsp; AcceptType: PAnsiChar;<br>&nbsp; dwBufLen, dwIndex: longword;<br>&nbsp; Buf: Pointer; //缓冲区<br>&nbsp; f: file;<br>&nbsp; Data: array[0..$400] of Char;<br>&nbsp; TempStr: AnsiString;<br>&nbsp; mime_Head: string;</font></p> <p><font face="Courier New">&nbsp; procedure CloseHandles;<br>&nbsp; begin<br>&nbsp;&nbsp;&nbsp; InternetCloseHandle(hRequest);<br>&nbsp;&nbsp;&nbsp; InternetCloseHandle(hConnect);<br>&nbsp;&nbsp;&nbsp; InternetCloseHandle(hSession);<br>&nbsp; end;</font></p> <p><font face="Courier New">begin<br>&nbsp; inherited;<br>&nbsp; buf := nil;<br>&nbsp; try<br>&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ParseURL(FTURL, Host_Name, File_Name, port_no);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Terminated then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := False;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp;&nbsp; //建立会话<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hSession := InternetOpen(pchar(FTAgent), //lpszCallerName指定正在使用网络函数的应用程序<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTERNET_OPEN_TYPE_PRECONFIG, //参数dwAccessType指定访问类型<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nil, //服务器名（lpszProxyName）。 accesstype为GATEWAY_PROXY_INTERNET_ACCESS和CERN_PROXY_ACCESS时<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nil, //NProxyPort参数用在CERN_PROXY_INTERNET_ACCESS中用来指定使用的端口数。使用INTERNET_INVALID_PORT_NUMBER相当于提供却省的端口数。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0); //设置额外的选择。你可以使用INTERNET_FLAG_ASYNC标志去指示使用返回句句柄的将来的Internet函数将为回调函数发送状态信息，使用InternetSetStatusCallback进行此项设置</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp; //建立连接<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hConnect := InternetConnect(hSession, //会话句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(Host_Name), //指向包含Internet服务器的主机名称（如</font><a href="http://www.mit.edu/"><font face="Courier New">http://www.mit.edu</font></a><font face="Courier New">）或IP地址（如202.102.13.141）的字符串<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; port_no, //INTERNET_DEFAULT_HTTP_PORT, //是将要连结到的TCP/IP的端口号<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(FTUserName), //用户名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(FTPassword), //密码<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTERNET_SERVICE_HTTP, //协议<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0, // 可选标记，设置为INTERNET_FLAG_SECURE，表示使用SSL/PCT协议完成事务<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0); //应用程序定义的值，用来为返回的句柄标识应用程序设备场境</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTPostQuery = '' then RequestMethod := 'GET'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else RequestMethod := 'POST';</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTUseCache then InternetFlag := 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else InternetFlag := INTERNET_FLAG_RELOAD;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AcceptType := PChar('Accept: ' + FTAcceptTypes);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; //建立一个http请求句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hRequest := HttpOpenRequest(hConnect, //InternetConnect返回的HTTP会话句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RequestMethod, //指向在申请中使用的"动词"的字符串，如果设置为NULL，则使用"GET"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(File_Name), //指向包含动词的目标对象名称的字符串，通常是文件名称、可执行模块或搜索说明符<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'HTTP/1.0', //指向包含HTTP版本的字符串，如果为NULL，则默认为"HTTP/1.0"；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(FTReferer), //指向包含文档地址（URL）的字符串，申请的URL必须是从该文档获取的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @AcceptType, //指向客户接收的内容的类型<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InternetFlag,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mime_Head := 'Content-Type: ' + FTMimeType;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTPostQuery = '' then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := HttpSendRequest(hRequest, nil, 0, nil, 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp; //发送一个指定请求到httpserver<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := HttpSendRequest(hRequest,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pchar(mime_Head), //mime 头<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; length(mime_Head), //头长度<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PChar(FTPostQuery), //附加数据缓冲区，可为空<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strlen(PChar(FTPostQuery))); //附加数据缓冲区长度</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Terminated then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //CloseHandles;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := False;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwIndex := 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwBufLen := 1024;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetMem(Buf, dwBufLen);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; //接收header信息和一个http请求<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := HttpQueryInfo(hRequest,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HTTP_QUERY_CONTENT_LENGTH,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Buf, //指向一个接收请求信息的缓冲区的指针<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwBufLen, //HttpQueryInfo内容的大小<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwIndex); //读取的字节数</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Terminated then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := False;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTResult or not FTBinaryData then begin //如果请求<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTResult then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTFileSize := StrToInt(StrPas(Buf));</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BytesReaded := 0;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTToFile then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AssignFile(f, FTFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rewrite(f, 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end else FTStringResult := '';</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while True do begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Terminated then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := False;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not InternetReadFile(hRequest,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Data, //数据内容<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SizeOf(Data), //大小<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BytesToRead) //读取的字节数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then Break<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if BytesToRead = 0 then Break<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTToFile then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BlockWrite(f, Data, BytesToRead) //将读出的数据写入文件<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TempStr := Data;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetLength(TempStr, BytesToRead);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTStringResult := FTStringResult + TempStr;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inc(BytesReaded, BytesToRead);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Assigned(FTProgress) then //执行回调函数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Synchronize(UpdateProgress);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if FTToFile then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := FTFileSize = Integer(BytesReaded)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SetLength(FTStringResult, BytesReaded);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTResult := BytesReaded &lt;&gt; 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp;&nbsp;&nbsp; except<br>&nbsp;&nbsp;&nbsp; end;<br>&nbsp; finally<br>&nbsp;&nbsp;&nbsp; if FTToFile then CloseFile(f);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; if assigned(Buf) then FreeMem(Buf);<br>&nbsp;&nbsp;&nbsp; CloseHandles;<br>&nbsp; end;<br>end;</font></p> <p>&nbsp;</p> <p><font face="Courier New">function THTTPGetThread.getFileName: string;<br>begin<br>&nbsp; result := FTFileName;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getFileSize: integer;<br>begin<br>&nbsp; result := FTFileSize;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getResult: boolean;<br>begin<br>&nbsp; result := FTResult;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getStringResult: AnsiString;<br>begin<br>&nbsp; result := FTStringResult;<br>end;</font></p> <p><font face="Courier New">function THTTPGetThread.getToFile: boolean;<br>begin<br>&nbsp; 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>&nbsp; i: Integer;<br>begin<br>&nbsp; if Pos('http://', LowerCase(URL)) &lt;&gt; 0 then<br>&nbsp;&nbsp;&nbsp; Delete(URL, 1, 7);</font></p> <p><font face="Courier New">&nbsp; i := Pos('/', URL);<br>&nbsp; HostName := Copy(URL, 1, i);<br>&nbsp; FileName := Copy(URL, i, Length(URL) - i + 1);</font></p> <p><font face="Courier New">&nbsp; i := pos(':', hostName);<br>&nbsp; if i &lt;&gt; 0 then begin<br>&nbsp;&nbsp;&nbsp; portNO := strtoint(copy(hostName, i + 1, length(hostName) - i - 1));<br>&nbsp;&nbsp;&nbsp; hostName := copy(hostName, 1, i - 1);<br>&nbsp; end else portNO := 80;</font></p> <p><font face="Courier New">&nbsp; if (Length(HostName) &gt; 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>&nbsp; FTResult := FResult;<br>end;</font></p> <p><font face="Courier New">procedure THTTPGetThread.UpdateProgress;<br>begin<br>&nbsp; FTProgress(FTFileSize, BytesReaded);<br>end;</font></p> <p><font face="Courier New">end.</font></p> <p>&nbsp;</p> <p><font face="Courier New">/** 主要用来做线程和界面的交互</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作者:刘昆 </font></p> <p><font face="Courier New">*&nbsp;&nbsp; 最后修改日期:&nbsp; 2004-9-23&nbsp;</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 以上代码免费,若直接引用一下代码请告知,并保留此注释</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作为一名程序员应该有最基本的职业道德*/</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>&nbsp; TOnDoneFileEvent = procedure(FileName: string; FileSize: Integer) of object;<br>&nbsp; TOnDoneStringEvent = procedure(Result: AnsiString) of object;</font></p> <p><br><font face="Courier New">&nbsp; THttpGet = class<br>&nbsp; private<br>&nbsp;&nbsp;&nbsp; F_URL: string; //目标url<br>&nbsp;&nbsp;&nbsp; F_GetURLThread: THTTPGetThread; //取数据的线程</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; F_Accept_Types: string;<br>&nbsp;&nbsp;&nbsp; F_Agent: string;<br>&nbsp;&nbsp;&nbsp; F_Binary_Data: Boolean;<br>&nbsp;&nbsp;&nbsp; F_Use_Cache: Boolean; //是否读缓存<br>&nbsp;&nbsp;&nbsp; F_File_Name: string;<br>&nbsp;&nbsp;&nbsp; F_User_Name: string; //用户名<br>&nbsp;&nbsp;&nbsp; F_Password: string; //密码<br>&nbsp;&nbsp;&nbsp; F_PostQuery: string; //方法名<br>&nbsp;&nbsp;&nbsp; F_Referer: string;<br>&nbsp;&nbsp;&nbsp; F_Mime_Type: string;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; F_Wait_Thread: Boolean;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; FResult: Boolean;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; FProgress: TOnProgressEvent;<br>&nbsp;&nbsp;&nbsp; FDoneFile: TOnDoneFileEvent;<br>&nbsp;&nbsp;&nbsp; FDoneString: TOnDoneStringEvent;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; procedure ThreadDone(Sender: TObject);</font></p> <p><font face="Courier New">&nbsp; public<br>&nbsp;&nbsp;&nbsp; constructor Create();<br>&nbsp;&nbsp;&nbsp; destructor Destroy(); override;<br>&nbsp;&nbsp;&nbsp; procedure getFile();<br>&nbsp;&nbsp;&nbsp; procedure GetString();<br>&nbsp;&nbsp;&nbsp; procedure Abort();<br>&nbsp; published<br>&nbsp;&nbsp;&nbsp; property WaitThread: Boolean read F_Wait_Thread write F_Wait_Thread;<br>&nbsp;&nbsp;&nbsp; property AcceptTypes: string read F_Accept_Types write F_Accept_Types;<br>&nbsp;&nbsp;&nbsp; property Agent: string read F_Agent write F_Agent;<br>&nbsp;&nbsp;&nbsp; property BinaryData: Boolean read F_Binary_Data write F_Binary_Data;<br>&nbsp;&nbsp;&nbsp; property URL: string read F_URL write F_URL;<br>&nbsp;&nbsp;&nbsp; property UseCache: Boolean read F_Use_Cache write F_Use_Cache;<br>&nbsp;&nbsp;&nbsp; property FileName: string read F_File_Name write F_File_Name;<br>&nbsp;&nbsp;&nbsp; property UserName: string read F_User_Name write F_User_Name;<br>&nbsp;&nbsp;&nbsp; property Password: string read F_Password write F_Password;<br>&nbsp;&nbsp;&nbsp; property PostQuery: string read F_PostQuery write F_PostQuery;<br>&nbsp;&nbsp;&nbsp; property Referer: string read F_Referer write F_Referer;<br>&nbsp;&nbsp;&nbsp; property MimeType: string read F_Mime_Type write F_Mime_Type;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; property OnDoneFile: TOnDoneFileEvent read FDoneFile write FDoneFile;<br>&nbsp;&nbsp;&nbsp; property OnDoneString: TOnDoneStringEvent read FDoneString write FDoneString;<br>&nbsp; end;</font></p> <p><font face="Courier New">implementation</font></p> <p>&nbsp;</p> <p><font face="Courier New">{ THttpGet }</font></p> <p><font face="Courier New">procedure THttpGet.Abort;<br>begin<br>&nbsp; if Assigned(F_GetURLThread) then<br>&nbsp; begin<br>&nbsp;&nbsp;&nbsp; F_GetURLThread.Terminate;<br>&nbsp;&nbsp;&nbsp; F_GetURLThread.setResult(false);<br>&nbsp; end;<br>end;</font></p> <p><font face="Courier New">constructor THttpGet.Create;<br>begin<br>&nbsp; F_Accept_Types := '*/*';<br>&nbsp; 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>&nbsp; Msg: TMsg;<br>begin<br>&nbsp; if not Assigned(F_GetURLThread) then<br>&nbsp; begin<br>&nbsp;&nbsp;&nbsp;
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>&nbsp;&nbsp;&nbsp; F_GetURLThread.OnTerminate := ThreadDone;<br>&nbsp;&nbsp;&nbsp; if F_Wait_Thread then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while Assigned(F_GetURLThread) do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(Msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(Msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end<br>end;</font></p> <p><font face="Courier New">procedure THttpGet.GetString;<br>var<br>&nbsp; Msg: TMsg;<br>begin<br>&nbsp; if not Assigned(F_GetURLThread) then<br>&nbsp; begin<br>&nbsp;&nbsp;&nbsp;
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>&nbsp;&nbsp;&nbsp; F_GetURLThread.OnTerminate := ThreadDone;<br>&nbsp;&nbsp;&nbsp; if F_Wait_Thread then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while Assigned(F_GetURLThread) do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(Msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(Msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end<br>end;</font></p> <p><font face="Courier New">procedure THttpGet.ThreadDone(Sender: TObject);<br>begin<br>&nbsp; FResult := F_GetURLThread.getResult;<br>&nbsp; if FResult then<br>&nbsp;&nbsp;&nbsp; if F_GetURLThread.getToFile then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Assigned(FDoneFile) then FDoneFile(F_GetURLThread.getFileName, F_GetURLThread.getFileSize)<br>&nbsp;&nbsp;&nbsp; end else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if Assigned(FDoneString) then FDoneString(F_GetURLThread.getStringResult);</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; //end else if Assigned(FError) then FError(Self);<br>&nbsp; F_GetURLThread := nil;<br>end;</font></p> <p><font face="Courier New">end.</font></p> <p>&nbsp;</p> <p><font face="Courier New">/** 程序主界面</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作者:刘昆 </font></p> <p><font face="Courier New">*&nbsp;&nbsp; 最后修改日期:&nbsp; 2004-9-23&nbsp;</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 以上代码免费,若直接引用一下代码请告知,并保留此注释</font></p> <p><font face="Courier New">*&nbsp;&nbsp; 作为一名程序员应该有最基本的职业道德*/</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>&nbsp; Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br>&nbsp; Dialogs, StdCtrls, ExtCtrls, MyHttpGet;</font></p> <p><font face="Courier New">type<br>&nbsp; TMain = class(TForm)<br>&nbsp;&nbsp;&nbsp; Panel1: TPanel;<br>&nbsp;&nbsp;&nbsp; Edit1: TEdit;<br>&nbsp;&nbsp;&nbsp; Label1: TLabel;<br>&nbsp;&nbsp;&nbsp; Panel2: TPanel;<br>&nbsp;&nbsp;&nbsp; Panel3: TPanel;<br>&nbsp;&nbsp;&nbsp; GroupBox1: TGroupBox;<br>&nbsp;&nbsp;&nbsp; MeSend: TMemo;<br>&nbsp;&nbsp;&nbsp; GroupBox2: TGroupBox;<br>&nbsp;&nbsp;&nbsp; MeReceive: TMemo;<br>&nbsp;&nbsp;&nbsp; Button1: TButton;<br>&nbsp;&nbsp;&nbsp; CbSave: TCheckBox;<br>&nbsp;&nbsp;&nbsp; Edit2: TEdit;<br>&nbsp;&nbsp;&nbsp; Label2: TLabel;<br>&nbsp;&nbsp;&nbsp; procedure Button1Click(Sender: TObject);<br>&nbsp; private<br>&nbsp;&nbsp;&nbsp; { Private declarations }<br>&nbsp;&nbsp;&nbsp; procedure onGetString(Result: AnsiString);<br>&nbsp;&nbsp;&nbsp; procedure onGetFile(FileName: string; FileSize: Integer);</font></p> <p><font face="Courier New">&nbsp; public<br>&nbsp;&nbsp;&nbsp; { Public declarations }<br>&nbsp; end;</font></p> <p><font face="Courier New">var<br>&nbsp; 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>&nbsp; strs: TStrings;<br>&nbsp; i: Integer;<br>begin<br>&nbsp; hg := nil;<br>&nbsp; strs := nil;<br>&nbsp; try<br>&nbsp;&nbsp;&nbsp; strs := TStringList.Create;<br>&nbsp;&nbsp;&nbsp; hg := THttpGet.Create;<br>&nbsp;&nbsp;&nbsp; hg.WaitThread := false;<br>&nbsp;&nbsp;&nbsp; hg.AcceptTypes := '*.*';</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; hg.Agent := 'Nokia6610/1.0 (5.52) Profile/MIDP-1.0 Configuration/CLDC-1.02';<br>&nbsp;&nbsp;&nbsp; hg.BinaryData := false;<br>&nbsp;&nbsp;&nbsp; hg.URL := 'Http://' + Edit1.Text;<br>&nbsp;&nbsp;&nbsp; hg.UseCache := false;<br>&nbsp;&nbsp;&nbsp; hg.FileName := 'provison.xml';<br>&nbsp;&nbsp;&nbsp; hg.UserName := '';<br>&nbsp;&nbsp;&nbsp; hg.Password := '';</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; for i := 0 to MeSend.Lines.Count - 1 do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strs.Add(trim(MeSend.Lines[i]));</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; hg.PostQuery := strs.Text;<br>&nbsp;&nbsp;&nbsp; hg.Referer := 'Http://' + Edit1.Text; //text/plain<br>&nbsp;&nbsp;&nbsp; hg.MimeType := Edit2.Text;<br>&nbsp;&nbsp;&nbsp; hg.OnDoneString := onGetString;<br>&nbsp;&nbsp;&nbsp; hg.OnDoneFile := onGetFile;</font></p> <p><font face="Courier New">&nbsp;&nbsp;&nbsp; hg.GetString;<br>&nbsp; finally<br>&nbsp;&nbsp;&nbsp; strs.Free;<br>&nbsp;&nbsp;&nbsp; hg.Free;<br>&nbsp; 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>&nbsp; MeReceive.Lines.Text := Result;<br>end;</font></p> <p><font face="Courier New">end.</font></p><br><br><img src ="http://www.cppblog.com/Khan/aggbug/2644.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-12 03:25 <a href="http://www.cppblog.com/Khan/archive/2004/11/12/2644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>每个月都有那么几天让偶心烦,突然想做一个控制modem或者adsl modem发传真的东西</title><link>http://www.cppblog.com/Khan/archive/2004/11/09/2645.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Tue, 09 Nov 2004 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2004/11/09/2645.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2645.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/09/2645.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2645.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2645.html</trackback:ping><description><![CDATA[传真,开源,object pascal,无第三方控件和class<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原因就素因为我家里有一部传真机,我想把他当打印机用,仔细在网上找了一下,发现没有什么资料,只有一些软件或控件. <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我发誓,要让这些把技术拽在手里饿死.</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 靠,能写个把软件了不起啊,</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这个写完了以后,照旧开源,照旧不用第三方控件或class</p><img src="http://blog.codelphi.com/liukun966123/aggbug/28374.aspx" height="1" width="1"><img src ="http://www.cppblog.com/Khan/aggbug/2645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-09 21:45 <a href="http://www.cppblog.com/Khan/archive/2004/11/09/2645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于delphi的log的class已经完成,一如既往的open 他</title><link>http://www.cppblog.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.cppblog.com/Khan/archive/2004/11/09/2646.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2646.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/09/2646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2646.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2646.html</trackback:ping><description><![CDATA[delphi ,日志class,临界区,文件操作<img src="http://blog.codelphi.com/liukun966123/aggbug/28356.aspx" height="1" width="1"><br><br><br><p>如果你引用或者修改以下代码 请不要去掉注释,这个涉及到一个程序员的职业道德问题</p><p>转载请注明</p><p>/** 本代码为日志class</p><p>*&nbsp;&nbsp; 作者:刘昆 </p><p>*&nbsp;&nbsp; 最后修改日期:&nbsp; 2004-9-23&nbsp;</p><p>*&nbsp;&nbsp; 以上代码免费,若直接引用一下代码请告知,并保留此注释</p><p>*&nbsp;&nbsp; 作为一名程序员应该有最基本的职业道德*/</p><p>unit pushLog;</p><p>interface</p><p>uses classes, sysutils, windows;</p><p>var<br>&nbsp; ThreadLock: TRTLCriticalSection; //临界区</p><p><br>const PathDelim = '\';<br>&nbsp; DriveDelim = ':';</p><p>type<br>&nbsp; Tlog = class<br>&nbsp; private<br>&nbsp;&nbsp;&nbsp; //logfile: file;<br>&nbsp;&nbsp;&nbsp; fileName: string;</p><p>&nbsp;&nbsp;&nbsp; function dirExist(const DirName: string): boolean;<br>&nbsp;&nbsp;&nbsp; function getDirName(const fileName: string): string;<br>&nbsp;&nbsp;&nbsp; function LastDelimiter(const Delimiters, S: string): Integer;</p><p>&nbsp;&nbsp;&nbsp; procedure createLogDir();</p><p><br>&nbsp; public<br>&nbsp;&nbsp;&nbsp; constructor Create(const filename: string);<br>&nbsp;&nbsp;&nbsp; destructor Destroy(); override;</p><p>&nbsp;&nbsp;&nbsp; procedure addLog(p: Pchar);<br>&nbsp; end;</p><p>implementation</p><p><br>{ Tlog }</p><p>procedure Tlog.addLog(p: Pchar);<br>var log_Line: pchar;<br>&nbsp; log_len: integer;<br>&nbsp; handle: Thandle;<br>&nbsp; des_Len: longword;<br>begin<br>&nbsp; EnterCriticalSection(ThreadLock);<br>&nbsp; log_Line := nil;<br>&nbsp; handle := $0;<br>&nbsp; des_Len := $0;<br>&nbsp; try<br>&nbsp;&nbsp;&nbsp; createLogDir;<br>&nbsp;&nbsp;&nbsp; log_len := strlen(p);<br>&nbsp;&nbsp;&nbsp; getmem(log_Line, log_len);<br>&nbsp;&nbsp;&nbsp; strcopy(log_Line, p);</p><p>&nbsp;&nbsp;&nbsp; handle := createfile(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pchar(fileName), //文件名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GENERIC_READ or GENERIC_WRITE, //期望存取模式 通用读写<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE_SHARE_READ or FILE_SHARE_WRITE, //共享模式<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nil, //定义文件安全特性的指针（前提：操作系统支持）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OPEN_ALWAYS, //打开和创建文件方式。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE_ATTRIBUTE_NORMAL or FILE_FLAG_RANDOM_ACCESS, //要打开文件的标志和属性（如：隐藏，系统等）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0); //模板文件句柄</p><p>&nbsp;&nbsp;&nbsp; if handle &lt;&gt; INVALID_HANDLE_VALUE then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetFilePointer(handle, 0, nil, FILE_END);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteFile(handle, log_Line^, log_len, des_Len, nil);</p><p>&nbsp;&nbsp;&nbsp; end;<br>&nbsp; finally<br>&nbsp;&nbsp;&nbsp; CloseHandle(handle);<br>&nbsp;&nbsp;&nbsp; freeMem(log_Line);<br>&nbsp;&nbsp;&nbsp; LeaveCriticalSection(ThreadLock);<br>&nbsp; end;<br>end;</p><p>&nbsp;</p><p>constructor Tlog.Create(const filename: string);<br>begin<br>&nbsp; self.fileName := filename;<br>end;</p><p>&nbsp;</p><p><br>procedure Tlog.createLogDir;<br>var dir_Name: string;<br>begin<br>&nbsp; dir_Name := getDirName(fileName) + '\log';<br>&nbsp; if not DirExist(dir_Name) then begin //检测日志目录是否存在<br>&nbsp;&nbsp;&nbsp; mkdir(dir_Name);<br>&nbsp; end;<br>end;</p><p>&nbsp;</p><p>destructor Tlog.Destroy;<br>begin<br>&nbsp; inherited;<br>end;</p><p>&nbsp;</p><p>function Tlog.DirExist(const DirName: string): boolean;<br>var<br>&nbsp; Handle: THandle;<br>&nbsp; FindData: TWin32FindData;<br>begin<br>&nbsp; result := false;<br>&nbsp; Handle := FindFirstFile(PChar(DirName), FindData);<br>&nbsp; if Handle &lt;&gt; INVALID_HANDLE_VALUE then begin<br>&nbsp;&nbsp;&nbsp; FindClose(Handle);<br>&nbsp;&nbsp;&nbsp; if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = $10 then begin<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result := true;<br>&nbsp;&nbsp;&nbsp; end;<br>&nbsp; end;<br>end;</p><p>&nbsp;</p><p>function Tlog.getDirName(const fileName: string): string;<br>var<br>&nbsp; I: Integer;<br>begin<br>&nbsp; I := LastDelimiter(':\', Filename);<br>&nbsp;
if (I &gt; 1) and (FileName[I] = PathDelim) and (((FileName[I - 1]
&lt;&gt; PathDelim) and (FileName[I - 1] &lt;&gt; DriveDelim)) or
(ByteType(FileName, I - 1) = mbTrailByte)) then<br>&nbsp;&nbsp;&nbsp; Dec(I);<br>&nbsp; while (ByteType(FileName, I - 1) = mbTrailByte) and (I &gt; 0) do<br>&nbsp;&nbsp;&nbsp; Dec(I);<br>&nbsp; Result := Copy(FileName, 1, I);<br>end;</p><p>&nbsp;</p><p>&nbsp;</p><p><br>function Tlog.LastDelimiter(const Delimiters, S: string): Integer;<br>var<br>&nbsp; P: PChar;<br>begin<br>&nbsp; Result := Length(S);<br>&nbsp; P := PChar(Delimiters);<br>&nbsp; while Result &gt; 0 do<br>&nbsp; begin<br>&nbsp;&nbsp;&nbsp; if (S[Result] &lt;&gt; #0) and (StrScan(P, S[Result]) &lt;&gt; nil) then // 检测最后一个字符是否为 '\'或者':'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ByteType(S, Result) = mbTrailByte) then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dec(Result)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit;<br>&nbsp;&nbsp;&nbsp; Dec(Result);<br>&nbsp; end;<br>end;</p><p>&nbsp;</p><p><br>initialization<br>&nbsp; InitializeCriticalSection(ThreadLock);<br>finalization<br>&nbsp; DeleteCriticalSection(ThreadLock);<br>end.<br></p><p>&nbsp;</p><p>&nbsp;</p><p>调用方法</p><p>procedure TMain.Button1Click(Sender: TObject);<br>var<br>&nbsp; log: Tlog;<br>begin</p><p>&nbsp; log := Tlog.Create(ExtractFileDir(Application.Exename) + '\' + 'aa.log');<br>&nbsp; log.addLog(pchar('好的' + #13#10));<br>&nbsp; log.addLog(pchar('aaaaaaaaaaaaaaaaaaaa' + #13#10));<br>&nbsp; log.Free;<br>end;</p><br><img src ="http://www.cppblog.com/Khan/aggbug/2646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-09 19:10 <a href="http://www.cppblog.com/Khan/archive/2004/11/09/2646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天突然想写一个关于日志文件的class,用pascal,以前用java几简单,pascal的这块反而没有接触过</title><link>http://www.cppblog.com/Khan/archive/2004/11/08/2647.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Mon, 08 Nov 2004 13:27:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2004/11/08/2647.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/2647.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2004/11/08/2647.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/2647.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/2647.html</trackback:ping><description><![CDATA[delphi 日志 class<img src="http://blog.codelphi.com/liukun966123/aggbug/28265.aspx" height="1" width="1"><br><br><p>文本文件是由若干行组成的，若干个字符串组成一行，一行的结尾由回车换行符表示。如果对文本文件进行操作，则首先应通过调用AssignFile过
程建立文件变量与外部文件的联系，并且使用Reset或ReWrite或Append方法打开。由于文本文件是以行为单位进行读写操作的，并且每一行的长
度不一定相同，所以不能计算出指定行在文件中的准确位置，因此对于文件只能顺序的读写。要对文件进行读写操作，必须相应的对文件进行以读或写的方式打开，
也就是对一个文本文件只能单独进行读或写的操作，而不能同时进行。</p><p>1、 以添加方式打开文件(Append)</p><p>通过调用函数Append可打开一个已经存在的文件以便在文件末尾添加文本。如果在文件最后的128个字节块中，存在字符〈ctrl〉+〈z〉（ASCII26），那么文件将在字节处插入，并且覆盖该字符。</p><p>Append过程的声明如下：<br>procedure Append(var F:text);</p><p>其
中F是一个任意文件类型的变量，并且必须同用AssignFile函数打开的外部文件相联系，如果指定的文件不存在，则会产生错误，如果指定的文件已经打
开，则先关闭再重新打开。当前文件的位置设置在文件末尾。如果分配给F的是一个空名字，则在调用Append函数后，文件变量（F）将同将同标准输出文件
建立联系。</p><p><br>2 、文本文件的读取和写入</p><p>文本文件通过调用过程Reset后以只读方式打开后，就可以使用Read或Readln过程来读取文件数据了。文本文件通过调用Write或Writeln过程来打开一文件后就可以使用或过程来写入数据。</p><p>(1) 用Read过程读取数据</p><p>通过调用Read过程可以从文本文件中读取或数字。其声明如下：<br>Procedure Read([var F:text;]v1 [,v2,…,vn,]);</p><p>其
中F是一个文件变量，v1 ,v2,…,vn用于存储读取的数据，其必须为相同的类型。当v1
,v2,…,vn定义为字符串型或字符型变量时，则Read过程将按照定义的长度读取字符。当v1
,v2,…,vn定义为整数或实数变量时，则Read过程将以空格作为分隔符，如果在数字中出现逗号、分号或其他字符将产生异常。</p><p>(2) 用Readln过程读取数据</p><p>通过调用Readln 过程可以从文本文件中读取字符串、字符或数字，直到一行结束。其声明如下：<br>Procedure readln([var F:text;]v1 [,v2 ,…]);</p><p>其中F是一个文件变量，v1 ,v2,…,vn用于存储读取的数据</p><p>(3) 用Write过程写入数据</p><p>通过调用Write过程可以向文件中写入数据。其声明如下：<br>Procedure Write([var F:text;]p1[,p2,…]);</p><p>其中F是一个文件变量，p1 ,p2,…,pn用于存储写入的数据</p><p><br>(4) Writeln用过程写入数据</p><p>通过调用Writeln过程可以向文件中写入一行数据，并在结尾处输入回车符。声明如下：<br>Procedure Writeln([var F:text;]P1[,P2,…]):</p><p><br>3、 文件的基本操作</p><p>对文本文件进行操作的基本函数与过程见表：</p><p>方法&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明<br>Procedure AssignPrn(var F:text);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 建立文本文件同打印机的联系&nbsp;<br>Function Eoln(var F:text):Boolean;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;检测文件指针是否指向行尾&nbsp;<br>Procedure Flush(var F:text); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 清空以输出方式（ReWite或Append）打开的文件缓冲区，以确保写入的文件字符都被写入外部文件&nbsp;<br>Function SeekEof(var F:text): boolean;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回文件尾状态&nbsp;<br>Function SeekEoln(var F:text):boolean;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回文件行尾状态&nbsp;<br>Procedure SetTextBuf(var F :text;var buf [;size:integer]);&nbsp; &nbsp;设置文件缓冲区</p><br><img src ="http://www.cppblog.com/Khan/aggbug/2647.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2004-11-08 21:27 <a href="http://www.cppblog.com/Khan/archive/2004/11/08/2647.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>