2010년 3월 8일 월요일

Dialog를 작업표시줄(task bar)에서 숨기려면

Dialog기반 프로그램을 작업표시줄에서 감추고 싶다면, 간단하게 Window Style을 수정해 주면 된다.

  1. LRESULT CMainDlg::OnInitDialog(  
  2.     UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)  
  3. {  
  4.     ...  
  5.     ModifyStyleEx( WS_EX_APPWINDOW,WS_EX_TOOLWINDOW,0 );  
  6.     return TRUE;  
  7. }  

문제는!!
이렇게 되면 Alt+Tab으로는 이 window를 선택할 수 없다는 점이다. 어쩌다 포커스를 잃게되면, window를 다시 찾기 상당히 귀찮아진다.

두시간의 삽질-_-을 통해 꽁수를 부려봤다. 좀 더 좋은 방법이 있다면 알려주시길~
WTL기반으로 작업했지만, MFC라도 약간만 응용하면 적용할 수 있다. (오히려 더 쉽게)

한줄요약: 작업표시줄에서는 나타나지 않으면서, Alt + Tab을 통해 활성화 되는 Dialog를 만들어 보자.

1. 바보-_- 윈도를 하나 만들자. (MFC라면 CWnd를 쓰면 되므로 이 과정은 생략)

  1. class CInvisibleWnd : public CWindowImpl<CInvisibleWnd >  
  2. {  
  3. public:  
  4.     DECLARE_WND_CLASS(NULL);  
  5.  
  6.     BEGIN_MSG_MAP(CInvisibleWnd)  
  7.     END_MSG_MAP()  
  8. };  

2. WTL이라면 Run함수에서 Dialog를 생성할 것이다. (MFC라면 CWinApp::InitInstance)
이때, Dialog의 부모로 바보윈도를 설정해 준다. 눈치 채셨겠지만, 이 꽁수의 핵심은 Dialog의 부모로 설정한 바보윈도는 화면에 표시되면 안된다는 점이다.

  1. int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)  
  2. {  
  3.     ...  
  4.  
  5.     CInvisibleWnd wndInvisible;  
  6.     wndInvisible.Create( NULL, 0, NULL, WS_OVERLAPPEDWINDOW );  
  7.     CMainDlg dlgMain;  
  8.     if ( dlgMain.Create( wndInvisible ) == NULL )  
  9.     {  
  10.         ATLTRACE(_T("Main dialog creation failed!\n"));  
  11.         return 0;  
  12.     }  
  13.  
  14.     dlgMain.ShowWindow(nCmdShow);  
  15.     int nRet = theLoop.Run();  
  16.     _Module.RemoveMessageLoop();  
  17.  
  18.     if ( wndInvisible.IsWindow() )  
  19.         wndInvisible.DestroyWindow();  
  20.  
  21.  
  22.     return nRet;  
  23. }  

그렇다. 바보 윈도는 화면에 표시되지 않고 있으니 작업표시줄에 나타나지 않지만, 인스턴스가 있으므로 Alt + Tab을 치면 나타난다! 그 인스턴스를 활성화 시켜주면 자식윈도로 등록된 Dialog가 활성되는 원리.
중요한점은, 프로그램 종료 시점에서 바보윈도또한 소멸시켜 줘야 한다는 거!

MFC라면 좀 더 쉽다. CDialog를 생성할때, 바보 윈도를 생성자의 parameter로 넘겨주기만 하면된다.
(물론, 소멸은 신경써줘야 한다.)

  1. BOOL CComaApp::InitInstance()  
  2. {  
  3.     ...  
  4.  
  5.     CWnd wndInvisible;  
  6.     LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);  
  7.  
  8.     if (!wndInvisible.CreateEx(0,   
  9.                             pstrOwnerClass,   
  10.                             _T(""),  
  11.                             WS_OVERLAPPEDWINDOW ,   
  12.                             CW_USEDEFAULT,  
  13.                             CW_USEDEFAULT,  
  14.                             CW_USEDEFAULT,  
  15.                             CW_USEDEFAULT,  
  16.                             NULL,   
  17.                             0 ))  
  18.     {  
  19.         TRACE(_T("failed to create invisible window"));  
  20.         return FALSE;  
  21.     }  
  22.  
  23.     CMainDlg dlg(&wndInvisible);  
  24.     
  25.     m_pMainWnd = &dlg;  
  26.     dlg.DoModal();  
  27.  
  28.     if (wndInvisible.m_hWnd != NULL)  
  29.         wndInvisible.DestroyWindow();  
  30. }  

3. 이제 OnInitDialog에서 ModifyStyleEx( WS_EX_APPWINDOW,0 ); 해주면 된다.

꽁수 끄읏!