a)如果有CWnd对象如何获取这个对象内部的句柄?
pWnd ->m_hWnd
pWnd ->GetSafeHwnd(); //获取当前窗口的句柄
CWnd wnd;
HWND h = wnd;
b)如果有句柄HWND如何转为CWnd?
static CWnd* CWnd::FromHandle(HWND hWnd); //根据给定的句柄(handle)获取相应的CWnd对象
c)注意:GetDlgItem内部都是靠FromHandle实现的。
d)注意:FromHandle内部是有Map禁止一个句柄被多个对象包含。
就如同一个端口只能被一个进程占用,一个句柄只能有一个对象包含。
e)注意:FromHandle的返回值只限于本函数使用,不可以保存在成员变量长期使用。
原因是不定期清理Map,参见:CWnd::DeleteTempMap
FromHandle示例:
// 假设有一个对话框类 CMyDialog,它继承自 CDialog
HWND hDlg = m_MyDialog.GetSafeHwnd();// 获取对话框句柄
CWnd* pWnd = CWnd::FromHandle(hDlg);// 通过对话框句柄获取 CWnd 对象
if (pWnd != NULL)// 验证 pWnd 是否为有效指针
{ pWnd->SetWindowText(_T("My Dialog")); // 设置对话框的标题
CRect rect;
pWnd->GetClientRect(&rect); // 获取对话框的客户区矩形
CDC* pDC = pWnd->GetDC(); // 绘制一个红色矩形框
pDC->SelectStockObject(NULL_BSH);
pDC->SelectStockObject(DC_PEN);
pDC->SetDCPenColor(RGB(255, 0, 0));
pDC->Rectangle(rect);
pWnd->ReleaseDC(pDC);
}
通过对话框对象的GetSafeHwnd()函数获取对话框句柄。然后使用FromHandle()函数将句柄转换为CWnd指针。接下来通过该指针对对话框进行各种操作,例如设置标题、获取客户区矩形并绘制矩形框等。需要注意的是,使用FromHandle()函数从句柄获取CWnd对象后,需要进行有效性检查,以确保返回的指针不为空。
class CWnd : public CCmdTarget
{
public:
HWND m_hWnd; // must be first data member
static CWnd* PASCAL FromHandle(HWND hWnd);
static CWnd* PASCAL FromHandlePermanent(HWND hWnd);
static void PASCAL DeleteTempMap();
//用于删除临时映射。当您不再需要使用文件的临时映射时,通常会调用此函数。
BOOL Attach(HWND hWndNew);
HWND Detach();
BOOL SubclassWindow(HWND hWnd);
BOOL SubclassDlgItem(UINT nID, CWnd* pParent);
HWND UnsubclassWindow();
operator HWND() const
{ return this == NULL ? NULL : m_hWnd; }
BOOL operator==(const CWnd& wnd) const
{return wnd.GetSafeHwnd() == this ->GetSafeHwnd();}
//这样写程序不安全 { return wnd.m_hWnd == m_hWnd; }
_AFXWIN_INLINE BOOL CWnd::operator!=(const CWnd& wnd) const
{return wnd.GetSafeHwnd() != GetSafeHwnd();}
HWND CWnd::GetSafeHwnd() const
{ return this == NULL ? NULL : m_hWnd; }
static AFX_DATA const CWnd wndTop; // SetWindowPos's pWndInsertAfter
static AFX_DATA const CWnd wndBottom; // SetWindowPos's pWndInsertAfter
static AFX_DATA const CWnd wndTopMost; // SetWindowPos pWndInsertAfter
static AFX_DATA const CWnd wndNoTopMost; // SetWindowPos pWndInsertAfter
BOOL SetWindowPos(const CWnd* pWndInsertAfter, int x, int y,int cx, int cy, UINT nFlags);
void MoveWindow(int x, int y, int nWidth, int nHeight,BOOL bRepaint = TRUE);
void MoveWindow(LPCRECT lpRect, BOOL bRepaint = TRUE);
// for child windows, views, panes etc 创建子窗口,后来在所有派生类中都重写了Create函数。
virtual BOOL Create(LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,CWnd* pParentWnd, UINT nID,CCreateContext* pContext = NULL);
// advanced creation (allows access to extended styles) :创建框架的
virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL);
//增强风格的子窗口
virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName,
DWORD dwStyle,const RECT& rect,CWnd* pParentWnd, UINT nID,LPVOID lpParam = NULL);
virtual BOOL DestroyWindow();
void GetWindowRect(LPRECT lpRect) const;
void GetClientRect(LPRECT lpRect) const;
void ClientToScreen(LPPOINT lpPoint) const;
void ClientToScreen(LPRECT lpRect) const;
void ScreenToClient(LPPOINT lpPoint) const;
void ScreenToClient(LPRECT lpRect) const;
int GetDlgCtrlID() const; 获取一个窗口ID
int SetDlgCtrlID(int nID); 修改窗口ID
// get and set window ID, for child windows only
CWnd* GetDlgItem(int nID) const; 获取子窗口句柄(内部用FromHandle创建一个外壳类对象)
// get immediate child with given ID
void GetDlgItem(int nID, HWND* phWnd) const; 直接返回子控件的句柄
// as above, but returns HWND
CWnd* GetDescendantWindow(int nID, BOOL bOnlyPerm = FALSE) const;
在子孙孙内获取ID对应的句柄(内部调用FromHandle创建外壳类对象)
// like GetDlgItem but recursive
UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse,
void (CALLBACK* lpfnTimer)(HWND, UINT, UINT_PTR, DWORD));
BOOL KillTimer(UINT_PTR nIDEvent);
//为什么主窗口用一个点去探测,不用面向对象?
static CWnd* PASCAL WindowFromPoint(POINT point);
CWnd* ChildWindowFromPoint(POINT point) const;//为什么子窗口要面向对象
CWnd* ChildWindowFromPoint(POINT point, UINT nFlags) const;
CWnd* GetTopWindow() const;
BOOL IsChild(const CWnd* pWnd) const; 判断一个窗口是不是它的子窗口之一
CWnd* GetParent() const;获取父窗口
CWnd* SetParent(CWnd* pWndNewParent); //设置父窗口
CWnd* GetNextWindow(UINT nFlag = GW_HWNDNEXT) const;
CWnd* GetWindow(UINT nCmd) const;
//可以获取该窗口的父亲GW_OWNER ,儿子GW_CHILD 和兄弟(GW_HWNDNEXT)
void SetWindowText(LPCTSTR lpszString);
int GetWindowText(_Out_writes_to_(nMaxCount, return + 1) LPTSTR lpszStringBuf, _In_ int nMaxCount) const;
void GetWindowText(CString& rString) const;
int GetWindowTextLength() const;
void SetFont(CFont* pFont, BOOL bRedraw = TRUE);
CFont* GetFont() const;
BOOL IsWindowEnabled() const;//禁用和激活
BOOL EnableWindow(BOOL bEnable = TRUE);
LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) const;
BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
void SendMessageToDescendants(UINT message, WPARAM wParam = 0,
LPARAM lParam = 0, BOOL bDeep = TRUE, BOOL bOnlyPerm = FALSE);
virtual CMenu* GetMenu() const; //设置和获取菜单
virtual BOOL SetMenu(CMenu* pMenu);
void DrawMenuBar();
CMenu* GetSystemMenu(BOOL bRevert) const; //系统菜单
BOOL HiliteMenuItem(CMenu* pMenu, UINT nIDHiliteItem, UINT nHilite);
BOOL IsIconic() const; 判断窗口最小化 相当于:GetStyle()&WS_MINIMIZE
BOOL IsZoomed() const; 判断窗口最大化 相当于:GetStyle()&WS_MAXIMIZE
int SetWindowRgn(HRGN hRgn, BOOL bRedraw); 不规则窗口(椭圆窗口,圆角窗口,五边形窗口)
int GetWindowRgn(HRGN hRgn) const;
void BringWindowToTop();
// the active window applies only to top-level (frame windows)
static CWnd* PASCAL GetActiveWindow(); 参见AfxGetMainWnd()
CWnd* SetActiveWindow(); //将指定的窗口置于所有其他窗口的前面,并将焦点设置在该窗口上。
// the foreground window applies only to top-level windows (frame windows)
BOOL SetForegroundWindow(); //将窗口设置为前台窗口
static CWnd* PASCAL GetForegroundWindow();
// Icon Functions
HICON SetIcon(HICON hIcon, BOOL bBigIcon);
HICON GetIcon(_In_ BOOL bBigIcon) const;
// Alert Functions
BOOL FlashWindow(BOOL bInvert);
// capture and focus apply to all windows
static CWnd* PASCAL GetCapture();
CWnd* SetCapture(); //ReleaseCaptue是API不封装为什么呢?你想想SetCursor也是API不封装?
//必须在合适的时机调用ReleaseCapture函数来释放捕获
//SetCapture函数只能捕获鼠标输入,无法捕获键盘输入
//如果需要捕获键盘输入,可以使用SetKeyboardState函数配合GetAsyncKeyState函数实现。
static CWnd* PASCAL GetFocus();
CWnd* SetFocus();
static CWnd* PASCAL GetDesktopWindow(); //调用即可返回当前桌面的窗口句柄
void CMainDlg::OnBnClickedSendmessage()
{
auto p = FindWindow(_T("Notepad"), NULL);
if (p)
p->SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}
void CMainDlg::OnBnClickedPostmessage()
{
auto p = FindWindow(_T("Notepad"), NULL);
if (p)
p->SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
void CMainDlg::OnBnClickedButton3()
{
auto p = GetDlgItem(IDOK);
auto q = p->GetOwner();
ASSERT(q == this);
//auto b = this->IsChild(p);
}
void Search(CWnd* p)
{
if (!p)
return;
auto q = p->GetWindow(GW_CHILD);
TCHAR s[256];
while (q)
{
GetClassName(q->GetSafeHwnd(), s, _countof(s));
TRACE(_T("q=%s\n"), s);
Search(q);
q = q->GetWindow(GW_HWNDNEXT);
}
}
void CMainDlg::OnBnClickedButton1()
{
auto p = FindWindow(_T("CabinetWClass"), NULL);
Search(p);
}
void CMainDlg::OnBnClickedButton2()
{
auto p = FindWindow(_T("Notepad"), NULL);
if (p)
p->BringWindowToTop();
}
/*
BringWindowToTop函数只负责将窗口置于最前端,而不会激活窗口;
而SetForegroundWindow函数不仅将窗口置于最前端,还会将其激活成为焦点窗口
*/
void CMainDlg::OnBnClickedButton4()
{
auto p = FindWindow(_T("Notepad"), NULL);
if (p)
p->SetForegroundWindow();
}
void CMainDlg::OnBnClickedButton5()
{
auto p = FindWindow(_T("Notepad"), NULL);
if (p)
p->FlashWindow(TRUE);
}
void CMainDlg::OnBnClickedButton6()
{
auto p = GetDesktopWindow();
p = p->GetWindow(GW_CHILD); //主窗口遍历和子窗口搜索
TCHAR s[256];
while (p)
{
//GetClassName(p->GetSafeHwnd(), s, _countof(s));
p->GetWindowText(s, _countof(s));
TRACE(_T("主窗口:%s\n"), s);
p = p->GetWindow(GW_HWNDNEXT);
}
}
消息分类:系统消息和用户消息:
a)类向导中第一页和第二页子窗口(反射型)消息和主窗口基础消息,全部都是系统消息。
b)系统消息的范围是:0-1024(WM_USER),用户消息(也叫自定义消息)的WM_USER到32767之间。
消息发送的用途:
a)往往是一个多线程程序的底层工作线程,向主线程的界面发送通知(包含数据)
b)子窗口向父窗口发送消息(可能携带数据)
c)一个进程向另外一个进程发送消息(可能携带数据)
d)对windows控件发送指令,SendMessage(LVM_INSERTCOLUMN,&col);
注意:自从有了消息发送的方法之后,子窗口可以不再使用指针来调用符窗口了!!
参见CEyeCtrl:甚至都不知道父窗口是哪个类!!
1.定义用户消息 消息法都会定义这个宏 或者之前用到的指针法
消息法,它连它老爸是谁都不知道 便于移植
enum {UM_LBDOWN = WM_USER+999,UM_LBUP};
2.在CLoginDlgl类使用–>类向导–>添加自定义消息
protected:
afx_msg LRESULT OnUmLbdown(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnUmLbup(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT CLoginDlg::OnUmLbdown(WPARAM wParam, LPARAM lParam)
{
auto pEdit = reinterpret_cast<CEdit*>(GetDlgItem(IDC_PASS));
pEdit->SetPasswordChar(0);
pEdit->RedrawWindow();
return 0;
}
afx_msg LRESULT CLoginDlg::OnUmLbup(WPARAM wParam, LPARAM lParam)
{
auto pEdit = reinterpret_cast<CEdit*>(GetDlgItem(IDC_PASS));
pEdit->SetPasswordChar(_T('●'));
pEdit->RedrawWindow();
return 0;
}
#pragma once
class CLoginDlg; //提前声明,假包含
class CEyeCtrl : public CWnd
{
DECLARE_DYNAMIC(CEyeCtrl)
public:
CEyeCtrl();
virtual ~CEyeCtrl();
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
};
// CEyeCtrl 消息处理程序
void CEyeCtrl::OnLButtonDown(UINT nFlags, CPoint point){
auto p = GetParent();
if (p)
p->SendMessage(UM_LBDOWN);
SetCapture(); //窗口捕捉 锁定光标
CWnd::OnLButtonDown(nFlags, point);
}
void CEyeCtrl::OnLButtonUp(UINT nFlags, CPoint point){
auto p = GetParent();
if (p)
p->SendMessage(UM_LBUP);
ReleaseCapture(); //当离开捕获就会弹起
CWnd::OnLButtonUp(nFlags, point);
}