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


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

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

    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;  

    }

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

  • 相关阅读:
    全网通5X_AL10 非定制版 固件汇总
    system.new.dat解压工具sdat2img
    linux 平台中 Android5.0的更新包中system.new.dat文件的解包
    【 henuacm2016级暑期训练-动态规划专题 A 】Cards
    【BZOJ 1486】 [HNOI2009]最小圈
    【BZOJ 1433】[ZJOI2009]假期的宿舍
    【BZOJ 1412】[ZJOI2009]狼和羊的故事
    【BZOJ 1305】[CQOI2009]dance跳舞
    【Codeforces Round #483 (Div. 2) C】Finite or not?
    【Codeforces Round #482 (Div. 2) C】Kuro and Walking Route
  • 原文地址:https://www.cnblogs.com/me115/p/1632923.html
Copyright © 2020-2023  润新知