首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 視窗游標控制全攻略:從註冊表找瀏覽器到 WM_SETCURSOR 實戰

     編輯:關於VC++

問題一:如何找到預設瀏覽器路徑?

Windows 無單一「預設瀏覽器」註冊表鍵值。可靠做法:查詢 .htm 檔案關聯:

  1. HKEY_CLASSES_ROOT\.htm → 預設值 htmlfile
  2. HKEY_CLASSES_ROOT\htmlfile\shell\open\command → 預設值含執行檔路徑

範例值:


// IE
"\"C:\PROGRA~1\INTERN~1\iexplore.exe\" -nohome"
// Netscape
"\"C:\PROGRA~1\NETSCAPE\netscape.exe\""

解析字串取得路徑後,配合 ShellExecute 啟動即可。

問題二:如何改變視窗/控制項游標?

方法 A:視窗類別註冊時指定全域游標


WNDCLASS wc = {0};
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 或自訂 .cur 資源
RegisterClass(&wc);

MFC 預設為主視窗註冊箭頭游標。

方法 B:處理 WM_SETCURSOR 訊息(動態/控制項級控制,推薦)

訊息流向:滑鼠移入子視窗 → 子視窗 WM_SETCURSOR → 若回傳 FALSE → 父視窗 WM_SETCURSOR → 若仍 FALSE → 使用類別全域游標。

按鈕類別覆寫範例:


BOOL CMyButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT msg) {
    ::SetCursor(m_hMyCursor); // m_hMyCursor 為載入的 HCURSOR
    return TRUE;              // 停止向上傳播
}

對話框統一處理範例(不想新增按鈕類別時):


BOOL CMyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT msg) {
    if (pWnd->GetDlgCtrlID() == IDC_MY_BUTTON) {
        ::SetCursor(LoadCursor(NULL, IDC_HAND));
        return TRUE;
    }
    return CDialog::OnSetCursor(pWnd, nHitTest, msg);
}

關鍵點:必須回傳 TRUE 表示已處理,否則系統會繼續預設流程。

問題三:靜態程式庫資源 ID 衝突解決方案

靜態庫連結進 EXE 時,資源 ID 共享同一命名空間,極易衝突。四種解決策略:

策略 1:基底偏移量 + 預處理器重定義(原始碼可見)


// libres.h
#ifndef LIBBASEID
#define LIBBASEID 2000
#endif
#define IDR_FOO (LIBBASEID + 1)
#define IDR_BAR (LIBBASEID + 2)

// 主程式 .rc
#define LIBBASEID 3000   // 衝突時改這裡
#include "libres.h"
#include "libres.rc"

缺點:需重新編譯庫(若庫直接使用 IDR_FOO)。

策略 2:執行期全域變數基底(無需重編庫)


// libres.h
#ifdef RC_INVOKED
#ifndef LibBaseId
#define LibBaseId 2000
#endif
#else
extern UINT LibBaseId;
#endif
#define IDR_FOO (LibBaseId + 1)
#define IDR_BAR (LibBaseId + 2)

// 庫主模組 .cpp
UINT LibBaseId = 2000;

// 主程式啟動碼
LibBaseId = 3000; // 衝突時修改

RC_INVOKED 確保資源編譯器只看到宏定義,C++ 編譯器看到 extern 變數。

策略 3:字串資源 ID(零衝突機率,效能稍低)


#define IDR_FOO "MyApp_IDR_FOO"
#define IDR_BAR "MyApp_IDR_BAR"

適用於對話框等低頻資源;高頻資源(圖示、位圖)仍建議整數 ID。

策略 4:函數參數傳遞 ID(完全解耦)


// 庫內部
BOOL SomeLibFn(UINT nDlgID) { DialogBox(hInst, MAKEINTRESOURCE(nDlgID), ...); }

// 主程式呼叫
SomeLibFn(IDR_FOO); // 主程式定義 IDR_FOO

庫不直接引用資源 ID,主程式完全掌控編號。

總結建議

  • 游標控制:子視窗覆寫 OnSetCursor 最符合 OO 原則
  • 資源衝突:策略 2(執行期基底變數) 平衡靈活度與維護成本
  • 瀏覽器啟動:查詢 .htm 關聯 + ShellExecute 最相容
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved