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