ZZ Windows 控制台編程

來源:互聯網
上載者:User

ZZ From: http://blog.csdn.net/tomcui/archive/2008/01/22/2058502.aspx

 

Windows 控制台編程

說明:本文章為本人在做項目時查閱相關文章而寫成,如有不當之處,請指出。

mail: tomcui60000520@163.com

關鍵字:

控制台,控制台應用程式,

 

一、             什麼是控制台

開啟Windows的控制台會看到類似的映像

 

圖一

雙擊其中的一個表徵圖,會顯示對話方塊,讓使用者來完成相應的軟硬體設定工作。這就是我們看到的控制台。那麼如何開發控制台程式呢?帶著疑問在MSDN和google裡搜尋索引鍵“Control Panel”,就會找到相關的技術文章。這是我工作的方法:借鑒已有的資源。但實際情況是那樣嗎?我們可以跟著MSDN的講述來一步一步深入下去。

經過挖掘,發現並不是exe檔案(Windows Vista下支援exe的控制台應用程式,並且微軟建議做成exe檔案),而是有著cpl尾碼名的檔案,在windows->system32下可以找到這樣的檔案。如果藉助工具,Dependency Walker for Win32 (x86) 或dumpbin等就可以看到該檔案匯出了一些函數。

 

 

圖二

多觀察幾個這樣的檔案,發現匯出的函數雖有差異,但其中都有CPLApplet函數被匯出。這些特徵與DLL的特徵吻合。去MSDN上查閱CPLApplet函數的說明證明我們的猜測是正確的。可以說控制台應該程式就是以CPL為尾碼名並且一定要匯出CPLApplet函數的dll檔案。

對於具體的描述可以參考:

http://msdn2.microsoft.com/en-us/library/bb776838(VS.85).aspx

二、             明確幾個概念

l  控制台管理程式:用於管理控制台的程式,在案頭windows版本是CONTROL.EXE,在windows CE版本是CTLPNL.EXE,它們負責管理控制台裡的控制台條目。簡單的說,我們開啟控制台時,這些管理程式就在運行了。只不過我們看到的是掛上了Shell外觀而已(註:這是我的猜測,還沒有找到依據)。

l  控制台條目(Control Panel Item):在控制台裡看到的每個表徵圖所對應的就是一個控制台條目。

l  控制台應用程式(Control Panel Application):就是最終看到的CPL檔案,一個控制台應用程式可以實現幾個控制台條目。

 

三、             控制台應用程式的編寫

編寫控制台應用程式,就是編寫dll檔案,在該檔案中實現控制所需要的功能。這就涉及到一個不得不說的函數,沒有它就無法完成控制台程式的實現。該函數為CPLApplet。下面就該函數的參數等知識做些介紹。

函數:LONG CPLApplet(HWND hwndCPl,UINT msg, LPARAM lParam1, LPARAM lParam2)

函數CPLApplet是控制台應用程式(Control Panel application)的進入點,它被控制台管理程式(control.exe 或Ctlpnl.exe)自動調用,它是個回呼函數(Callback),注意:CPL檔案一定要把函數CPLApplet匯出,這樣控制台才能找到程式的進入點。

當啟動控制台時,它會搜尋Windows或System32或註冊表的相應條目目錄下的檔案,並把以CPL作為副檔名的檔案載入,它調用CPL檔案的匯出函數CPLApplet(),發送訊息給該函數。所以,控制台應用程式要處理控制台發送過來的訊息,即在函數CPLApplet中進行處理,該函數沒有預設的行為。如果一個CPL檔案中實現了多個控制台程式,那麼只會有一個CPLApplet函數,它負責所有的控制台應用程式。

參數說明:

hwndCPl:控制台管理程式或稱為控制台的視窗控制代碼,即為control.exe的視窗控制代碼。如果控制台應用程式或其它視窗需要傳遞父視窗控制代碼,可以使用該參數。

Msg:發送到控制台應用程式的訊息,由控制台管理程式發送。

lParam1:訊息參數

lParam2:訊息參數

函數的傳回值依據訊息的不同而不同。

應用程式要使用該函數需要包含標頭檔:cpl.h

 

 

訊息名稱
 描述
 
CPL_INIT
  控制台應用程式收到的第一個訊息,通常在此處理全域初始化和記憶體配置。成功返回非0,否則返回0,此時控制台管理程式終止和該應用程式的通訊,並釋放相應的CPL檔案。
 
CPL_GETCOUNT
 該訊息緊接在CPL_INIT訊息之後被發送,它返回控制台管理程式所能看到該CPL檔案中所包含的控制台組件的數目,即該CPL檔案可以出現在控制台中的表徵圖的數目。
 
CPL_INQUIRE
 於CPL_GETCOUNT之後被發送,為指定的控制台條目提供資訊。
 
CPL_NEWINQUIRE
 於CPL_GETCOUNT之後被發送,與訊息CPL_INQUIRE完成的功能類似,只不過其實現要求TNewCPLInfo結構指標,所包含的資源不提供緩衝,所以控制台啟動的較慢,一般不建議處理該訊息,除非特別必要,如要根據一定的條件動態改變控制台條目的表徵圖、字串等。
 
CPL_DBLCLK
 表明使用者選定了一個控制台條目,程式應該顯示相應的對話方塊以便使用者完成相應的任務。成功返回0,否則,返回非0.
 
CPL_STOP
 控制台管理程式關閉時被發送,控制台應用程式在此時處理記憶體釋放等動作。成功處理,返回0.
 
CPL_SELECT
 目前不被使用。只有Windows 95 和Microsoft Windows NT 4.0之前的系統使用。
 
CPL_STARTWPARMS
 該訊息與CPL_DBLCLK類似,但lParam2指向LPCTSTR,該訊息在shell32.dll version 5.0 (Windows 2000 ,Windows Millennium Edition (Windows Me))及以後版本有效
 
CPL_EXIT
 於CPL_STOP訊息之後被發送,這是控制台應用程式在釋放資源的最後機會。成功處理返回0.
 

 

CPL_INQUIRE:lParam1是以0為起點的整數,它是該CPL檔案中所包含的控制台條目的索引,lParam2參數要求一個CPLINFO結構的指標,用來填充所需的表徵圖、字串等資訊。如果成功處理了該訊息,應該返回0。

CPL_NEWINQUIRE:該訊息與CPL_INQUIRE都是CPL_GETCOUNT之後被發送的訊息,但並沒有明確的先後順序。所以程式裡不要依賴它們的順序來處理不同的事務。

編寫控制台應用程式的步驟:

1 選擇適當的開發工具(如:Visual Studio 2008),建立DLL項目;

2 匯出函數CPLApplet;

3 在函數CPLApplet的訊息處理過程中完成你需要的工作;

一個簡單的例子

開發工具:Microsoft Visual Studio 2008

作業系統:Windows XP SP2

步驟:

1 建立Win32 Project,工程名為CPLTest;

 

2 應用程式類型選擇DLL(CPL檔案本質上是DLL);

 

 

3 在項目中新增或匯入一個表徵圖檔案和兩個字串資源,用於在控制台管理程式中顯示表徵圖和提示;

在Resource Files 上右鍵選擇Add->Resource,然後選擇Icon或String Table

以下為resource.h 的部分內容

#define IDI_ICON1                       101 //表徵圖標識

#define IDS_STRING102                   102 //字串tom

#define IDS_STRING103                   103//字串cui

4 在dllmain.cpp檔案中增加函數的匯出CPLApplet;

extern "C" __declspec(dllexport) LONG  APIENTRY CPlApplet(HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2);

原則上可以按照上面的方式匯出就可以了,但是請注意CPlApplet的調用方式是APIENTRY,通過這樣方式匯出的函數會被改名,通過多次實驗也不可行。你可能會上去掉APIENTRY,但這樣編出來的CPL檔案無法運行,查閱了相關文檔,在Windows Mobile Version 5.0 SDK的文檔裡指明了該函數的調用方式,windows CE 5.0 和Windows Shell and Controls沒有指明這種調用方式。所以,只有加上APIENTRY。

現在的問題是如何匯出該函數?看來要通過DEF檔案了,如果你的項目裡沒有產生DEF檔案,可以通過Project->Properties->Linker->Module Definition File來指定或自己用記事本建立這樣的檔案,輸入如下內容。

; CPLTest.def : Declares the module parameters for the DLL.

 

LIBRARY      "CPLTest"

 

EXPORTS

    ; Explicit exports can go here

CPlApplet

5 在dllmain.cpp檔案中增加函數CPLApplet的訊息處理函數來完成指定的功能;

在dllmain.cpp中包含以上兩個標頭檔

#include "resource.h" //資源標識

#include <Cpl.h> //CPLApplet函數要求的標頭檔

我的例子完成顯示一個MessageBox的功能。

dllmain.cpp的完整代碼:

// dllmain.cpp : Defines the entry point for the DLL application.

#include "stdafx.h"

#include "resource.h"

#include <Cpl.h>

 

LONG  APIENTRY CPlApplet(HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2);

 

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                                    )

{

       switch (ul_reason_for_call)

       {

       case DLL_PROCESS_ATTACH:

       case DLL_THREAD_ATTACH:

       case DLL_THREAD_DETACH:

       case DLL_PROCESS_DETACH:

              break;

       }

       return TRUE;

}

 

LONG APIENTRY  CPlApplet(HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2)

{

       int i;

       LPCPLINFO lpCPlInfo;

 

       i = (int) lParam1;

 

       switch (uMsg) {

       case CPL_INIT: // first message, sent once

              return TRUE;

 

       case CPL_GETCOUNT: // second message, sent once

              return 1;

              break;

 

       case CPL_INQUIRE: // third message, sent once per application

              lpCPlInfo = (LPCPLINFO) lParam2;

              lpCPlInfo->lData = 0;

              lpCPlInfo->idIcon = IDI_ICON1;

              lpCPlInfo->idName = IDS_STRING102;

              lpCPlInfo->idInfo = IDS_STRING103;

              break;

 

       case CPL_DBLCLK: // application icon double-clicked

              MessageBox(NULL, TEXT("Tom66"), TEXT("Cuei666"), MB_OK);

              break;

 

       case CPL_STOP: // sent once per application before CPL_EXIT

              break;

 

       case CPL_EXIT: // sent once before FreeLibrary is called

              break;

 

       default:

              break;

 

       }

       return 0;

}

 

6 編譯

Project->Properties->Linker->Output File修改輸出檔案的尾碼名為CPL,也可以不修改,到最後把dll改為cpl也可以的。

 

四、       控制台應用程式的安裝與運行

l  將cpl檔案拷貝到Windows(Windows CE)或Windows/system32(案頭版本Windows),可以在這裡雙擊運行,也可以開啟控制台就可以看到該CPL檔案所包含的控制台條目,表徵圖和檔案就是你在CPLApplet裡指定的,雙擊也可運行。

2 在命令列下運行rundll32 shell32.dll,Control_RunDLL CPLTest.cpl(CPL檔案名稱)@1(數字指定運行第幾個控制台條目,一個CPL檔案可以包含幾個控制台條目)。在windows CE下,在命令列輸入ctlpnl.exe /windows/cplmain.cpl,5,與案頭版本有些差異。

3    在windows的註冊表[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Control Panel/Cpls] 下建立字串,並指定cpl所在的完整路徑,然後就可以在控制台裡看到新增加的控制台條目。通過寫註冊表的方式,是一些應用軟體慣用的方式,安裝時可以通過InstallShield等安裝製作工具將其添加到註冊表,卸載時,刪除註冊表中相關的項。

 

4  通過拷貝的方式,直接刪除相應的CPL檔案就可以了。至於有沒有更好的方式,我還沒有發現。

 

五、參考資料:

1 http://msdn2.microsoft.com/en-us/library/aa926276.aspx

2 http://msdn2.microsoft.com/en-us/library/bb776392.aspx

Add by myself
    通過修改註冊表的方式,來安裝 控制台應用程式(Control panel application),必須在CPlApplet中響應CPL_INQUIRE訊息,並在其中載入表徵圖。(LPCPLINFO->IdIcon),否則開啟控制台時,所安裝應用程式的表徵圖無法載入,無法顯示。
    而通過拷貝檔案至System32目錄,則可以響應CPL_INQUIRE或者CPL_NEWINQUIRE,可以在其中的任意一個響應函數中load表徵圖。

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/jtujtujtu/archive/2008/12/12/3503878.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.