Delphi 之 第九課 Windows編程

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   os   使用   ar   for   

  Delphi 利用Object Pascal 和可視控制項陳列庫(VCL)對底層的Windows API 進行了完美的封裝,所以很少需要使用基礎Pascal 語言來建立Windows應用程式,也無需直接調用Windows API 函數。儘管如此,如果遇到特殊情況,VCL 又不支援,Delphi程式員還得直接面對Windows編程。不過只有在極其特殊的情況下,例如:基於不尋常API 呼叫的Delphi新控制項開發, 你才需要這樣做,這裡我不想討論這方面內容,我只想讓大家看一下與作業系統互動的幾個Delphi元素以及Delphi程式員能從中獲益的Windows編程技術。

Windows 控制代碼

Delphi從Windows 引入了不少資料類型,其中控制代碼最重要。這種資料類型名為THandle,該類型在Windows 單元中定義:

type  THandle = LongWord;

控制代碼資料類型通過數字實現,但並不當數字用。在Windows 中,控制代碼是一個系統內部資料結構的引用。例如,當你操作一個視窗,或說是一個Delphi 表單時,系統會給你一個該視窗的控制代碼,系統會通知你:你正在操作142號視窗,就此,你的應用程式就能要求系統對142號視窗進行操作——移動視窗、改變視窗大小、把視窗極小化為表徵圖,等等。實際上許多Windows API 函數把控制代碼作為它的第一個參數,如GDI (圖形裝置介面)控制代碼、菜單控制代碼、執行個體控制代碼、位元影像控制代碼等等,不僅僅局限於視窗函數,。

換句話說,控制代碼是一種內部代碼,通過它能引用受系統控制的特殊元素,如視窗、位元影像、表徵圖、記憶體塊、游標、字型、菜單等等。Delphi中很少需要直接使用控制代碼,因為控制代碼藏在表單、位元影像及其他Delphi對象的內部。當你要調用Delphi不支援的Windows API 函數時,控制代碼才會有用。

現在舉一個簡單的Windows控制代碼例子,完善這節內容。例WHandle 程式的表單很簡單,只有一個按鈕。正如下面主表單文本所定義的那樣,我在代碼中添加了表單的OnCreate 事件和按鈕的OnClick 事件:

object FormWHandle: TFormWHandle  Caption = ‘Window Handle‘  OnCreate = FormCreate  object BtnCallAPI: TButton    Caption = ‘Call API‘    OnClick = BtnCallAPIClick  endend

表單一建立,程式就會通過表單本身的Handle 屬性,擷取表單對應的視窗控制代碼。調用IntToStr ,把控制代碼數值轉換為一個字串,然後再把它添加到表單標題中,9.1:

procedure TFormWHandle.FormCreate(Sender: TObject);begin  Caption := Caption + ‘ ‘ + IntToStr (Handle);end;

因為FormCreate 是表單類的方法,它可直接存取同類的其他屬性和方法。因此,在這個過程中我們能夠直接存取表單的Caption 屬性和Handle 屬性。

圖 9.1: 例 WHandle 顯示表單控制代碼,每次運行程式得到的控制代碼值不同

 

如果你多此次執行該程式,通常會獲得不同的控制代碼值。這個值實際上是由Windows 作業系統確定並返回給應用程式的。(控制代碼從來不是由程式決定的,而且控制代碼沒有預定義值,控制代碼是由系統決定的,每執行一次程式,產生一個新值。)

當你單擊按鈕,程式將調用Windows API 函數SetWindowText,它會根據第一個傳遞參數改變視窗的標題。更準確地說,所用的API 函數其第一個參數是需要修改表單的控制代碼:

procedure TFormWHandle.BtnCallAPIClick(Sender: TObject);begin  SetWindowText (Handle, ‘Hi‘);end;

這段代碼與前面所講的事件處理常式等效,它通過給表單的Caption 屬性賦一個新值,改變表單的標題。對上面這種情況,調用一個API 函數沒有什麼意義,因為用Delphi來做更簡單。然而有些API在Delphi中沒有相應的函數,就需要直接調用API,這一點你會在後面的進階例子中看到。

外部聲明

Windows 編程中涉及的另一個重要元素是外部聲明。外部聲明原先用於在Pascal代碼中串連組合語言寫的外部函數,現在外部聲明用於Windows編程,用來調用動態串連庫DLL函數。在Delphi的Windows 單元中有許多這種聲明:

// forward declarationfunction LineTo (DC: HDC; X, Y: Integer): BOOL; stdcall;// external declaration (instead of actual code)function LineTo; external ‘gdi32.dll‘ name ‘LineTo‘;

這段聲明表示函數LineTo 的代碼同名儲存在GDI32.DLL 動態連結程式庫中(最重要的Windows 系統庫之一)。實際應用時,外部聲明中的函數名與DLL中的函數名可以不同。

一般你不需要象剛才所例舉的那樣寫聲明,因為Windows 單元和一些Delphi 系統單元中已包含了這些聲明。只有在調用自訂DLL,或調用Delphi 中未定義的Windows 函數時,你才能需要寫外部聲明。

注意:在16位Delphi中,外部聲明使用不帶副檔名的庫名,後面跟name指令(如上所示)或是一個index指令,後面跟DLL中函數的序號。儘管Win32 仍然允許通過序號訪問DLL函數,但是微軟公司已經聲明未來將不支援這種訪問方式,這一改變反映了系統庫訪問方式的改變。還要注意的是:目前Delphi的Windows 單元已取代了16位Delphi的WinProcs 和WinTypes 單元。

回呼函數

從第六章已經瞭解到Objet Pascal 支援過程類型。過程類型常用於給Windows API函數傳遞迴調函數。

首先,什麼是回呼函數呢?回呼函數就是能對一系列系統內部元素執行給定操作的API函數,例如能對所有同類視窗進行操作的函數。這種函數也叫枚舉函數,它是作為參數傳遞的函數,代表對所有內部元素執行的操作,該函數或過程的類型必須與給定的過程類型相容。Windows 回呼函數的應用不止上述一種,不過這裡僅研究以上簡單應用。

現在考慮 EnumWindows API 函數,它的原型如下(從Win32 協助檔案拷貝而來):

BOOL EnumWindows(  WNDENUMPROC lpEnumFunc,  // address of callback function  LPARAM lParam // application-defined value  );

當然,這是個C語言的定義。我們可以查看Windows 單元,從中找到相應的Pascal 語言定義:

function EnumWindows (  lpEnumFunc: TFNWndEnumProc;  lParam: LPARAM): BOOL; stdcall;

查閱協助檔案,我們發現作為參數傳遞的函數應該屬於下面的類型(也是在C中):

BOOL CALLBACK EnumWindowsProc (  HWND hwnd, // handle of parent window  LPARAM lParam // application-defined value  );

這與下面的Delphi 過程類型定義一致:

type  EnumWindowsProc = function (Hwnd: THandle;    Param: Pointer): Boolean; stdcall;

其中第一個參數是各主表單的控制代碼,第二個參數則是調用EnumWindows 函數時所傳遞的值。實際上,Pascal 中沒有相應的TFNWndEnumProc類型定義 ,它只是個指標。這意味著我們需要傳遞一個帶有合適參數的函數,將它用作一個指標,也就是取函數的地址而不是調用它。不幸的是,這也意味著如果某個參數類型出現錯誤時,編譯器不會給予提示。

每當調用Windows API函數或傳遞一個回呼函數給系統時,Windows 要求程式員遵循stdcall 調用協定。預設情況下,Delphi使用另一種更高效的調用協定,其關鍵字為register。

下面是一個與定義相容的回呼函數,此函數把視窗的標題讀到字串中,然後添加到給定表單的一個列表框中:

function GetTitle (Hwnd: THandle; Param: Pointer): Boolean; stdcall;var  Text: string;begin  SetLength (Text, 100);  GetWindowText (Hwnd, PChar (Text), 100);  FormCallBack.ListBox1.Items.Add (    IntToStr (Hwnd) + ‘: ‘ + Text);  Result := True;end;

表單有一個幾乎覆蓋整個表單的列表框,表單頂部有一個小面板,面板上有一個按鈕。當按下按鈕時,EnumWindows API函數被調用,並且GetTitle 函數作為參數傳遞給它:

procedure TFormCallback.BtnTitlesClick(Sender: TObject);var  EWProc: EnumWindowsProc;begin  ListBox1.Items.Clear;  EWProc := GetTitle;  EnumWindows (@EWProc, 0);end;

你可以直接調用GetTitle函數,不必先把值儲存到過程類型臨時變數中,上例這麼做是為了使回調過程更清楚。程式運行結果確實很有意思,正如你在圖9.2中看到的那樣,結果顯示了系統中正在啟動並執行所有主視窗,其中大部分是隱藏的,你通常看不到,許多實際上沒有標題。

圖 9.2: 例CallBack輸出結果--當前所有主表單,其中包括可見及隱藏的表單

最小的Windows 程式

為了完整介紹Windows 編程及Pascal 語言,現在我展示一個簡單但完整的應用程式,建立該程式沒有使用VCL庫。這個程式只是簡單地採用命令列參數(儲存在系統全程變數cmdLine中),並利用ParamCount 和 ParamStr 這兩個Pascal 函數從參數中提取資訊。其中第一個函數返回參數的個數,第二個返回給定位置的參數。

儘管在圖形化使用者介面環境下使用者很少操縱命令列參數,但是Windows 命令列參數對系統本身卻很重要。例如,一旦你定義了副檔名和應用程式的關聯,只要雙擊所關聯的檔案就能執行這個程式。實際上,當你雙擊一個檔案,Windows 即啟動關聯程式並把選定的檔案作為命令列參數傳遞給它。

下面是工程檔案的完整原始碼(一個DPR 檔案,不是PAS 檔案):

program Strparam;uses  Windows;begin  // show the full string  MessageBox (0, cmdLine,     ‘StrParam Command Line‘, MB_OK);  // show the first parameter  if ParamCount > 0 then    MessageBox (0, PChar (ParamStr (1)),       ‘1st StrParam Parameter‘, MB_OK)  else    MessageBox (0, PChar (‘No parameters‘),       ‘1st StrParam Parameter‘, MB_OK);end.

輸出代碼使用MessageBox API 函數,很容易就避開了VCL庫。實際上,象上面那樣純粹的Windows 程式,其優點就是占的記憶體少,程式執行檔案大約才16k位元組。

為了給程式提供命令列參數,你可以用Delphi的 Run > Parameters 功能表命令。另一個方法是:開啟Windows 資源管理員,尋找包含程式執行檔案的目錄,然後把你要執行的檔案拖到可執行檔上,Windows 資源管理員會把拖放的檔案名稱用作命令列參數,開始執行程式。圖9.3顯示了資源管理員及相應的輸出。

圖9.3: 把一個檔案拖放到執行檔案上,給例StrParam提供命令列參數 

結束語

在這一章中,我們對Windows 編程的底層內容進行了介紹,討論了控制代碼和簡單的Windows 程式。對於常規的Windows 編程任務,通常只需使用Delphi 提供的可視開發工具及VCL可視控制項陳列庫。但是這超出了本書討論的範圍,因為本書討論的是Pascal 語言

Delphi 之 第九課 Windows編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.