关于windows下窗体的ID
Windows平台下每个窗体都有一个ID,窗体创建的时候被设置,主要用来标识子窗体,对不同的窗体,其子窗体的ID可以相同。但同一窗体的不同子窗体必须不同。否则
API如何运行正确:
HWND GetDlgItem( HWND hDlg, int nIDDlgItem);
nIDDlgItem: 子窗体的ID
由该API也可以看出,由窗体的ID可得到窗体的句柄,当然还需要其父窗体的句柄作为参数,所以可以进程内不唯一。
看MFC的代码(wincore.cpp),标示为红色的参数即为窗体的ID。
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */)
{
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, lpParam);
}
以上函数调用了同名的以下函数,请看
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
…
}
由此可见,窗体ID即为CREATESTRUCT.hMenu参数
如何得到窗体ID呢?
API :LONG lID=GetWindowLong(hWnd, GWL_ID);
设置:
API :SetWindowLong(hWnd, GWL_ID,dwNew);
看一下MFC是如何分配切分窗体的ID的,看代码(winsplit.cpp)
BOOL CSplitterWnd::CreateView(int row, int col,
CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext)
{
…(略)
CWnd* pWnd;
TRY
{ //new一个该类的对象,动态创建
pWnd = (CWnd*)pViewClass->CreateObject();
if (pWnd == NULL)
AfxThrowMemoryException();
}
CATCH_ALL(e)
{
TRACE0("Out of memory creating a splitter pane./n");
// Note: DELETE_EXCEPTION(e) not required
return FALSE;
}
END_CATCH_ALL
ASSERT_KINDOF(CWnd, pWnd);
ASSERT(pWnd->m_hWnd == NULL); // not yet created
DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
if (afxData.bWin4)
dwStyle &= ~WS_BORDER;
// Create with the right size (wrong position)
CRect rect(CPoint(0,0), sizeInit);
//调用该类的创建函数来创建
if (!pWnd->Create(NULL, NULL, dwStyle,
rect, this, IdFromRowCol(row, col), pContext))
{
TRACE0("Warning: couldn't create client pane for splitter./n");
// pWnd will be cleaned up by PostNcDestroy
return FALSE;
}
ASSERT((int)_AfxGetDlgCtrlID(pWnd->m_hWnd) == IdFromRowCol(row, col));
// send initial notification message
if (bSendInitialUpdate)
pWnd->SendMessage(WM_INITIALUPDATE);
return TRUE;
}
注意上函数中的IdFromRowCol
int CSplitterWnd::IdFromRowCol(int row, int col) const
{
ASSERT_VALID(this);
ASSERT(row >= 0);
ASSERT(row < m_nRows);
ASSERT(col >= 0);
ASSERT(col < m_nCols);
return AFX_IDW_PANE_FIRST + row * 16 + col;
}
至此如何分配ID很明了了,#define AFX_IDW_PANE_FIRST 0xE900,不同切分窗体(CplitterWnd)的子窗体ID可以相同。再一次证明了文章开头的结论。