<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 第九章 ## Windows 編程 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 end end ~~~ 窗體一創建,程序就會通過窗體本身的Handle 屬性,獲取窗體對應的窗口句柄。調用IntToStr ,把句柄數值轉換為一個字符串,然后再把它添加到窗體標題中,如圖9.1: ~~~ procedure TFormWHandle.FormCreate(Sender: TObject); begin Caption := Caption + ' ' + IntToStr (Handle); end; ~~~ 因為FormCreate 是窗體類的方法,它可直接訪問同類的其他屬性和方法。因此,在這個過程中我們能夠直接訪問窗體的Caption 屬性和Handle 屬性。 **圖 9.1: 例 WHandle 顯示窗體句柄,每次運行程序得到的句柄值不同** ![](https://box.kancloud.cn/490b6414a84f2639ecf2eaca6e38ccda_259x115.png) 如果你多此次執行該程序,通常會獲得不同的句柄值。這個值實際上是由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 declaration function 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輸出結果--當前所有主窗體,其中包括可見及隱藏的窗體** ![](https://box.kancloud.cn/eafcc413c5fb474bd12cdf950127a7b1_304x352.png) ### 最小的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提供命令行參數** ![](https://box.kancloud.cn/ce2a1830b41b26b48e35c78e324755c0_495x100.png) * * * * * ### 結束語 在這一章中,我們對Windows 編程的底層內容進行了介紹,討論了句柄和簡單的Windows 程序。對于常規的Windows 編程任務,通常只需使用Delphi 提供的可視開發工具及VCL可視控件庫。但是這超出了本書討論的范圍,因為本書討論的是Pascal 語言。 下一章介紹variant類型。對Pascal 數據類型系統來說,它是一個非常特殊的外來物,引入它是為了提供完全的OLE 支持。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看