btn->SetWindowTextW(_T( " hello "));
CWnd::GetDlgItem(int nID)
這個是一個類成員函數,可使用CWnd* pWnd = GetDlgItem(ID_XXX);
而HWND GetDlgItem(
HWND hDlg, // handle of dialog box
int nIDDlgItem // identifier of control
);
是一個sdk的函數
兩個的主要區別是用的地方不一樣
一個參數的是在窗口中調用的函數,兩個參數的是在平台SDK中調用的
你在對話框類里面調用GetDlgItem(IDC_BOARD_SIZE),就是調用的類成員函數CWnd::GetDlgItem
獲得某個控件的句柄GetDlgItem(IDC_BOARD_SIZE)->m_hWnd就可以了
如果要用到第二種用法,要這樣
::GetDlgItem(this-> m_hWnd,IDC_BOARD_SIZE);
效果一樣的
那個IDC_BOARD_SIZE是你某個控件的id,
如果HWND GetDlgItem(
HWND hDlg, // handle of dialog box
int nIDDlgItem // identifier of control
);的話,
第一個參數是窗體的句柄,第二個參數是某個控件的ID,和IDC_BOARD_SIZE是一個意思
GetDlgItem(IDC_..),GetDlgItem(HWND hWnd, IDC_..)該如何使用,我在使用前者時老報錯,提示應使用后者,但后者的hWnd不知如何獲取。
GetDlgItem(HWND hWnd, IDC_..)是一個靜態方法,它是一個讓你指定從哪個對話框里獲取控件指針
舉個例子:你調用了上廁所這個函數,如果你在家里的話肯定是在自己家里上廁所,所以不需要知道在哪里上廁所(hwnd)
如果你在室外那么上廁所就一定要選一個地方(hwnd)。
如果說你上廁所的地方都不是一個房間,那么肯定會報錯嘛,因為你在隨地大小便,哈哈
所以你先搞清楚這兩個函數的使用環境區別
再者,你問這個問題說明了你還沒有搞清楚對話框是一個什么東西,建議學習一下深入淺出MFC
------------------------------------------------------------------------------------------
BOOL EnableWindow(
HWND hWnd,
BOOL bEnable
);
函數功能:
參數:
hWnd:被禁止/允許的窗口的句柄。
bEnable:定義窗口是被允許,還是被禁止。若該參數為TRUE,則窗口被允許。若該參數為FALSE,則窗口被禁止。
如果窗口原來是禁止態,返回值不為零;如果窗口原來是允許態,返回值為零。若想獲得更多的錯誤信息,可調用GetLastError函數。
備注:
速查:
Windows NT:3.1及以上版本;
Windows:95及以上版本;
Windows CE:1.0及以上版本;
頭文件:Winuser.h;
庫文件:user32.lib。
用法:EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),TRUE);
我們在調用CWnd::GetDlgItem()函數時,MSDN告訴我們:The returned pointer may be temporary and should not be stored for later use.
中文意思就是:返回的指針可能是臨時的並且最好不要保存起來放到以后用。
猜測:返回的指針既然可能是臨時的,那么可能是非臨時的(永久的),最好不要保存起來放到以后用(有時候可以保存起來)
源碼面前,了無秘密。讓我們深入MFC源代碼去看個究竟。
先隨便建立一個Dialog程序,然后在窗體上拉一個按鈕,添加按鈕事件,在按鈕事件里寫上如下代碼:GetDlgItem(IDC_BUTTON1); 然后給這行代碼加上斷點。好,我們開始進去看看,運行程序,按下按鈕,程序就停在剛才的斷點出,然后F11進去。
CWnd* CWnd::GetDlgItem(int nID) const
{
ASSERT(::IsWindow(m_hWnd));
if (m_pCtrlCont == NULL)
return CWnd::FromHandle(::GetDlgItem(m_hWnd, nID));
else
return m_pCtrlCont->GetDlgItem(nID);
}
再跟蹤到紅色代碼中去:
CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);
#ifndef _AFX_NO_OCC_SUPPORT
pWnd->AttachControlSite(pMap);
#endif
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
return pWnd;
}
再一次跟蹤進入紅色函數里去:
CHandleMap* PASCAL afxMapHWND(BOOL bCreate)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
if (pState->m_pmapHWND == NULL && bCreate)
{
BOOL bEnable = AfxEnableMemoryTracking(FALSE);
#ifndef _AFX_PORTABLE
_PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);
#endif
pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd),
offsetof(CWnd, m_hWnd));
#ifndef _AFX_PORTABLE
AfxSetNewHandler(pnhOldHandler);
#endif
AfxEnableMemoryTracking(bEnable);
}
return pState->m_pmapHWND;
}
看一下AFX_MODULE_THREAD_STATE的定義:
// AFX_MODULE_THREAD_STATE (local to thread *and* module)
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
// list of CFrameWnd objects for thread
CTypedSimpleList<CFrameWnd*> m_frameList;
// temporary/permanent map state
DWORD m_nTempMapLock; // if not 0, temp maps locked
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
// thread-local MFC new handler (separate from C-runtime)
_PNH m_pfnNewHandler;
#ifndef _AFX_NO_SOCKET_SUPPORT
// WinSock specific thread state
HWND m_hSocketWindow;
#ifdef _AFXDLL
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle;
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets;
CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications;
#else
CMapPtrToPtr* m_pmapSocketHandle;
CMapPtrToPtr* m_pmapDeadSockets;
CPtrList* m_plistSocketNotifications;
#endif
#endif
};
看一下黃色的那一行代碼,很明顯,MFC說臨時的map可以被鎖定,先記住就可以。
看一下黃色下面的代碼:
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
很明顯,這里放了一些臨時的映射,包括HWND到CWnd,HDC到CDC的,等等。
並且,MFC除了這些臨時的映射表之外,還有永久的映射表。
也就是說,GetDlgItem以及FromHandle等函數返回的CWnd以及CDC等指針是可以保存的,不管是臨時的map還是永久map中的,我們都可以安全的保存,前提是把臨時的map鎖定,那么不管怎么樣,返回的指針可以在任何時候都是安全的。默認的,MFC是在空閑時間里把臨時map里的東西清空掉的。
剛才說到在空閑時間MFC會把臨時的map刪除掉,我們在剛才那個按鈕事件里添上如下代碼:
AfxGetApp()->OnIdle(1);
然后運行並跟蹤到如下函數:
BOOL CWinApp::OnIdle(LONG lCount)
{
if (lCount <= 0)
{
CWinThread::OnIdle(lCount);
// call doc-template idle hook
POSITION pos = NULL;
if (m_pDocManager != NULL)
pos = m_pDocManager->GetFirstDocTemplatePosition();
while (pos != NULL)
{
CDocTemplate* pTemplate = m_pDocManager->GetNextDocTemplate(pos);
ASSERT_KINDOF(CDocTemplate, pTemplate);
pTemplate->OnIdle();
}
}
else if (lCount == 1)
{
VERIFY(!CWinThread::OnIdle(lCount));
}
return lCount < 1; // more to do if lCount < 1
}
再跟蹤進上面的紅色函數中,整個函數如下:
BOOL CWinThread::OnIdle(LONG lCount)
{
ASSERT_VALID(this);
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// check MFC's allocator (before idle)
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
ASSERT(AfxCheckMemory());
#endif
if (lCount <= 0)
{
// send WM_IDLEUPDATECMDUI to the main window
CWnd* pMainWnd = m_pMainWnd;
if (pMainWnd != NULL && pMainWnd->m_hWnd != NULL &&
pMainWnd->IsWindowVisible())
{
AfxCallWndProc(pMainWnd, pMainWnd->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
pMainWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
}
// send WM_IDLEUPDATECMDUI to all frame windows
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
CFrameWnd* pFrameWnd = pState->m_frameList;
while (pFrameWnd != NULL)
{
if (pFrameWnd->m_hWnd != NULL && pFrameWnd != pMainWnd)
{
if (pFrameWnd->m_nShowDelay == SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
if (pFrameWnd->IsWindowVisible() ||
pFrameWnd->m_nShowDelay >= 0)
{
AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
}
if (pFrameWnd->m_nShowDelay > SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
pFrameWnd->m_nShowDelay = -1;
}
pFrameWnd = pFrameWnd->m_pNextFrameWnd;
}
}
else if (lCount >= 0)
{
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
if (pState->m_nTempMapLock == 0)
{
// free temp maps, OLE DLLs, etc.
AfxLockTempMaps();
AfxUnlockTempMaps();
}
}
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// check MFC's allocator (after idle)
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
ASSERT(AfxCheckMemory());
#endif
return lCount < 0; // nothing more to do if lCount >= 0
}
怎么樣,當了老半天的間諜了,總算能看出點門道了吧?上面3行紅色的代碼說的很清楚,這里會把臨時的map釋放掉。
兩個函數的代碼如下:
AfxLockTempMaps();
AfxUnlockTempMaps();
void AFXAPI AfxLockTempMaps()
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
++pState->m_nTempMapLock;
}
BOOL AFXAPI AfxUnlockTempMaps(BOOL bDeleteTemps)
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
if (pState->m_nTempMapLock != 0 && --pState->m_nTempMapLock == 0)
{
if (bDeleteTemps)
{
if (bDeleteTemps != -1)
{
// allow COM libraries to be freed
CWinThread* pThread = AfxGetThread();
if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)
(*pThread->m_lpfnOleTermOrFreeLib)(FALSE, FALSE);
}
// clean up temp objects
pState->m_pmapHGDIOBJ->DeleteTemp();
pState->m_pmapHDC->DeleteTemp();
pState->m_pmapHMENU->DeleteTemp();
pState->m_pmapHWND->DeleteTemp();
pState->m_pmapHIMAGELIST->DeleteTemp();
}
#ifndef _AFX_PORTABLE
CWinApp* pApp = AfxGetApp();
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
// restore safety pool after temp objects destroyed
if (pApp != NULL &&
(pThreadState->m_pSafetyPoolBuffer == NULL ||
_msize(pThreadState->m_pSafetyPoolBuffer) < pApp->m_nSafetyPoolSize) &&
pApp->m_nSafetyPoolSize != 0)
{
// attempt to restore the safety pool to its max size
size_t nOldSize = 0;
if (pThreadState->m_pSafetyPoolBuffer != NULL)
{
nOldSize = _msize(pThreadState->m_pSafetyPoolBuffer);
free(pThreadState->m_pSafetyPoolBuffer);
}
// undo handler trap for the following allocation
BOOL bEnable = AfxEnableMemoryTracking(FALSE);
pThreadState->m_pSafetyPoolBuffer = malloc(pApp->m_nSafetyPoolSize);
if (pThreadState->m_pSafetyPoolBuffer == NULL)
{
TRACE1("Warning: failed to reclaim %d bytes for memory safety pool.\n",
pApp->m_nSafetyPoolSize);
// at least get the old buffer back
if (nOldSize != 0)
{
//get it back
pThreadState->m_pSafetyPoolBuffer = malloc(nOldSize);
ASSERT(pThreadState->m_pSafetyPoolBuffer != NULL);
}
}
AfxEnableMemoryTracking(bEnable);
}
#endif // !_AFX_PORTABLE
}
// return TRUE if temp maps still locked
return pState->m_nTempMapLock != 0;
}
看到上面黃色的代碼了吧,這時候你還敢保存GetDlgItem或者FromHandle返回的指針嗎?
剛才你不是說可以鎖定臨時map的嗎?是的,可以用AfxLockTempMaps鎖定,但是必須與AfxUnlockTempMaps配對使用,其內部有一個計數變量。MSDN上沒這個函數,最好不要用它,否則除了什么問題我可不保證哦 J
永久的map存放的應該就是我們顯示創建的例如CWnd此類的對象了。
其實很多函數如FromHandle、FindWindow等函數都是用到了這種技術,所以MSDN必定有這樣類似這樣的一句話:The returned pointer may be temporary and should not be stored for later use.
有興趣大家自己跟蹤代碼,源碼面前了無秘密