VC++检查程序托盘图标是否掩藏到沙漏区域中(附源码)
Posted dvlinker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++检查程序托盘图标是否掩藏到沙漏区域中(附源码)相关的知识,希望对你有一定的参考价值。
win7及以上系统引入了托盘图标沙漏区域,创建的新托盘图标是放置在托盘沙漏区域的,默认是掩藏在该沙漏区域中的。通过向上的箭头可以展开沙漏区域,如下所示:
很多程序在第一次运行时会弹出一个提示框,提示程序的托盘图标被掩藏到沙漏区域中了,可以把托盘图标拖到任务栏上来,退出掩藏状态,这样方便对托盘图标进行操作,也能看到托盘图标的闪动提示(比如收到聊天消息时的闪动)。
那么问题来了,该如何判断托盘图标掩藏到沙漏区域了呢?我们是有办法的,代码如下:
// 判断当前32进程是否运行在64位系统上
BOOL IsRunOnWin64()
BOOL bWow64 = FALSE;
BOOL bRet = IsWow64Process( GetCurrentProcess(), &bWow64 );
if ( !bRet )
return FALSE;
return bWow64;
// 判断win7/win8下TrueLink托盘图标是否被掩藏
BOOL IsTrueLinkTrayHidden()
HWND hWnd = NULL, hWndPager = NULL;
unsigned long ulPID = 0;
long lRet = 0, lButtonCount = 0;
HANDLE hProcess = NULL;
LPVOID pAddress = NULL;
long lTextAdr = 0;
TCHAR achBuff[1024] = 0 ;
const TCHAR *pTemp = NULL;
// 通过窗口的层次关系找到托盘区域窗口,至于窗口层次关系可以通过SPY++工具去查看
hWnd = ::FindWindow( _T("Shell_TrayWnd"), NULL );
hWnd = ::FindWindowEx( hWnd, 0, _T("TrayNotifyWnd"), NULL );
hWndPager = ::FindWindowEx( hWnd, 0, _T("SysPager"), NULL );
if( !hWndPager )
hWnd = ::FindWindowEx( hWnd, 0, _T("ToolbarWindow32"), NULL ); // win2000
else
hWnd = ::FindWindowEx( hWndPager, 0, _T("ToolbarWindow32"), NULL ); // win xp及以上系统
// 根据TBBUTTON的结构体构成,找到iString成员的地址偏移
int nStrOffset = sizeof(TBBUTTON) - sizeof(INT_PTR);
if ( IsRunOnWin64() )
// 当前进程是32位进程,字节是以4字节对齐
// 在64位系统上,托盘图标区域隶属于explorer资源管理器进程,是64位进程,在该进程中
// TBBUTTON中的各字段的长度都变长了,所以要针对64位情况计算偏移(要考虑不同系统中
// 的字节对齐问题,TBBUTTON结构体在64位进程中是8字节对齐),by 2014/09/10
nStrOffset += 4; // bReserved在win64下多出来的4字节
nStrOffset += 4; // DWORD_PTR在win64下多出来的4字节
const DWORD dwAllocSize = 0x4096; // 下面的VirtualAllocEx分配的内存大小
// 托盘图标区域窗口隶属于explorer资源管理器进程,托盘图标的信息在explorer进程中,涉及到跨进程内存的访问
// 要用到ReadProcessMemory
lRet = GetWindowThreadProcessId( hWnd, &ulPID );
hProcess = OpenProcess( PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, ulPID );
if ( hProcess == NULL )
return FALSE;
// VirtualAllocEx跨进程到explorer进程中分配内存
pAddress = VirtualAllocEx( hProcess, 0, dwAllocSize, MEM_COMMIT, PAGE_READWRITE );
lButtonCount = ::SendMessage( hWnd, TB_BUTTONCOUNT, 0, 0 );
for( int i=0; i< lButtonCount; i++ )
// 将TBBUTTON结构体信息获取到VirtualAllocEx分配的explorer进程中的内存中
lRet = ::SendMessage( hWnd, TB_GETBUTTON, i, long(pAddress) );
// 根据偏移值跨进程读取读取TBBUTTON中的iString成员的内容
lRet = ReadProcessMemory( hProcess, LPVOID(long(pAddress) + nStrOffset), &lTextAdr, 4, 0 );
if( lTextAdr != -1 )
// 将iString成员的内容读出来
lRet = ReadProcessMemory( hProcess, LPVOID(lTextAdr), achBuff, sizeof(achBuff), 0 );
pTemp = _tcsstr( achBuff, _T("Test")); // 通过窗口名称来比对
if ( pTemp != NULL ) // 找到对应字串
// If the dwFreeType parameter is MEM_RELEASE, dwSize must be 0 (zero).
VirtualFreeEx( hProcess, pAddress, 0, MEM_RELEASE );
CloseHandle( hProcess );
return FALSE;
// If the dwFreeType parameter is MEM_RELEASE, dwSize must be 0 (zero).
VirtualFreeEx( hProcess, pAddress, 0, MEM_RELEASE );
CloseHandle( hProcess );
return TRUE;
上述代码中有详细的注释,具体逻辑我就不再赘述了。
有一点需要注意一下,我们的进程为了兼容32为操作系统,做成32位进程,对于32为程序,内存是以4字节对齐。如果操作系统是64位的,内存是以8字节对齐的,托盘图标区域隶属于explorer资源管理器进程,是64位进程,在该进程中TBBUTTON中的各字段的长度都变长了,所以要针对64位情况计算偏移。所以代码中判断了当前运行的系统是32位的,还是64位的。要考虑不同系统中的字节对齐问题,TBBUTTON结构体在64位进程中是8字节对齐。
以上是关于VC++检查程序托盘图标是否掩藏到沙漏区域中(附源码)的主要内容,如果未能解决你的问题,请参考以下文章