• 通过枚举窗口,实现最小化到托盘中程序的窗口显示


    我得写点东西来总结一下我这两天的郁闷后最终的收获……

    目的很简单,某一特定应用程序最小化到托盘中,我需要编程实现显示它的主窗口。

    1.首先想到的是通过直接操作进程,通过Findwindow找到这个窗口句柄,然后给其发送一个showwindow消息将其显示。 类“#32770”是用spy++观察到的程序窗口类名。使用

    HWND hwnd = ::FindWindow(_T("#32770"),_T(""));

    ::ShowWindow(hwnd,SW_SHOWNORMAL);

    但如此得到的句柄总是为空。通过实验发现,一旦程序最小化到托盘后,其窗口句柄就无法被捕获。(通过另一程序来枚举当前开的窗口:LP)

    2.失败后,转向托盘编程,考虑在托盘中能获得相关信息:

          标准三部曲:

    //   得到任务栏窗口句柄  

      HWND hTaskBarWnd   =   FindWindow(   "Shell_TrayWnd",   NULL   ); 

      //   得到通知区窗口句柄  

      HWND  hTrayNotifyWnd   =   FindWindowEx(   hTaskBarWnd,     NULL,  

      "TrayNotifyWnd",     NULL   );  

      //   得到系统托盒窗口句柄  

      HWND     hTrayClockWnd   =   FindWindowEx(     hTrayNotifyWnd,  

      NULL,     "ToolbarWindow32",     NULL   );

    但是在我电脑上就是无法获得第三个句柄(即托盘句柄)。而我使用TrayClockWClass,是可以正常获得。他们都是同一父亲,不知何故?

       如果能获取,则可进一步使用

    PostMessage(TB_HIDEBUTTON, index,(LPARAM) MAKELONG(FALSE,   0));

    SendMessage(TB_PRESSBUTTON, i,(LPARAM)MAKELONG(TRUE,   0));  来进行相关处理。当然,还有托盘的刷新操作:

    void   CTrayBar::Refresh()  

    {  

        NOTIFYICONDATAW Icon;  

        Icon.cbSize =   sizeof(   NOTIFYICONDATAW   );  

        Icon.hWnd =   this->m_hWnd   ;  

        Icon.uID =   0;  

        Icon.uFlags =   NIF_MESSAGE   |   NIF_TIP;  

        Icon.uCallbackMessage =   WM_USER   +   777;  

        Icon.hIcon =   NULL;  

        Shell_NotifyIconW(   NIM_ADD   ,   &Icon   );  

        Shell_NotifyIconW(   NIM_DELETE   ,   &Icon   );  

    }  

    3.考虑只获取到通知窗口句柄后,再取得其位置,然后通过每个图标占16 *16 的位置,来推出我的特定程序的图标位置,得到位置后,再模拟鼠标的点击操作,从而实现窗口的显示。代码如下:

    void  ShowMyApp()

    {

        HWND hTrayWindow;

        RECT rctTrayIcon;

        int nIconWidth;

        int nIconHeight;

        CPoint CursorPos;

        int nRow;

        int nCol;

        // Get tray window handle and bounding rectangle

        hTrayWindow = ::FindWindowEx(::FindWindow(

           "Shell_TrayWnd", NULL), 0, "TrayNotifyWnd", NULL);

        if(!::GetWindowRect(hTrayWindow, &rctTrayIcon))

           return;

        //CWnd * pwnd = CWnd::FromHandle(hTrayWindow); //hTrayWindow

        // Get small icon metrics

        nIconWidth = GetSystemMetrics(SM_CXSMICON);

        nIconHeight = GetSystemMetrics(SM_CYSMICON);

        GetCursorPos(&CursorPos);

        for(nRow=0; nRow<(rctTrayIcon.bottom-rctTrayIcon.top)/nIconHeight; nRow++)

        {

           for(nCol=0; nCol<(rctTrayIcon.right-rctTrayIcon.left)/nIconWidth; nCol++)

           {

               SetCursorPos(rctTrayIcon.left + nCol * nIconWidth + 10,

                      rctTrayIcon.top + nRow * nIconHeight + 10);

               GetCursorPos(&CursorPos);

               LPARAM lParam = MAKELPARAM(CursorPos.x,CursorPos.y);//鼠标点击的坐标

               mouse_event(MOUSEEVENTF_LEFTDOWN,CursorPos.x,CursorPos.y,0,NULL);

               mouse_event(MOUSEEVENTF_LEFTUP,CursorPos.x,CursorPos.y,0,NULL);

               Sleep(0);

           }

        }

    }

    如此确实是可以实现我的目标,但是有个大缺点,就是必须知道我的应用程序在托盘中的特定位置,而每次启动Windows后程序在托盘中的位置都是可能不相同的。只有编程实现,正确确定位置,才能模拟鼠标点击。此法还是不行。

    4.再次回到进程的方法上来。通过如下代码可获得程序中所有进程,包括没有窗口句柄的:

    HANDLE GetProcessHandle(int nID)

    {

        return OpenProcess(PROCESS_ALL_ACCESS, FALSE, nID);

    }

    HANDLE GetProcessHandle(LPCTSTR pName)

    {

        HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

        if (INVALID_HANDLE_VALUE == hSnapshot) {

           return NULL;

        }

        PROCESSENTRY32 pe = { sizeof(pe) };

        BOOL fOk;

        for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe)) {

           afxDump << pe.szExeFile<< "  "<< pe.th32ProcessID<< "\n";

           if (!_tcscmp(pe.szExeFile, pName)) {

               CloseHandle(hSnapshot);

               return GetProcessHandle(pe.th32ProcessID);

           }

        }

        return NULL;

    }

    void CPMTimerDlg::OnBnClickedOk()

    {

     HANDLE hd = GetProcessHandle(_T("Bubbles.exe"));

    }

    如此,确实能得到我要的程序的Handle,但是无法从此Handle得到其Hwnd或CWnd,因为一个进程,可能有多个窗口,也可能没有窗口,MS在这方面没有提供更多的函数供我们参考。

    5.通过枚举窗口,这次终于达到目的,至此,花费一整天加一晚上的时间:

           //if   (!::EnumWindows((WNDENUMPROC)enumProc,   0))  

        //  AfxMessageBox("Error"); 

    BOOL CALLBACK enumProc(HWND   hwnd,   LPARAM   lParam)  

    {  

        if   (hwnd   ==   NULL)  

           return   FALSE;  

        if   (::IsWindow(hwnd)   )//&&   ::IsWindowVisible(hwnd))  

        {  

           TCHAR   szCap[255]   =   {0};  

           ::GetWindowText(hwnd,   szCap,   255);  

           if   (strlen(szCap)   ==   0)  

               return   TRUE; 

           CString str ;

           str.Format(_T("%s"),szCap); 

           if(str.Find(_T("ubbles")) != -1)

               ShowWindow(hwnd,SW_SHOWNORMAL);

        }  

        return   TRUE;  

    }

    难关攻克,后面将开始我的轻松代码之旅……

  • 相关阅读:
    UVA
    UVA
    模板——扩展欧几里得算法(求ax+by=gcd的解)
    UVA
    模板——2.2 素数筛选和合数分解
    模板——素数筛选
    Educational Codeforces Round 46 (Rated for Div. 2)
    Educational Codeforces Round 46 (Rated for Div. 2) E. We Need More Bosses
    Educational Codeforces Round 46 (Rated for Div. 2) D. Yet Another Problem On a Subsequence
    Educational Codeforces Round 46 (Rated for Div. 2) C. Covered Points Count
  • 原文地址:https://www.cnblogs.com/me115/p/1632923.html
Copyright © 2020-2023  润新知