使用VC++編寫Windows95的CPL組件
發表時間:2023-08-22 來源:明輝站整理相關軟件相關文章人氣:
[摘要]王 琰控 制 面 板 是Windows 95 的 控 制 中 心, 通 過 它 可 以 完 成 添 加 新 硬 件 設 備、 改 變 桌 面 設 置、 配 置 網 絡 協 議 等 多 項 工 作。 ...
王 琰
控 制 面 板 是Windows 95 的 控 制 中 心, 通 過 它 可 以 完 成 添 加 新 硬 件 設 備、 改 變 桌 面 設 置、 配 置 網 絡 協 議 等 多 項 工 作。 在Windows 95 中, 控 制 面 板 通 常 有20 多 個 組 件, 我 們 只 要 用 鼠 標 雙 擊 任 一 組 件 的 圖 標, 就 會 彈 出 一 個 對 話 框, 對 話 框 包 含 有 設 置 一 些 系 統 參 數 的 選 項, 這 些 參 數 的 絕 大 多 數 都 存 放 在Windows 95 的 注 冊 表 中。
---- 控 制 面 板 的 主 程 序 是CONTROL.EXE, 它 在 啟 動 時 自 動Winndows\System 目 錄 下 查 找 并 調 入 文 件 擴 展 名 為CPL 的 控 制 面 板 組 件。 控 制 面 板 組 件 是 可 以 擴 充 的, 一 些 軟 件 在 安 裝 過 程 中 會 自 動 加 入 新 的 控 制 面 板 組 件。 按 照Windows 用 戶 界 面 設 計 原 則 的 規 定, 凡 是 影 響 到 系 統 的 整 體 行 為 和 界 面 風 格 的 各 項 參 數 都 應 該 通 過 控 制 面 板 來 設 置, 因 此 掌 握 控 制 面 板 組 件 的 編 程 方 法 是 很 有 必 要 的。
控 制 面 板 組 件 的 工 作 原 理 ---- 控 制 面 板 的 各 個 組 件 都 是 一 些 特 殊 的 動 態 鏈 接 庫, 只 不 過 它 們 的 擴 展 名 不 是DLL, 而 是CPL, 即Control Panel 的 縮 寫。
---- CONTROL.EXE 啟 動 后 會 依 次 調 入 在 系 統 目 錄 下 查 找 到 的CPL 庫。 一 般 來 說, 一 個CPL 庫 只 負 責 管 理 某 一 方 面 的 設 置, 對 應 著 控 制 面 板 中 的 一 個 組 件( 即 一 個 圖 標), 但 也 有 少 數CPL 庫 支 持 多 個 組 件。
---- 每 個CPL 庫 必 須 輸 出 一 個 叫CPlApplet() 的 函 數 供CONTROL.EXE 調 用,CPlApplet() 具 有 以 下 原 型:
typedef LONG (APIENTRY *APPLET_PROC)(HWND hwndCpl, UINT msg,
LONG lParam1,LONG lParam2);
---- 容 易 看 出,CPlApplet() 與 普 通 窗 口 處 理 函 數 的 形 式 很 相 似, 事 實 上, 控 制 面 板 正 是 以 發 送 消 息 的 方 式 與CPL 庫 進 行 通 信。 參 數hwndCpl 為 控 制 面 板 的 窗 口 句 柄,msg 為 消 息 標 識,lParam1 和lParam2 為 附 加 的 兩 個 參 數, 具 體 的 意 義 視msg 的 值 而 定。
---- 控 制 面 板 用LoadLibrary() 函 數 把CPL 庫 調 入 內 存 以 后, 立 刻 向CPlApplet() 發 送 一 條CPL_INIT 消 息, 指 示CPL 庫 作 初 始 化 工 作。
---- 因 為 這 是 唯 一 允 許 返 回 失 敗 信 息 的 消 息, 所 以CPL 庫 此 時 應 該 分 配 運 行 過 程 中 需 要 的 所 有 內 存 和 資 源, 如 果 因 為 內 存 不 夠 或 者 其 它 原 因 不 能 繼 續, 就 返 回 零 值, 控 制 面 板 將 不 再 處 理 這 個CPL 庫, 并 自 動 卸 下 它。
---- 所 有CPL 庫 初 始 化 完 畢 后, 控 制 面 板 再 向 每 個CPL 庫 的CPlApplet() 函 數 發 送 一 條CPL_GETCOUNT 消 息, 此 時CPL 庫 返 回 它 所 支 持 的 組 件 數。 接 下 來, 控 制 面 板 再 針 對 每 一 個 組 件 向CPlApplet() 函 數 發 送 多 條CPL_NEWINQUIRE 消 息, 目 的 是 取 得 每 個 組 件 對 應 的 圖 標、 名 稱 和 提 示 信 息,CPL 庫 可 以 在 處 理 這 條 消 息 時 依 次 初 始 化 各 個 組 件 的 對 話 框。 在Windows 3.x 中, 控 制 面 板 發 送 的 是CPL_INQUIRE 消 息, 考 慮 到 兼 容 性 的 問 題, 這 條 消 息 在Windows 95 中 被 保 留 下 來 了, 但 是 基 于WIN 32 的CPL 庫 只 需 處 理 新 的CPL_NEWINQUIRE 消 息。
---- 進 行 到 這 一 步 后, 控 制 面 板 顯 示 出 所 有 組 件 的 圖 標, 并 開 始 接 受 用 戶 的 選 擇。 當 用 戶 雙 擊 某 個 組 件 的 圖 標 時, 控 制 面 板 向 該 組 件 所 在 的CPL 庫 發 送 一 條CPL_DBLCLK 消 息, 并 指 明 用 戶 選 擇 的 是 該CPL 庫 中 的 第 幾 個 組 件,CPL 庫 在 接 到 這 條 消 息 后 從INI 文 件 或Windows 95 的 注 冊 表 中 讀 出 要 處 理 的 系 統 參 數 的 原 始 值, 并 啟 動 相 應 的 對 話 框, 允 許 用 戶 改 變 設 置。 當 用 戶 在 修 改 過 程 中 按 下 應 用(Apply) 按 鈕 后,CPL 庫 保 存 新 的 參 數 并 返 回 到 控 制 面 板 中; 如 果 用 戶 取 消 了 所 作 修 改,CPL 庫 只 需 返 回 即 可。
---- 控 制 面 板 在 被 關 閉 時 會 對 每 個 組 件 發 送 一 條CPL_STOP 消 息, 接 著 對 每 個CPL 庫 發 送 一 條CPL_EXIT 消 息, 此 時CPL 庫 釋 放 在CPL_INIT 消 息 中 分 配 的 內 存 和 資 源。 最 后 控 制 面 板 依 次 卸 下 各 個CPL 庫 并 退 出。
---- 上 面 敘 述 的 就 是 控 制 面 板 組 件 的 工 作 原 理, 其 中 各 條 消 息 的 具 體 參 數 定 義 請 參 考WIN 32 SDK。
利 用VC++ 編 寫 控 制 面 板 組 件 ---- 編 寫 控 制 面 板 組 件 實 際 上 是 編 寫DLL, 利 用Visual C++ 這 個 強 大 的 可 視 化 編 程 工 具 可 以 很 方 便 地 完 成 這 項 工 作。MFC 基 本 類 庫 為 我 們 封 裝 了DLL 的 基 本 框 架, 我 們 只 需 編 寫 處 理 消 息 的CPlApplet() 函 數 和 各 個 組 件 的 對 話 框 即 可。 遺 憾 的 是,MFC 類 庫 中 沒 有 現 成 的 關 于 控 制 面 板 組 件 的 類, 為 了 充 分 利 用C++ 語 言 可 繼 承 性 的 優 點, 本 文 后 面 的 程 序 給 出 了 一 個 控 制 面 板 組 件 的 基 類CControlPanel, 它 的 成 員 函 數 提 供 了 處 理 各 種CPL 消 息 的 缺 省 代 碼, 我 們 只 要 從 這 個 基 類 派 生 出 新 的 子 類, 并 為 需 要 處 理 的 消 息 重 載 相 應 的 代 碼, 就 可 以 迅 速 建 立 一 個 控 制 面 板 組 件。
---- 利 用Visual C++ 中 編 寫 控 制 面 板 組 件 的 步 驟 如 下:
調 用AppWizard 建 立 一 個 新 的 項 目, 將 應 用 程 序 類 型 為 設 使 用MFC 的DLL, 并 把MFC 類 庫 作 為 靜 態 庫 連 接, 按 下Finish 按 鈕, 讓AppWizard 自 動 生 成 框 架 文 件。
把 本 文 后 面 的CtrlPan.CPP 加 入 到 項 目 中, 把CPlApplet 添 加 到DEF 文 件 的 輸 出 名 表 中, 然 后 選 擇Build 菜 單 的Settings, 修 改 輸 出 文 件 的 擴 展 名 為CPL。
從CControlPanel 中 派 生 出 新 的 子 類, 并 重 載 部 分 消 息 代 碼。 多 數 情 況 下 只 需 要 重 載 處 理CPL_NEWINQUIRE 和CPL_DBLCLK 消 息 的 函 數 就 行 了, 如 下 所 示:
#include "ctrlpan.h"
class CNewCPL : public CControlPanel
{
public:
virtual LONG OnInquire(UINT uAppNum, NEWCPLINFO* pInfo);
virtual LONG OnDblClk(HWND hwndCPl, UINT uAppNum, LONG lData);
};
---- 如 果 要 在 一 個CPL 庫 中 支 持 多 個 組 件, 那 么 至 少 還 要 重 載OnGetCount() 函 數。
編 寫 消 息 處 理 代 碼,OnInquire() 函 數 負 責 返 回 組 件 的 各 種 信 息, 可 參 考 基 類 中 該 函 數 的 實 現 代 碼,OnDblClk() 函 數 負 責 讀 取 和 保 存 各 個 參 數, 并 調 用 對 話 框 讓 用 戶 選 擇。
設 計 對 話 框, 用ClassWizard 生 成 對 話 框 的 處 理 代 碼, 并 修 改 這 些 代 碼 使 之 符 合 要 求。
源 代 碼 編 寫 完 畢 后, 編 譯 連 接, 把 生 成 的CPL 文 件 拷 則 到SYSTEM 目 錄 下, 運 行 控 制 面 板 進 行 調 試。
調 試 正 確 后, 重 新 建 立CPL 庫 的Release 版。
// CtrlPan.h: 類CControlPanel 的 聲 明
#ifndef _CTRLPAN_H_
#define _CTRLPAN_H_
#include //VC 提 供 的 頭 文 件
class CControlPanel
{
public:
CControlPanel();
virtual ~CControlPanel();
// 可 重 載 的 消 息 處 理 函 數
virtual LONG OnDblClk(HWND hwndCPl, UINT uAppNum, LONG lData);
virtual LONG OnExit();
virtual LONG OnGetCount();
virtual LONG OnInit();
virtual LONG OnInquire(UINT uAppNum, NEWCPLINFO* pInfo);
virtual LONG OnSelect(UINT uAppNum, LONG lData);
virtual LONG OnStop(UINT uAppNum, LONG lData);
virtual LONG OnExit();
// CPL 庫 的 輸 出 函 數
static LONG APIENTRY CPlApplet(HWND hwndCPl, UINT uMsg,
LONG lParam1, LONG lParam2);
static CControlPanel* m_pThis;
};
#endif // _CTRLPAN_H_
// CtrlPan.cpp, 定 義 了 類CControlPanel 的 缺 省 處 理 函 數
#include "stdafx.h"
#include "ctrlpan.h"
CControlPanel* CControlPanel::m_pThis = NULL;
CControlPanel::CControlPanel()
{ m_pThis = this; }
CControlPanel::~CControlPanel()
{ }
// CPL 庫 的 輸 出 函 數
LONG APIENTRY CControlPanel::CPlApplet(HWND hwndCPl, UINT uMsg,
LONG lParam1, LONG lParam2)
{
CControlPanel* pCtrl = m_pThis;
ASSERT(pCtrl); // 檢 查pCtrl 的 有 效 性
switch (uMsg) {
case CPL_DBLCLK:
return pCtrl->OnDblClk(hwndCPl, lParam1, lParam2);
case CPL_EXIT:
return pCtrl->OnExit();
case CPL_GETCOUNT:
return pCtrl->OnGetCount();
case CPL_INIT:
return pCtrl->OnInit();
case CPL_NEWINQUIRE:
return pCtrl->OnInquire(lParam1, (NEWCPLINFO*)lParam2);
case CPL_INQUIRE:
return 0; // 基 于WIN32 的CPL 庫 不 處 理 這 條 消 息
case CPL_SELECT:
return pCtrl->OnSelect(lParam1, lParam2);
case CPL_STOP:
return pCtrl->OnStop(lParam1, lParam2);
case CPL_EXIT:
retrun pCtrl->OnExit();
default: break;
}
return 1;
}
// 缺 省 的 消 息 處 理 函 數
LONG CControlPanel::OnDblClk(HWND hwndCPl, UINT uAppNum, LONG lData)
{ return 0; }
LONG CControlPanel::OnExit()
{ return 0; }
LONG CControlPanel::OnGetCount()
{ return 1; } // 缺 省 為 一 個 組 件
LONG CControlPanel::OnInit()
{ return 1; }
LONG CControlPanel::OnInquire(UINT uAppNum, NEWCPLINFO* pInfo)
{
// 填 充NEWCPLINFO 結 構, 結 構 的 定 義 請 參 考VC 的 聯 機 幫 助
pInfo->dwSize = sizeof(NEWCPLINFO);
pInfo->dwFlags = 0;
pInfo->dwHelpContext = 0;
pInfo->lData = 0;
pInfo->hIcon = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(1));
strcpy(pInfo->szName, "Applet");
strcpy(pInfo->szInfo, "Default Control Panel Applet");
strcpy(pInfo->szHelpFile, "");
return 0;
}
LONG CControlPanel::OnSelect(UINT uAppNum, LONG lData)
{ return 1; }
LONG CControlPanel::OnStop(UINT uAppNum, LONG lData)
{ return 1; }
LONG CControlPanel::OnExit()
{ return 1; }