• GetDlgItem用法


    基本用法(得到当前对话框中的控件):
    CButton* btn = (CButton*)GetDlgItem(IDC_BUTTON_SEND);
    btn->SetWindowTextW(_T("hello"));
    如果想得到其他对话框中的控件,用GetDlgItem(hwnd,IDD);

    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(IDC_..)是一个非静态方法,意思是你对话框内获取该控件指针,所以这里不需要获取对话框句柄,也就是说你如果在非对话框窗口里面调用这个方法就肯定会出错
    GetDlgItem(HWND hWnd, IDC_..)是一个静态方法,它是一个让你指定从哪个对话框里获取控件指针
    举个例子:你调用了上厕所这个函数,如果你在家里的话肯定是在自己家里上厕所,所以不需要知道在哪里上厕所(hwnd)
    如果你在室外那么上厕所就一定要选一个地方(hwnd)。
    如果说你上厕所的地方都不是一个房间,那么肯定会报错嘛,因为你在随地大小便,哈哈
    所以你先搞清楚这两个函数的使用环境区别
    再者,你问这个问题说明了你还没有搞清楚对话框是一个什么东西,建议学习一下深入浅出MFC

    ------------------------------------------------------------------------------------------

    BOOL EnableWindow(

    HWND hWnd,      // handle to window  (i)

    BOOL bEnable      // flag for enabling or disabling input  (i)

    );

    函数功能:

     该函数禁止/允许指定的窗口或控件,以便拒绝/接受鼠标和键盘的输入。禁止时,窗口不响应鼠标和按键的输入,允许时,窗口接受所有的输入。

    参数:

    hWnd:被禁止/允许的窗口的句柄。

    bEnable:定义窗口是被允许,还是被禁止。若该参数为TRUE,则窗口被允许。若该参数为FALSE,则窗口被禁止。

     返回值:

    如果窗口原来是禁止态,返回值不为零;如果窗口原来是允许态,返回值为零。若想获得更多的错误信息,可调用GetLastError函数。

    备注:

      若窗口的允许/禁止状会发生变化,则Enblewindow函数将发送WM_ENABLE消息。若窗口已被禁止,那么它所有的子窗口也被禁止,即使他们没有被发送WM_ENABLE消息。

      窗口被激活前必须处于允许态。比如,一个应用程序正在显示一个非模态对话框,并且其主窗口处于禁止状态,则应用程序必须在撤消该对话框之前将其主窗口置于允许态。否则,其他窗口将接受键盘输入焦点并被激活。若子窗口被禁止,则系统在确定由哪个窗口接受鼠标消息时将忽略该窗口。

     窗口被创建时默认为允许态。若创建一个初始化为禁止状态的窗口,应用程序需要在CreateWindow或CreateWindowEX函数中指定WS_DISABLED风格。窗口在创建后,应用程序可用EnbleWindow函数来将窗口置于允许态或禁止态。

     应用程序可利用此函数允许/禁止对话框中的某个控件。被禁止的控制既不能接受键盘输入,也不能被用户访问。

    速查:

     

    Windows NT:3.1及以上版本;

    Windows:95及以上版本;

    Windows CE:1.0及以上版本;

    头文件:Winuser.h;

    库文件:user32.lib。

     

    用法:EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),TRUE);

          GetDlgItem(IDC_START)->EnableWindow(FALSE);

    由GetDlgItem函数想到的

    我们在调用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.


    有兴趣大家自己跟踪代码,源码面前了无秘密

  • 相关阅读:
    [转]linux下IPTABLES配置详解
    Linux查看物理CPU个数、核数、逻辑CPU个数 (转)
    linux的NetworkManager服务(转)
    iis 回收工作进程时出错的解决办法
    apache模块详解说明
    Apollo 刨析:简介
    Apollo 刨析:Localization
    格式化聊天列表时间
    ARGB 颜色取值与透明度搭配
    PHPExcel方法总结
  • 原文地址:https://www.cnblogs.com/web100/p/getdlgitem.html
Copyright © 2020-2023  润新知