⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trayiconposition.cpp

📁 mysee网络直播源代码Mysee Lite是Mysee独立研发的网络视频流媒体播放系统。在应有了P2P技术和一系列先进流媒体技术之后
💻 CPP
字号:
/*
 *  Openmysee
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "stdafx.h"
#include "TrayIconPosition.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

extern volatile HINSTANCE g_hInstance;

CTrayIconPosition::CTrayIconPosition()
{
	m_hWndOfIconOwner = NULL;
	m_iTrayIconID = -1;
	m_prDefaultPrecision = High;
	m_iPrecisions[0] = 60; //seconds for low precision mode
	m_iPrecisions[1] = 30; //seconds for medium precision mode
	m_iPrecisions[2] = 10; //seconds for high precision mode

	m_osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx( &m_osVer );
}

CTrayIconPosition::~CTrayIconPosition()
{

}

void CTrayIconPosition::InitializePositionTracking(HWND hwndOfIconOwner, int iIconID)
{
	m_hWndOfIconOwner = hwndOfIconOwner;
	m_iTrayIconID = iIconID;
}

BOOL CTrayIconPosition::GetTrayIconPositionVisualScan(POINT& a_ptPoint, Precision a_ePrec)
{
	//let's find the time from last tray icon position calculation
	time_t iTotalSec = (m_tLastUpdate - time(NULL));
	if(iTotalSec < 0)
	{
		iTotalSec = -iTotalSec;
	}

	Precision prec;
	if(a_ePrec == Default)
	{
		prec = m_prDefaultPrecision;
	}
	else
	{
		prec = a_ePrec;
	}

	BOOL bUpdateRequired = FALSE;
	if(prec == Low && iTotalSec > m_iPrecisions[0]	  ||
	   prec == Medium && iTotalSec > m_iPrecisions[1] ||
	   prec == High && iTotalSec > m_iPrecisions[2]	    )
	   {
		bUpdateRequired = TRUE;
	   }

	if(bUpdateRequired)
	{
		m_rtRectangleOfTheTray = GetTrayWndRect();
		
		if(FindOutPositionOfIcon(::LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_BLANK_BLACK))) == TRUE)
		{
			//we were able to find position of icon in tray - that's GREAT!
			m_tLastUpdate = time(NULL);
			a_ptPoint = m_ptPosition;
			return TRUE;
		}
		else
		{
			//We were unable to locate our icon - this is not a tragedy - usually there is a solution:

			if(m_osVer.dwPlatformId == VER_PLATFORM_WIN32_NT && m_osVer.dwMajorVersion >= 5)
			{
				//We're under Win XP
				//It's quite possible that icon is hidden now let's return Left-Center point of tray - it's most likely WinXP hide-tray-icons button.
				//a_ptPoint = m_rtRectangleOfTheTray.CenterPoint();
				a_ptPoint.x = (m_rtRectangleOfTheTray.left+m_rtRectangleOfTheTray.right)/2;
				a_ptPoint.y = (m_rtRectangleOfTheTray.top+m_rtRectangleOfTheTray.bottom)/2;
				a_ptPoint.x = m_rtRectangleOfTheTray.left + 6;
			}
			else
			{
				//we're not under XP - I have no idea why but we were unable to locate our icon - let's retunr center of the tray area
				//a_ptPoint = m_rtRectangleOfTheTray.CenterPoint();
				a_ptPoint.x = (m_rtRectangleOfTheTray.left+m_rtRectangleOfTheTray.right)/2;
				a_ptPoint.y = (m_rtRectangleOfTheTray.top+m_rtRectangleOfTheTray.bottom)/2;
			}
			return FALSE;
		}
		
	}
	else
	{
		a_ptPoint = m_ptPosition;
	}

	return TRUE;
}

BOOL CTrayIconPosition::GetTrayIconPosition(POINT& a_ptPoint, TrackType a_eTrackType, Precision a_ePrec)
{
	if(m_hWndOfIconOwner == NULL || m_iTrayIconID == -1)
	{
		return -1;
	}
	
	//remove it if you need exact point of left/top corner of the icon
	const int iOffsetX = 4;
	const int iOffsetY = 6;

	RECT rcDirectRect;
	
	switch (a_eTrackType) 
	{
	case UseBothTechniquesDirectPrefered:
		if( FindOutPositionOfIconDirectly(m_hWndOfIconOwner, m_iTrayIconID, rcDirectRect) == FALSE )
		{
			return GetTrayIconPositionVisualScan(a_ptPoint, a_ePrec);
		}
		
		a_ptPoint.x = rcDirectRect.left + iOffsetX;
		a_ptPoint.y = rcDirectRect.top  + iOffsetY;
		return TRUE;

	case UseBothTechniquesVisualScanPrefered:
		if( GetTrayIconPositionVisualScan(a_ptPoint, a_ePrec) == FALSE )
		{
			BOOL bOK = FindOutPositionOfIconDirectly(m_hWndOfIconOwner, m_iTrayIconID, rcDirectRect);

			a_ptPoint.x = rcDirectRect.left + iOffsetX;
			a_ptPoint.y = rcDirectRect.top  + iOffsetY;
			return bOK;
		}
		return TRUE;

	case UseDirectOnly:
		{
			BOOL bOK = FindOutPositionOfIconDirectly(m_hWndOfIconOwner, m_iTrayIconID, rcDirectRect);

			a_ptPoint.x = rcDirectRect.left + iOffsetX;
			a_ptPoint.y = rcDirectRect.top  + iOffsetY;
			return bOK;
		}

	case UseVisualScanOnly:
		return GetTrayIconPositionVisualScan(a_ptPoint, a_ePrec);
		
	default:
		assert(0);
		break;
	}
	

	return FALSE;
}

/*
This class performs check of current position of tray icon olny from time to time.
You can decide if you want low , med or high precision.
Default values of precisions are:
Low - 60 seconds
Med - 30 seconds
High - 10 secods

For example Low precision at 60 seconds means that this class make a full calculation
of tray icon and this value expires in next 60 seconds. If application will request
position of tray icon in time shorter than 60 seconds - there will be no recalculation
and previous calculated value will be used.
*/

void CTrayIconPosition::SetPrecisionTimeOuts(int iLowSec, int iMedSec, int iHighSec)
{
	m_iPrecisions[0] = iLowSec;
	m_iPrecisions[1] = iMedSec;
	m_iPrecisions[2] = iHighSec;
}

/*
This function and GetTrayWndRect() are not written by me - I found this code on codeproject - not remember exacly where.
I was forced to modify this code a bit since some assumptions taken by author were going too far.
*/

BOOL CALLBACK CTrayIconPosition::FindTrayWnd(HWND hwnd, LPARAM lParam)
{    
	TCHAR szClassName[256];
    GetClassName(hwnd, szClassName, 255);    // Did we find the Main System Tray? If so, then get its size and quit
	if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0)    
	{        
		HWND* pWnd = (HWND*)lParam;
		*pWnd = hwnd;
        return FALSE;    
	}    
	
	//Oryginal code I found on Internet were seeking here for system clock and it was assumming that clock is on the right side of tray.
	//After that calculated size of tray was adjusted by removing space occupied by clock.
	//This is not a good idea - some clocks are ABOVE or somewhere else on the screen. I found that is far safer to just ignore clock space.
	
	return TRUE;
}

BOOL CALLBACK CTrayIconPosition::FindToolBarInTrayWnd(HWND hwnd, LPARAM lParam)
{    
	TCHAR szClassName[256];
    GetClassName(hwnd, szClassName, 255);    // Did we find the Main System Tray? If so, then get its size and quit
	if (_tcscmp(szClassName, _T("ToolbarWindow32")) == 0)    
	{        
		HWND* pWnd = (HWND*)lParam;
		*pWnd = hwnd;
        return FALSE;    
	}    
	return TRUE;
}



HWND CTrayIconPosition::GetTrayNotifyWnd(BOOL a_bSeekForEmbedToolbar)
{
	HWND hWndTrayNotifyWnd = NULL;
	
    HWND hWndShellTrayWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
    if (hWndShellTrayWnd)    
	{        
		EnumChildWindows(hWndShellTrayWnd, CTrayIconPosition::FindTrayWnd, (LPARAM)&hWndTrayNotifyWnd);   
		
		if(hWndTrayNotifyWnd && IsWindow(hWndTrayNotifyWnd))
		{
			HWND hWndToolBarWnd = NULL;
			EnumChildWindows(hWndTrayNotifyWnd, CTrayIconPosition::FindToolBarInTrayWnd, (LPARAM)&hWndToolBarWnd);   
			if(hWndToolBarWnd)
			{
				return hWndToolBarWnd;
			}
		}

		return hWndTrayNotifyWnd;
	}  

	return hWndShellTrayWnd;
}

RECT CTrayIconPosition::GetTrayWndRect()
{    
	RECT rect;
	memset(&rect, 0, sizeof(rect));
	
	HWND hWndTrayWnd = GetTrayNotifyWnd(FALSE);
	if(hWndTrayWnd)
	{
		GetWindowRect(hWndTrayWnd, &rect);
		return rect;
	}

	int nWidth  = GetSystemMetrics(SM_CXSCREEN);
    int nHeight = GetSystemMetrics(SM_CYSCREEN);
	::SetRect(&rect, nWidth-40, nHeight-20, nWidth, nHeight);

	return rect;
}


//First tracking method: attaches to Tray process and reads data directly, is fast and reliable but will fail if user uses non standard tray software
//It was suggested by Neal Andrews with VB example: http://www.codeproject.com/shell/ctrayiconposition.asp?select=999036&forumid=14631&df=100#xx999036xx
//Ported to C++ by Ireneusz Zielinski
BOOL CTrayIconPosition::FindOutPositionOfIconDirectly(const HWND a_hWndOwner, const int a_iButtonID, RECT& a_rcIcon)
{
	//first of all let's find a Tool bar control embed in Tray window
	HWND hWndTray = GetTrayNotifyWnd(TRUE);
    if (hWndTray == NULL)    
	{
		return FALSE;
	}

	//now we have to get an ID of the parent process for system tray
	DWORD dwTrayProcessID = -1;
	GetWindowThreadProcessId(hWndTray, &dwTrayProcessID);
	if(dwTrayProcessID <= 0)
	{
		return FALSE;
	}

	HANDLE hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);
	if(hTrayProc == NULL)
	{
		return FALSE;
	}
 

	//now we check how many buttons is there - should be more than 0
	LRESULT lButtonsCount = SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);

	//We want to get data from another process - it's not possible to just send messages like TB_GETBUTTON with a localy
	//allocated buffer for return data. Pointer to localy allocated data has no usefull meaning in a context of another
	//process (since Win95) - so we need to allocate some memory inside Tray process.
	//We allocate sizeof(TBBUTTON) bytes of memory - because TBBUTTON is the biggest structure we will fetch. But this buffer
	//will be also used to get smaller pieces of data like RECT structures.
	LPVOID lpData = VirtualAllocEx(hTrayProc, NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
	if( lpData == NULL || lButtonsCount < 1 )
	{
		CloseHandle(hTrayProc);
		return FALSE;
	}

	BOOL bIconFound = FALSE;

	for(int iButton=0; iButton<lButtonsCount; iButton++)
	{
		//first let's read TBUTTON information about each button in a task bar of tray

		DWORD dwBytesRead = -1;
		TBBUTTON buttonData;
		SendMessage(hWndTray, TB_GETBUTTON, iButton, (LPARAM)lpData);
		ReadProcessMemory(hTrayProc, lpData, &buttonData, sizeof(TBBUTTON), &dwBytesRead);
		if(dwBytesRead < sizeof(TBBUTTON))
		{
			continue;
		}

		//now let's read extra data associated with each button: there will be a HWND of the window that created an icon and icon ID
		DWORD dwExtraData[2] = { 0,0 };
		ReadProcessMemory(hTrayProc, (LPVOID)buttonData.dwData, dwExtraData, sizeof(dwExtraData), &dwBytesRead);
		if(dwBytesRead < sizeof(dwExtraData))
		{
			continue;
		}

		HWND hWndOfIconOwner = (HWND) dwExtraData[0];
		int  iIconId		 = (int)  dwExtraData[1];
		
		if(hWndOfIconOwner != a_hWndOwner || iIconId != a_iButtonID)
		{
			continue;
		}
		
		//we found our icon - in WinXP it could be hidden - let's check it:
		if( buttonData.fsState & TBSTATE_HIDDEN )
		{
			break;
		}

		//now just ask a tool bar of rectangle of our icon
		RECT rcPosition = {0,0};
		SendMessage(hWndTray, TB_GETITEMRECT, iButton, (LPARAM)lpData);
		ReadProcessMemory(hTrayProc, lpData, &rcPosition, sizeof(RECT), &dwBytesRead);

		if(dwBytesRead < sizeof(RECT))
		{
			continue;
		}

		MapWindowPoints(hWndTray, NULL, (LPPOINT)&rcPosition, 2);
		a_rcIcon = rcPosition;
		
		bIconFound = TRUE;
		break;
	}

	if(bIconFound == FALSE)
	{
		a_rcIcon = GetTrayWndRect(); //we failed to detect position of icon - let's return fail safe cooridinates of system tray
	}

	VirtualFreeEx(hTrayProc, lpData, NULL, MEM_RELEASE);
	CloseHandle(hTrayProc);

	return bIconFound;	
}

//as mentioned in article Shell_NotifyIcon likes to alter icons while putting them to system tray
//so even black icon can be not in 100 black
BOOL CTrayIconPosition::CheckIfColorIsBlackOrNearBlack(COLORREF crColor)
{
	//code improved by Harald according to
	//http://www.codeproject.com/shell/ctrayiconposition.asp?forumid=14631&select=786426&df=100#xx786426xx

	return !(((DWORD)crColor)&0xFCFCFC);
}

BOOL CTrayIconPosition::FindOutPositionOfIcon(HICON icon)
{
	//First: let's set a BLANK icon in the tray.
	NOTIFYICONDATA nid; 
	nid.cbSize = sizeof(nid); 
	nid.hWnd = m_hWndOfIconOwner; 
	nid.uID = m_iTrayIconID; 
	nid.uFlags = NIF_ICON; 
	nid.hIcon = icon;
	Shell_NotifyIcon(NIM_MODIFY, &nid);
	BOOL bWeFoundIt = FALSE;
	
	HDC hdcScreen = GetDC(NULL);
	
	//since tray window can be strethed verticaly let's scan this area in few steps starting from the bottom to the top.
	for(int iy = m_rtRectangleOfTheTray.bottom-3; iy > m_rtRectangleOfTheTray.top; iy--)
	{
		int iNoOfPixelsInLine=0;
		for(int ix=m_rtRectangleOfTheTray.left;ix<m_rtRectangleOfTheTray.right;ix++)
		{
			COLORREF crPixel = GetPixel(hdcScreen, ix, iy);
			COLORREF crPixel2 = GetPixel(hdcScreen, ix, iy-2);
			COLORREF crPixel3 = GetPixel(hdcScreen, ix, iy+2);
			if(CheckIfColorIsBlackOrNearBlack(crPixel)  && CheckIfColorIsBlackOrNearBlack(crPixel2)  && CheckIfColorIsBlackOrNearBlack(crPixel3))
			{
				iNoOfPixelsInLine++;
			}
			else
			{
				iNoOfPixelsInLine = 0;
			}
			
			if(iNoOfPixelsInLine > 8)
			{
				//well I think we found it!
				m_ptPosition.x = ix-1;
				m_ptPosition.y = iy-6;
				bWeFoundIt = TRUE;
				break;
			}
		}
		
		if(bWeFoundIt)
		{
			break;
		}
	}

	ReleaseDC(NULL, hdcScreen);
	return bWeFoundIt;
}

void CTrayIconPosition::RestoreTrayIcon(HICON icon)
{
	  NOTIFYICONDATA nid; 
	  nid.cbSize = sizeof(nid); 
	  nid.hWnd = m_hWndOfIconOwner; 
	  nid.uID = m_iTrayIconID; 
	  nid.uFlags = NIF_ICON; 
	  nid.hIcon = icon;
	  if(Shell_NotifyIcon(NIM_MODIFY, &nid) == FALSE)
        Shell_NotifyIcon(NIM_ADD, &nid);
}

void CTrayIconPosition::Invalidate()
{
	m_tLastUpdate = 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -