全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1686
推到 Plurk!
推到 Facebook!

Delphi Internet 編程(1)

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-09-26 16:09:40 IP:61.221.xxx.xxx 未訂閱
Delphi Internet 編程(1) http://klz.myrice.com/program/delphi/del099.htm 這篇文章主要講述如何使DELPHI和因特網配合工作。本文中將詳述兩個專門技術:         WININET:構建FTP,HTTP和Gopher用戶端程式         ISAPI:擴充因特網資訊服務,例如,獲得伺服器上的資訊並把它們顯示在瀏覽器上。         現今的電腦世界中,由於微軟公司的因特網戰略而掀起了一個巨大發展潮流。那些製作CGI(公共閘道介面)和第三方工具(即使是最基本的因特網工具)的日子將最終一去不復返了。對複雜的第三方工具的需求總是存在的,但現在程式師將會發現他們所需的大量的嵌入作業系統的因特網工具,簡言之,並不需要進一步的投資,你就能夠使用免費的DELPHI資源來:         *開發WEB瀏覽器*運行FTP,HTTP和Gopher,在兩個DELPHI應用軟體之間或DELPHI應用軟體和基於TCP(傳輸控制協定)的伺服器之間操作TCP         因爲DELPHI能夠輕鬆地調用Windows API,並且它支援OCX/ActiveX,因此微軟的新戰略和我們的計劃配合的恰到好處。微軟生産工具,而DELPHI程式師獲得收成!                  --------------------------------------------------------------------------------         在本篇中有些什麽?         這篇文章中包含了三個大部分和一些小部分,有三個大主題:         *尋找資料:那裏能搞到本文中提及的技術資料,而且包含了關於您所需的運行文中代碼的軟硬體的簡短說明。         *ISAPI:怎樣使用ISAPI*WININET:怎樣使用WININET         在大多數情況下,本文中的ISAPI和WININET部分是完全獨立的,您可以自由地選擇閱讀時的順序。                  --------------------------------------------------------------------------------         查找資料,硬體和軟體的要求         您需要一份Microsoft Windows NT 3.51 Server或NT 4.0 Server的拷貝,其中應附有因特網資訊服務文檔,因爲您需要甬道其中所提到的技術。這份文檔應隨NT  Server4.0附送,NT 3.51的用戶可從微軟的網址上下載。運行Windows NT,您的機器的最低配置應爲486相容,20兆以上記憶體。         您必須有另一台電腦裝有網頁瀏覽器。爲使本文中的ISAPI部分能夠順利運行,第二台機器必須能夠運行所有支援網頁瀏覽器的軟體。如果在您的機器上運行的是Windows  95或Windows NT,那麽本文中的WININET代碼片就能運行的最好。任何符合條件的網頁瀏覽器在這種技術環境下都能夠使用。         在1996年六月以後發佈的Delphi2.0以上的版本中,有您所需的把Delphi連接到因特網上的幾乎全部資源。         如果您沒有最新的Delphi版本[注:此處作者指的是2.0版本(譯者)],那麽您需要本文檔中提到的特殊文件,所有這些幾乎都可以從萬維網上免費獲得[注:如果您正在使用Delphi2.0以上版本,則不許考慮(譯者)]。所有本文中提到的技術在Delphi2.0環境下都能順利工作,但在16位Delphi環境下則不一定能順利工作。                  如果您需要從萬維網上下載資訊,鏈結爲:http://www.borland.com/TechInfo/delphi/index.html[注:現在已經不存在了!:-(((譯者)]                  Delphi2.0的新版本中附有WININET.PAS文檔,如果你的拷貝中不包含它,那麽上面那個萬維網節點可以爲您提供。WININET.PAS包括爲擴展微軟視窗因特網所設計的變數清單、函數、類型和屬性。這意味著您能夠輕而易舉地爲您的應用程式增添FTP、HTTP和Gopher支援。微軟公司的WININET.DLL是免費發佈的,如果它不在您的Windows/System或Windows/System32目錄下的話,您可以從微軟公司那裏得到它。下面是可獲得WININET.H這個視窗幫助文件的萬維網節點:         http://www.microsoft.com/intdev/sdk/docs/wininet/default.htm[注:好象也沒了!:-((譯者)]         一般來說,微軟因特網開發者的網上之家是微軟節點的INTDEV部分。         除了WININET和ICP之外,另一個爲Delphi支援的關鍵技術就是ISAP。正如微軟公司文檔中所描述的,這項技術能使您“‘寫入’伺服器端的原本和過濾本,從而擴充微軟因特網資訊服務和其他ISAPI萬維網服務”。         如果您需要找到關於ISAPI的描述,可以去:         http://www.microsoft.com/intdev/sdk/servapi.htm[注:上帝保佑您!;-)(譯者)]         在本文最後,附加了一個名爲HTTPEXT.PAS的關鍵的ISAPI文檔的拷貝。         微軟公司免費發佈的因特網控制包(ICP)是一個OCX/ActiveX控制集,您可以在Delphi中把它們拖放到應用程式上(Delphi2.0中包含這些控制項)。他們提供了創建Delphi應用程式的即時支援,他們知道如何瀏覽網頁、如何應用FTP、WINSOCK和其他因特網技術。如果您的Delphi拷貝中沒有包含這些控制項,那麽您在使用它們之前您應該把這些文檔添加進Delphi所在的目錄中的Lib目錄下。這些文檔位於上面提及的鏈結中的Borland的INDEX.HTML站點下。在本文中我沒有提到ICP控制項,但是任何對這項技術有興趣的人應該明確確認他擁有這些控制項的拷貝。         您可以從我的站點下載我的Pascal應用文件,他們的名字是STRBOX.PAS和MATHBOX.PAS。         經常察看一下這個站點上的關於本文提到的資訊的更新情況是很有好處的。         在這裏我假設讀者對於Delphi和Object Pascal都很熟悉,並且讀者對於因特網,HTML,瀏覽器和萬維網伺服器有基本的瞭解。                  ISAPI         ISAPI是一項很容易使用然而功能強大的技術,它能夠讓您擴充因特網資訊服務的功能。這項技術隨WindowsNT4.0附送,讓您在您的伺服器上建立WEB、FTP和GOPHER站點。同時這項技術與WindowsNT3.51  Server[注:指伺服器版本,另一個版本是工作站版本(譯者)]相容。         在過去,擴充網頁伺服器的最佳辦法是建立CGI應用程式。它們是強有力的工具,但是也被他們的執行格式所限制[注:如PERL是解釋執行的(譯者)]。當您從瀏覽其上發出一個基於CGI的請求到伺服器上時,這個CGI應用程式將極有可能先被強制裝入記憶體中,這會消耗很多時間。而且,在某些環境下,CGI技術顯得稍微難用了一點。         ISAPI是一種通過寫入DLLs[注:動態鏈結程式(譯者)]從而替代CGI應用的方法。您也可以通過ISAPI來寫過濾文本,但這項技術我不會在本篇中提及。同CGI相比,ISAPI更容易使用,而且它更快,同時能更好地利用系統資源。在下面幾點中,我將詳細地介紹爲什麽ISAPI  DLLs比CGI應用要更爲出色:         ISAPI DLLs與HTTP服務位於相同的位址,因此他們能夠從伺服器上直接存取HTTP服務。與CGI應用相比,它們能更快地裝入記憶體;當他們在伺服器上發出請求時,所需的停懸的時間[注:指發出請求到接受伺服器應答的時間(譯者)]要少的多。這點當伺服器的負荷很重時更加重要。         您可以控制DLLs何時被裝載和卸載。例如:您可以在第一次嘗試請求時預先裝載DLLs;當它們不被使用時卸載這個ISAPI應用DLLs以便釋放系統資源。         正如前文所述,您可以利用ISAPI寫過濾文本[注:一般指C/S結構中的腳本(譯者)],更具微軟的文檔,您可以通過ISAPI過濾文本做下面這些事情:         用戶授權方案壓縮加密登入通信分析或其他請求分析(例如,尋找"....etcpassword"中的請求)                  在本文中,我會著重介紹如何編寫返回資料集的DLLs,或者是如何與運行瀏覽器的用戶進行簡單的聯繫。                  ISAPI基礎         HTTPEXT.PAS文件包含了使用ISAPI的關鍵聲明。這個文件應隨1996年6月以後發表的Delphi版本分發。它也可以在Borland的站點上找到,在本文的ISAPI部分附有這份文檔。因爲這是基於NT的技術,您必須使用Delphi2.0以上的版本來應用這項技術。您不可能在16位的編輯器上應用它。         HTTPEXT.PAS包含了微軟公司創立的ISAPI技術的介面[注:指Delphi介面,ISAPI由C++編寫(譯者)]。在編寫Delphi的時候並沒有提供ISAPI的用戶介面,我會僅僅就如何使用微軟公司的現有技術進行描述。不過,ISAPI太容易使用了,而且對大多數用戶來說,用戶的Delphi物件的版本並不是必須的。         有三個函數可作爲ISAPI DLLs的入口,前兩個是必須的,第三個時可選的。         GetExtensionVersion:進對最低版本做檢查         HttpExtensionProc:這是DLL的入口,就像是Delphi應用程式中的begin...end塊         TerminateExtension:這是個可選的程式,它可以用作清除其他記憶體分配的線程。         當您在創建ISAPI DLL的時候,您必須引用上面列出的三個函數中的頭兩個函數,執行這兩個函數是所有ISAPI編程的關鍵。         這三個語句都包含了“字輸出”,使用這項術語是因爲ISAPI DLLs擴充了因特網資訊伺服器。(記住,因特網資訊伺服器指的是微軟伺服器。如果您要把一台NT伺服器作爲體格網頁伺服器的話,那麽,這正是您所需的工具。ISAPI  DLLs隨NT4.0分發,在安裝作業系統是自動安裝。)                  ISAPI提供了一個製作伺服器可遵循的標準。例如,它可以把網景公司的複雜的NSAPI介面壓縮至相關的簡練而優美的ISAPI來對NSAPI介面進行操作。         下面是這兩個重要函數的聲明         function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL; stdcall;function  HttpExtensionProc(var ECB: TExtensionControlBlock): DWORD; stdcall;         您只要把GetExtensionVersion粘貼到您的DLLs救行了.當ISAPI向公衆發佈新版本時您只需要做輕微的改動。         function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL;  stdcall;beginVer.dwExtensionVersion := $00010000; // 1.0 supportVer.lpszExtensionDesc :=  'Delphi 2.0 ISAPI DLL'; // DescriptionResult := True;end;         The parameter passed to this function is declared in HTTPEXT.PAS as follows:有關的參數在HTTPEXT.PAS中聲明如下:         PHSE_VERSION_INFO = ^THSE_VERSION_INFO;THSE_VERSION_INFO = packed  recorddwExtensionVersion: DWORD;lpszExtensionDesc: array[0..HseMaxExtDLLNameLen-1]of  Char;end;         常量HseMaxExtDllNameLen在聲明中的值爲256。紀錄中的這兩個變數是“自聲明”的,前一個包含了ISAPI的版本號[注:即變數dwExtensionVersion(譯者)],後一個則表示用戶定義的一個用來描述DLLs的字串。         在您引用GetExtensionVersion語句的同時,您必須在您的DLL程式的DPR文件部分增添輸出部分。在您寫這段語句時您還應該寫下:         exportsGetExtensionVersion,HttpExtensionProc;         這就是您在建立這兩個重要ISAPI DLL的函數時所要做的。下一步,使用HttpExtensionProc,稍微複雜一點,因此我將把它作爲一個獨立的部分。                  與HttpExtensionProc一起工作         HttpExtensionProc語句是DLL的入口。它的作用就好比C語言中的main()語句,或者Delphi中的begin...end部分         這裏有一個簡單的使用GetExtensionVersion語句的例子         function HttpExtensionProc(var ECB: TExtensionControlBlock):DWORD;  stdcall;varResStr: string;StrLen: Integer;beginECB.lpszLogData := 'Delphi DLL  Log';ECB.dwHTTPStatusCode := 200;ResStr := '<HTML><TITLE>Test server result</TITLE>' +'

Test server results

' +'<BODY>Hello from ISAPI
</BODY>' +'</HTML>'; ResStr := Format('HTTP/1.0 200 OK'#13#10+'Content-Type: text/html'#13#10+'Content-Length: %d'#13#10+'Content:'#13#10#13#10'%s',[Length(ResStr), ResStr]); StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; 如果您在瀏覽其中向這個DLL發出請求,那麽您會得到一頁這樣的回應: Test Server Results Hello from ISAPI 函數體內的大部分域提供基本資訊的簡單的HTML代碼密切相關。您還需要填寫TExtensionControlBlock中的一些域,如下所示。 注意到在這個紀錄裏有一個叫做WriteClient的函數指標,您可以引用這個函數把資訊傳送回瀏覽器。當呼叫這個函數時,您使用到了下面提到的TExtensionControl塊中的ConnID欄位。當函數被呼叫時,ConnID爲您自動填充。 在察看函數的代碼之前,請讓我爲您演示所有用到的上文提及的HttpExtensionProc函數的ISAPI DLL的完整程式 library Isapi1; library Isapi1; usesWindows, SysUtils, HTTPExt; function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall;beginVer.dwExtensionVersion := $00010000; // We're expecting version 1.0 supportVer.lpszExtensionDesc := 'Written in Delphi 2.0';Result := True;end; function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ): DWORD; stdcall;varResStr: string;StrLen: Integer;beginECB.lpszLogData := 'Delphi DLL Log';ECB.dwHTTPStatusCode := 200;ResStr := '' +'Test server results' +'Isapi says hello to DevRel ';ResStr := Format('HTTP/1.0 200 OK'#13#10+'Content-Type: text/html'#13#10+'Content-Length: %d'#13#10+'Content:'#13#10#13#10'%s',[Length(ResStr), ResStr]);StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; exportsGetExtensionVersion,HttpExtensionProc; beginend. 爲了運行這個DLL程式,您應該把它複製到您的NT伺服器下的腳本目錄中去。在我的NT4.0機器中,它就像這樣: c:winntsystem32inetsrvscriptsmystuffisapi1.dll 在這個例子中,我已經創建了我的名爲“mystuff”的目錄,它只不過是用來存儲我創建的ISAPI DLLs。您的目錄,當然和我的機器上的不完全一樣,取決於您的“inetsrv”目錄位置和其他因素。 爲成功調用這個DLL,您應該在您的HTML頁上增添這個超鏈結: ISAPI One
當用戶點擊這個超鏈結時,ISAPI1 Dll會被呼叫,然後字串“Hello from ISAPI”會顯示在用戶的瀏覽器上。如果您並不是把ISAPI.DLL放在mystuff目錄下,那麽您應該修改上面的HTML代碼來使之與您的情況適應。注意,您的目錄必須與目錄inetsrv有關,不應,也不能包含您的整個DLL所在的目錄。 下面是呼叫的完整的HTML腳本: <HTML><HEAD><TITLE>CharlieC Home Page</TITLE></HEAD><BODY><H1>My Home Page This is the home page for my home computer.ISAPI One
</BODY></HTML> 注意,如果您多次把程式ISAPI1.DLL複製到mystuff目錄下,在每一次複製之前您應該關掉網路服務器的萬維網埠。這是因爲,在第一次複製這個DLL時,您可以不受限制,但在此之後,它就屬於伺服器了。因此,在您複製第一次拷貝的更新版本時,因當關掉萬維網服務。您可以使用網路管理程式來關掉萬維網服務。這個程式應該在微軟網路管理程式組(Microsoft Internet Server group)下面,在安裝網路資訊服務時被安裝到程式管理器(Explorer/Program Manager)下。 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Delphi Internet 編程(2) 與TExtensionControlBlock一起工作 通過本文中的這一要點,您能夠建立您的第一個ISAPI DLL,並且能在第二台機器上的網頁瀏覽器調用它。 在本文中接下來的ISAPI的其餘部分將會更加深入。 這裏是HttpExtensionProc參數中比較複雜的部分 PExtensionControlBlock = ^TExtensionControlBlock;TExtensionControlBlock = packed recordcbSize: DWORD; // = sizeof(TExtensionControlBlock)dwVersion: DWORD; // version info of this specConnID: HCONN; // Context Do not modify!dwHttpStatusCode: DWORD; // HTTP Status code// null terminated log info specific to this Extension DLLlpszLogData: array[0..HSE_LOG_BUFFER_LEN-1]of Char;lpszMethod: PChar; // REQUEST_METHODlpszQueryString: PChar; // QUERY_STRINGlpszPathInfo: PChar; // PATH_INFOlpszPathTranslated: PChar; // PATH_TRANSLATEDcbTotalBytes: DWORD; // Total bytes from clientcbAvailable: DWORD; // Available number of byteslpbData: Pointer; // pointer to cbAvailable byteslpszContentType: PChar; // Content type of client data GetServerVariable: TGetServerVariableProc;WriteClient: TWriteClientProc;ReadClient: TReadClientProc;ServerSupportFunction: TServerSupportFunctionProc;end; 注意到這個紀錄中包含了上面提到過的ConnID欄位,並且向WriteClient傳送第一個參數。 這個紀錄中的第一個參數是爲版本控制而設的。它應該是TExtensionControlBlock的大小的規定。如果微軟公司改變了它的結構,那麽它們能夠通過檢查紀錄的大小來判斷它們正在處理的結構版本。您永遠也不要這個紀錄中的前三個欄位,它們早已被ISAPI填充,在您的程式中,它們只能被訪問,而不能被改變。 這個紀錄中最重要的欄位可能就是lpszQueryString了,它包含了從伺服器上傳來的請求的資訊。例如,假設您已經創建了一個名叫ISAPI1.Dll。爲了調用這個DLL,您就要在您的瀏覽器的一頁上創建一個像這樣的HREF[注:HTML語言中的一種格式(譯者)]: Test One 如果您希望回應這個DLL,您就要對上面那行做這樣的改動: Test One 假如HTML代碼段中有像上面兩行中的第二行,那麽,您的DLL就會在lpszQueryString參數中得到“MyQuery”的字串,特別要注意跟在請求字串後的請求標誌的使用。 當然,您可以隨心所欲地改變請求字串。例如,您可以這樣寫: Test One 在這個請求中,這個DLL會回答伺服器的名稱。您在傳遞這個參數時,不受任何限制。您可以傳遞任何您想要的東西,而且,如何分析DLL中的資訊也由您的喜好決定。 當您從伺服器返回資訊至瀏覽器時,您使用到了這個紀錄中的“WriteClient”函數指標。在初始化這個指標時您不需做任何事;它已經自動地有網路資訊伺服器傳遞給您了。 CGI應用程式的作者會注意到傳送請求字串的語法十分熟悉。事實上,ISAPI跟隨了CGI的大多數習慣,在TExtensionControlBlock中的多數欄位可以簡單地被CGI技術借用。 在TExtensionControlBlock中的另一個關鍵字段是lpbData,它包含了從瀏覽起上傳給您的附加資訊。 例如,您有一個伴隨幾個欄位的HTML表單,這些自斷中包含的資訊就會被一個叫做“lpData”的指標傳遞。本文中的下一個主題,“從‘確認’按鈕中獲得資訊”,將會著重講述怎樣處理這種情況。 到現在爲止我已經介紹了TExtensionControlBlock中的四個關鍵字段: WriteClient:一個能夠讓您傳遞格式化的HTML資料到瀏覽器上的指標。這個函數用到了TExtensionControlBlock的ConnID欄位。 lpszQueryString:從瀏覽騎上傳來的請求。 lpbData:從瀏覽器上傳給你的人一的附加資料。通常是一個HTML表單的任意欄位的內容。我將在“確認按鈕”這部分進一步討論。 要獲得其他TExtensionControlBlock中的欄位是如何工作的感覺,最好的辦法就是親自在瀏覽其中將他們做對照。換句話說,您會希望創建一個HTML頁,使得用能夠調用用戶端的ISAPI DLL。這個ISAPI DLL的目的僅僅是在HTML中格式話TExtensionControlBlock中的每一個欄位,然後把它們傳回瀏覽器。這樣就把您的瀏覽器變成了一個有點可怕的調試器,來顯示TExtensionControlBlock中的所有欄位。 這裏有一個程式,由Borland公司的Danny Thorpe編寫,他會執行這個任務: library test1; usesWindows,SysUtils,HTTPExt; function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall;beginVer.dwExtensionVersion := $00010000; // 1.0 supportVer.lpszExtensionDesc := 'A test DLL written in Delphi 2.0';Result := True;end; function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ): DWORD; stdcall;varResStr: string;StrLen: Integer;Buf: array[0..1024]of Char;beginECB.lpszLogData := 'Delphi DLL Log';ECB.dwHTTPStatusCode := 200;ResStr := Format('<HTML><TITLE>Test server result</TITLE>' +'

Test server results

' +'Size = %d
'+'Version = %.8x
'+'ConnID = %.8x
'+'Method = %s
' +'Query = %s
' +'PathInfo = %s
'+'PathTranslated = %s
'+'TotalBytes = %d
'+'AvailableBytes = %d
'+'ContentType = %s

'+'

Some Server Variables

',[ECB.cbSize, ECB.dwVersion, ECB.ConnID, ECB.lpszMethod, ECB.lpszQueryString,ECB.lpszPathInfo, ECB.lpszPathTranslated, ECB.cbTotalBytes, ECB.cbAvailable,ECB.lpszContentType]);with ECB dobeginStrLen := Sizeof(Buf);GetServerVariable(ConnID, 'REMOTE_ADDR', @Buf, StrLen);ResStr := ResStr + 'REMOTE_ADDR = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'REMOTE_HOST', @Buf, StrLen);ResStr := ResStr + 'Remote_Host = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'REMOTE_USER', @Buf, StrLen);ResStr := ResStr + 'Remote_User = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'SERVER_NAME', @Buf, StrLen);ResStr := ResStr + 'SERVER_NAME = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'SERVER_PORT', @Buf, StrLen);ResStr := ResStr + 'SERVER_PORT = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'SERVER_PROTOCOL', @Buf, StrLen);ResStr := ResStr + 'SERVER_PROTOCOL = '+Buf+'
';StrLen := SizeOf(Buf);GetServerVariable(ConnID, 'SERVER_SOFTWARE', @Buf, StrLen);ResStr := Format('%sSERVER_SOFTWARE = %s
'+'ThreadID = %.8x
',[ResStr, Buf, GetCurrentThreadID]);end;ResStr := ResStr + '</HTML>';ResStr := Format('HTTP/1.0 200 OK'#13#10+'Content-Type: text/html'#13#10+'Content-Length: %d'#13#10+'Content:'#13#10#13#10'%s',[Length(ResStr), ResStr]);StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; exportsGetExtensionVersion,HttpExtensionProc; beginend. 爲了調用這個DLL,您應該建立一個包括下面這行的HRML腳本 Test One
從“確認”按鈕獲得資訊 通常向您發送資訊的HTML表單中都有一個確認按鈕。只要信息量小於49KB,您就可以認爲TExetensionControlBlock中的lpbData欄位是可用的。這裏顯示了您可以如何在大多數情況下獲得由這個欄位的指標發來的資訊: var S: string;begin… S := PChar(ECB.lpbData);… end; 如果從這個欄位傳來的資訊大於48KB,那麽您必須呼叫ReadClient來獲得其餘的資訊。 如果您想要確切地知道在lpbData欄位中哪些資訊是可用的,您可以使用下面兩個函數把數據傳回到您的網頁瀏覽器中: function SetUpResString: string;beginResult := '<HTML>' +'<TITLE>Test server result</TITLE>' +'

Test server results

' +'<BODY>lpbData = %s </BODY>' +'</HTML>';end; function HttpExtensionProc(var ECB: TExtensionControlBlock):DWORD; stdcall;varResStr: string;StrLen: Integer;S, S1: string;beginECB.lpszLogData := 'Delphi DLL Log';ECB.dwHTTPStatusCode := 200;ResStr := SetUpResString;S := PChar(ECB.lpbData);ResStr := Format(ResStr,[S]);StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; 假設您已經有了附有下面代碼的HTML表單: <FORM ACTION="/scripts/mystuff/isapi2.dll" METHOD="POST" ENCTYPE="application/x-www-form-urlencoded"> Enter Number to Square: <INPUT NAME="GetSquare" VALUE="" MAXLENGTH="25" SIZE=25><INPUT TYPE=SUBMIT VALUE="Submit" NAME="GetSquare"></FORM> 這段代碼會産生一個包含一個供您輸入數位的文本區和一個叫做“submit”按鈕的表單,按鈕的名字叫做“GetSquare”。如果有了這個表單,接著您可以預計上面的兩段程式會返回如下的字串,假設用戶在表單中的文本區輸入了數位23: lpbData = GetSquare=23&GetSquare=Submit 爲了理解這時究竟發生了什麽,注意一下從上面函數中摘錄HTML語句中的主體部分,這部分語句駐留在伺服器上,反映如下: '<BODY>lpbData = %s </BODY>' + 如果您研究過上面HttpExtensionProc函數中的代碼,您會發現就在這句之前,它使用了Format語句中的%s參數來代替了ECB.lpbData中的值。(如果您不清楚語句Format是怎樣工作的,請參閱有關的Delphi文檔)[注:在作者所著的Delphi2編程大全(Delphi2 Unleashed)中的第三章《字串與文字檔案》中有詳細說明(譯者)] 假設上面所示的表單中,當用戶按下“確認”按鈕時,lpbData傳遞給ISAPI DLL的值是: GetSquare=23&GetSquare=Submit 爲了讓您有清晰的概念,讓我重復一下上面兩個語句傳回給瀏覽器的資訊是下面的字串,您已經看過了: lpbData = GetSquare=23&GetSquare=Submit 觀看這個過程的最好辦法試運行下面列出的ISAPI2程式。ISAPI2和ISAPI1差不多,但他包含了上面顯示的新的HttpExtensionProc函數,並且它還包含了SetUpResString這個實用函數。 library Isapi2; usesWindows, SysUtils, HTTPExt; function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall;beginVer.dwExtensionVersion := $00010000; // 1.0 supportVer.lpszExtensionDesc := 'DLL written in Delphi 2.0';Result := True;end; function SetUpResString: string;beginResult := '<HTML>' +'<TITLE>Test server result</TITLE>' +'

Test server results

' +'<BODY>lpbData = %s </BODY>' +'</HTML>';end; function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ): DWORD; stdcall;varResStr: string;StrLen: Integer;S, S1: string;Len: Integer;beginECB.lpszLogData := 'Delphi DLL Log';ECB.dwHTTPStatusCode := 200;ResStr := SetUpResString;S := PChar(ECB.lpbData);ResStr := Format(ResStr,[S));StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; exportsGetExtensionVersion,HttpExtensionProc; beginend +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Delphi Internet 編程(3) 一旦您從表單中獲得了由lpbData變數傳來的資訊,您就能分析這些資訊或者把它們返回給用戶。比如說,您可以從上面例子中把數位23抽出來,做平方後返回用戶。通過這樣做可以使您從用戶中獲得資訊,在這裏是數位,對數位進行一些數學運算,最後把結果返回給用戶。這意味著您可以在電波中創建互動的網頁,這可是現在因特網編程中最流行的哦! 以下是一個通過網路提交數位平方給瀏覽器的完整的程式碼: library Isapi3; { This code shows how to take input from the user via a browser,parse that information, and then return an answer to the user.In particular, the user submits a number, this code squares it,and then sends the result back to user. Here is the form from the browser that submits the information for parsing: <FORM ACTION="/scripts/mystuff/isapi2.dll" METHOD="POST"ENCTYPE="application/x-www-form-urlencoded"> Enter Number to Square: <INPUT NAME="GetSquare" VALUE=""MAXLENGTH="25" SIZE=25><INPUT TYPE=SUBMIT VALUE="Submit" NAME="GetSquare"></FORM> } usesWindows, SysUtils, HTTPExt,StrBox; function GetExtensionVersion( var Ver: THSE_VERSION_INFO ):BOOL; stdcall;beginVer.dwExtensionVersion := $00010000; // version 1.0 supportVer.lpszExtensionDesc := 'ISAPI3.DLL';Result := True;end; // Parse lpbData and retrieve the number the user passed to us.function ParseData(S: string): Integer;beginS := StripLastToken(S, '&');S := StripFirstToken(S, '=');Result := StrToInt(S);end; function SetUpResString: string;beginResult := '<HTML>' +'<TITLE>Test server result</TITLE>' +'

Test server results

' +'<BODY>Answer = %d </BODY>' +'</HTML>';end; function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ):DWORD; stdcall;varResStr: string;StrLen: Integer;S, S1: string;Num: Integer;beginECB.lpszLogData := 'Delphi DLL Log';ECB.dwHTTPStatusCode := 200;ResStr := SetUpResString;S := PChar(ECB.lpbData);Num := ParseData(S);Num := Sqr(Num);ResStr := Format(ResStr,[Num]);StrLen := Length(ResStr);ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0);Result := HSE_STATUS_SUCCESS;end; exportsGetExtensionVersion,HttpExtensionProc; beginend. 這段代碼從按下確認按鈕的用戶那裏接受下面的字串,用戶要求平方後的數位: GetSquare=5&GetSquare=Submit 假設這樣輸入,這段代碼會通過因特網返回用戶下面的字串: Answer = 25 一句話,用戶輸入數位5,你返回用戶數位25。如果用戶提交數位10,那麽您返回數位100。這看起來微不足道,但在這裏重要的是因特網上發生的行爲[注:指互動網頁(譯者)] 分析用戶傳來的函數像這樣: // Parse lpbData and retrieve the number the user passed to us.function ParseData(S: string): Integer;beginS := StripLastToken(S, '&');S := StripFirstToken(S, '=');Result := StrToInt(S);end; 這兩個語句在單元中,在本文開頭提到過,也包含在我的站點上。[注:這個文件在網路上幾乎到處可見,您也可以向譯者索取(譯者)][ 在本篇文章中,關於ISAPI我只想談這麽多了。這些內容對於啓發您利用這項優越的技術並獲得樂趣來說應該是夠用的了。接下來我要談一下GetServerVariable、ReadClient這兩個語句,在這方面我只進行了極其有限的試驗。在本文中,我附加了HTTPEXT.PAS文件,因爲除了這分關鍵文檔,在其他地方您不會找到它。 GetServerVariable和ReadClient語句 正如您的CGI應用程式中的請求資訊一樣,您可以使用語句來從伺服器上獲得資訊。下面是呼叫這個語句的例子: Len := HseMaxExtDllNameLen;SetLength(S1, Len);Dec(Len);ECB.GetServerVariable(ECB.ConnID,'CONTENT_LENGTH',PChar(S1),Len); 首先,這段代碼設定了保留從伺服器上取得的資訊的緩衝區的長度。接著它呼叫伺服器並發出請求,在本例中,它要求獲得伺服器傳來的資訊的"CONTENT_LENGTH"。 微軟公司的文獻告訴我們,您可以通過GetServerVariable的第二個參數來傳遞跟著的字串: AUTH_TYPE它包含了使用授權的類型。比如,如果使用的是基本(basic)授權,那麽字串就是"basic";如果是NT challenge回應,字串就是"NTLM"。其他的授權屬尤其對應的字串。因爲不斷有新的授權類型被增添到伺服器上,列出所有可能的字串是不可行的。如果字串爲空,那麽並沒有使用任何授權。 CONTENT_LENGTH腳本預計從用戶端回收到的位元組數。 CONTENT_TYPE由請求布告的主體部分提供的資訊的內容類型。[注:小弟才疏學淺,a POST request暫譯作"請求布告",望方家指正(譯者)] PATH_INFO附加的路由資訊,由客戶機提供。它包含了跟在腳本名字之後的URL的漫遊路由。如果有的話,它在請求字串的前面。 PATH_TRANSLATED它是PATH_INFO的值,但包含了擴充到一個路徑標誌的所有虛擬路由的名字。 QUERY_STRING跟在參考這個腳本的URL中的"?"後面的資訊。 REMOTE_ADDR發出請求的客戶機或其代理商(例如,閘道或防火牆)的IP地址。 REMOTE_HOST發出請求的客戶機或其代理商(例如,閘道或防火牆)的主機名。 REMOTE_USER它包含了由客戶機提供並且由伺服器授權的用戶名。如果返回空串那麽用戶使你名的(但是經過授權)。 UNMAPPED_REMOTE_USER它是有如下特徵的用戶的名稱:該用戶向NT用戶帳目發出請求(這是他以身份出現),在此之前ISAPI應用程式過濾起映射了該用戶。 REQUEST_METHOD是HTTP請求方法。 SCRIPT_NAME執行的腳本程式名稱。 SERVER_NAME當它以自參考URLs形式出現時的主機名或IP位址。 SERVER_PORT接受請求的TCP/IP的埠。 SERVER_PORT_SECURE一個非0即1的字串。當請求由安全埠處理時,它是1;否則是0。 SERVER_PROTOCOL接受與這個請求相關的協定的資訊的名稱和版本。他通常是HTTP/1.0。 SERVER_SOFTWARE是ISAPI應用DLL程式運行時所在的網頁伺服器的名稱和版本。 ALL_HTTP先前的變數並沒有分析全部的HTTP欄位頭。這些變數從HTTP_<欄位頭名>中得出。欄位頭(由行標分離)包含了各自的字串,這些字串並不會終止。 HTTP_ACCEPT HTTP欄位頭的特例。接受的值是:欄位由逗號(,)分離。例如:如果下面的幾行是HTTP頭的一部分: 接受:*/*,q=0.1則URL(2.0新版本的特性)給出它的基礎部分。 要注意的是,上面給出的資訊片是由TExtensionControlBlock紀錄自動傳遞的。因此您不需要調用GetServerVariable。不過,如果您確有需要,特別是您要從ReadClient中獲得資訊和需要知道要讀入多少資訊時,您可以調用它。 在很多時候,您不需要調用ReadClient。但是,您瀏覽器發出的信息量大於48KB的時候,您需要調用ReadClient來獲取其餘的資訊。 《第二》-------------------------------------------------------------------------------- FTP使用WININET 現在您閱讀的是本文的第二部分,它包含了WININET的內容。正如前文提及的那樣,這個部分與第一部分完全無關。 讓我們先來對您在FTP部分使用WININET DLL時需要編寫的代碼作一個做一個概括的瞭解。這並不是一個詳盡的學習,但卻能夠讓您進門。爲了知曉這項技術,您要做的第一件事情是明白WININET.PAS中的一些函數返回的是一個叫做HINTERNET類的指標變數: varHINTERNET: Pointer; 這個指標扮演一個您正在使用的不同的因特網服務的控制碼的角色。獲得了這個控制碼之後,你應當把它作爲第一個參數傳遞給在這個進程周期[注:指FTP的整個存在時間(譯者)]中調用的其他WININET函數。 您要記住的適當您在使用它的時間內要把控制碼返回給系統,通常是通過調用WININET函數InternetCloseHandle來實現: function InternetCloseHandle(hInet: HINTERNET): BOOL; stdcall; 爲了讓一個WININET進程開始,您調用InternetOpen : function InternetOpen(lpszCallerName: PChar; dwAccessType: DWORD; lpszServerName: PChar; nServerPort: INTERNET_PORT; dwFlags: DWORD): HINTERNET; stdcall; 第一個參數時打開這個進程的應用程式的名字。您可以在這個參數中傳遞任何您所要的任意符串。微軟公司的文獻聲稱"這個名字作爲HTTP協定中的用戶代理器的名字而被使用"。這個保留的參數可以設爲0或空。 varMyHandle: HINTERNET;… beginMyHandle := InternetOpen('MyApp', 0, nil, 0, 0);end; 如果您想要關於這個函數的更多資訊,從www.microsoft.com那裏下載WININET.HLP。 打開了這這個進程之後,下一步是通過InternetConnect函數來連接到伺服器上。 function InternetConnect(hInet: HINTERNET; // Handle from InternetOpenlpszServerName: PChar; // Server: i.e., www.borland.comnServerPort: INTERNET_PORT; // Usually 0lpszUsername: PChar; // usually anonymouslpszPassword: PChar; // usually your email addressdwService: DWORD; // FTP, HTTP, or Gopher?dwFlags: DWORD; // Usually 0dwContext: DWORD): // User defined number for callbackHINTERNET; stdcall; 這裏有三個可能的可以通過dwService參數傳遞的自說明旗標,它們是互斥的: INTERNET_SERVICE_FTPINTERNET_SERVICE_GOPHERINTERNET_SERVICE_HTTP 下面是dwFlags參數的選擇: INTERNET_CONNECT_FLAG_PASSIVE 這個選項僅當您在前一個參數中傳遞了INTERNET_SERVER_FTP才有效。這時候這個參數沒有其他有效的選項。 如果這個進程成功的話會返回一個有效的指標,否則它返回空。 連接上之後 當您連接上之後,您可以調用來GetCurrentDirectory獲得當前的路徑的名字: function TMyFtp.GetCurrentDirectory: string;varLen: Integer;S: string;beginLen := 0;ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len);SetLength(S, Len);ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len);Result := S;end; 這個函數聲明如下: function FtpGetCurrentDirectory(hFtpSession: HINTERNET; // handle from InternetConnectlpszCurrentDirectory: PChar; // directory returned herevar lpdwCurrentDirectory: DWORD): // buf size of 2nd parameterBOOL; stdcall; // True on success 如果您r
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-05-06 16:31:53
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!