能力值:
( LV12,RANK:1010 )
2 楼
呵呵,谢谢几位大虾的指点,偶已经调试成功了,这小程序暂时只能判别QQ2006版本的:
------------------------------------------------------------------------------------------------------------------
偶在调试中发现,读取QQ进程虚拟地址空间的内容中会显示一条信息:
http://mobile.client.qq.com/mqq2006/sms.html?qq=你的QQ号
于是直接用strrchr从后面找到qq=这几个关键字就可以了,当然可以自己选择了
偶准备用CString::Reverse(),算了还是用strrchr吧.
这一点和作者的提示有点儿不一样了.结果是QQ号码终于找到了:
/****************************************************************************
* FileName: GetQQName.cpp
* Author : sudami
* E-MAIL : [email]xiao_rui_119@163.com[/email]
* Time : 2007/08/15
* Comment : 获取当前进程中的正在运行的QQ号码
****************************************************************************/
#include <afxwin.h>
#include <tlhelp32.h>
#include <tchar.h>
/////////////////////////////////////////////////////////////////////////////
HANDLE hQQProcess[5];
int g_i = 0;
void GetQQHandle (); // 获得QQ进程的句柄
void FindandShowQQName (); // 获取并显示QQ号码
int __stdcall WinMain (HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
GetQQHandle ();
FindandShowQQName ();
}
/////////////////////////////////////////////////////////////////////////////
//
//
void GetQQHandle ()
{
int a = 0;
// 遍历进程,获得当前运行的QQ的PID,获得相应的句柄
// 汗,原来大小写不同还有可能找不到QQ进程.
CString szNameQE = TEXT("QQ.EXE");
CString szNameQe = TEXT("QQ.exe");
CString szNameqE = TEXT("qq.EXE");
CString szNameqe = TEXT("qq.exe");
PROCESSENTRY32 pe32 = {sizeof (PROCESSENTRY32)};
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot (
TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return;
if (::Process32First (hProcessSnap, &pe32))
{
do
{
if (pe32.szExeFile == szNameQE || pe32.szExeFile == szNameQe
|| pe32.szExeFile == szNameqE || pe32.szExeFile == szNameqe)
{
a++;
// 获得此QQ进程的句柄
hQQProcess[g_i] = ::OpenProcess (
PROCESS_ALL_ACCESS, false, pe32.th32ProcessID);
g_i++;
}
}
while (::Process32Next (hProcessSnap, &pe32));
}
if (a == 0)
::MessageBox (NULL, TEXT("小子你还没有运行QQ啊"), TEXT("NOTICE"), MB_OK);
::CloseHandle (hProcessSnap);
}
/////////////////////////////////////////////////////////////////////////////
//
//
void FindandShowQQName ()
{
int a = 0;
MEMORY_BASIC_INFORMATION mbi;
PBYTE pAddress = NULL;
char szBuf[MAX_PATH] = {0};
SYSTEM_INFO si;
memset(&si, 0, sizeof(si));
GetSystemInfo( &si );
LPVOID LowAddr, HighAddr;
LowAddr = si.lpMinimumApplicationAddress;
HighAddr = si.lpMaximumApplicationAddress;
for (int i=0; i<g_i; i++)
{
// 搜索 类型=MEM_PRIVATE 页面属性=PAGE_READWRITE 的内存块
while(VirtualQueryEx (hQQProcess[i], pAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION))
== sizeof(MEMORY_BASIC_INFORMATION))
{
if((mbi.AllocationProtect == PAGE_READWRITE)/* && (mbi.State == MEM_COMMIT)*/
&& (mbi.Type == MEM_PRIVATE))
{
// 读取QQ进程虚拟地址里面的指定内容
BOOL bReadMemory = ::ReadProcessMemory (hQQProcess[i], pAddress, szBuf, MAX_PATH,NULL);
/****************************************************************************
* 通过调试,偶发现读取的内容中有一条直接是:
*
* [url]http://mobile.client.qq.com/mqq2006/sms.html?qq=[/url]你的QQ号
*
* 哈哈,于是直接用strrchr从后面找到qq=这几个关键字就可以了,当然可以自己选择了
* 偶准备用CString::Reverse(),算了还是用strrchr吧.
*****************************************************************************/
int ch_a = '=';
int ch_b = ':';
char *p = strrchr (szBuf, ch_a);
char *q = strrchr (szBuf, ch_b);
if (p && q)
{
p++;
a++;
::MessageBox (NULL, TEXT("你的QQ是2006版本的吗?反正终于找到了 by:sudami"), p, MB_OK);
break;
}
}
pAddress += mbi.RegionSize;
}
}
if (a == 0)
::MessageBox (NULL, TEXT("这小程序暂时只能获取QQ2006版本的."), TEXT("NOTICE"), MB_OK);
} 问题暂时解决,希望继续讨论QQ2007版本的如何简单的获取其QQ号码呢?[s:289]
上传的附件:
能力值:
( LV12,RANK:1010 )
3 楼
-------------------------------------------------
QQ2007读取 QQ号码 是提取 LoginUinList.dat这个文件
偶按照你的提示写了个代码测试了一下,结果另人失望,读取的完全是乱码,根本没有任何数字.[s:269]
按照
zshoucheng 大叔说的去实现还是有道理,获取托盘处的Tip,偶还在写代码中...
/********************************************************************************
* FileName: GetQQNameFromFile
* Author : sudami
* Time : 2007/08/17
* Comment : simen521 同学说"QQ2007读取 QQ号码 是提取 LoginUinList.dat这个文件"
于是偶测试了一下,发现不成功, 都是乱码,其中没有数字出现.
不知道偶的测试是否准确,故帖出代码大家讨论一下.
/////////////////////////////////////////////
感觉还是 zshoucheng 大叔说的有道理,获取托盘处的Tip,偶还在写代码中...
*********************************************************************************/
#include <afxwin.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <iostream.h>
////////////////////////////////////////////////////////////
CString FILENAME = TEXT("LoginUinList.dat"); // 要读取的QQ目录下的文件
HANDLE hQQProcess[5]; // 保存QQ进程句柄
TCHAR QQFullPath[MAX_PATH]; // 保存QQ安装程序的目录
int g_i = 0;
////////////////////////////////////////////////////////////
void IsQQRunning (); // 判断QQ是否在运行,没有就运行QQ
BOOL GetQQFilePath (); // 获得QQ安装程序的目录
BOOL GetQQHandle (); // 获得QQ进程的句柄
BOOL FileRead (LPCTSTR pszPathName); // 读取LoginUinList.dat中的内容
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//
int main ()
{
if (!GetQQFilePath ())
{
::MessageBox (NULL, TEXT("大哥,这年头都不装QQ啊!"), TEXT("汗-_-||"), MB_OK);
exit (0);
}
IsQQRunning ();
/********************************************************
* *
* 读取QQ安装目录中的LoginUinList.dat文件 *
* *
********************************************************/
CString mPath = QQFullPath;
int mPos = mPath.ReverseFind('\\'); // 去掉最后的QQ.exe
if(mPos == -1)
return 0;
mPath = mPath.Left(mPos);
if (mPath.Right(1) != '\\')
mPath += '\\';
CString szFinalQQPath = mPath + FILENAME;
system("title sudami -- 读取QQ安装目录中的LoginUinList.dat文件");
cout << "您QQ的安装路径:" << mPath << endl;
/////////////////////////////////////////////////////
if (!FileRead (szFinalQQPath))
{
::MessageBox (
NULL,
TEXT("读取失败,MS QQ2007版本用这个方法行不通啊.\n是不是LoginUinList.dat的内容被加密了呢?\n by:sudami"),
TEXT("NOTICE"),
MB_OK);
}
return 0;
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//
void IsQQRunning ()
{
if (!GetQQHandle ())
{
int a = ::MessageBox (
NULL,
TEXT("获取QQ句柄过程出错,请保证您已经运行了QQ!\n \t点 '是' 开始运行QQ\
\n\t点 '否' 退出程序"),
TEXT("sudami"),
MB_YESNO);
if (a == IDYES)
{
::ShellExecute (NULL, _T("open"), QQFullPath, NULL, NULL, SW_SHOW);
Sleep (1000 * 10);
IsQQRunning ();
}
else
exit (0);
}
}
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// 获得QQ安装路径 -- 查询注册表是最简单的了,一开始还打算用文件遍历的
// 后来觉得太慢便改为调用 GetModuleFileName() 函数,可又找不到QQ进程的HINSTANCE.
// 汗,偶太菜了,最后想了想,还是用注册表最简单了.因为正规软件安装的时候都会把自己程序的
// 安装路径写进注册表的.
//
BOOL GetQQFilePath ()
{
DWORD dwBufLen = MAX_PATH;
HKEY hRoot = HKEY_LOCAL_MACHINE;
HKEY hKey;
/*************************************************************
* 在注册表中查询关键字 "QQ.exe" 发现的.
* 为了证实此CLSID在不同的电脑上是唯一的,偶在同学电脑查找了一下
* 又在虚拟机上查找了,结果是唯一的
*************************************************************/
char *szSubKey = TEXT("SOFTWARE\\Classes\\CLSID\\{2D616D8F-F1BA-43A1-BEF0-E2A82A0FBD56}\\LocalServer32");
if (::RegOpenKeyEx(hRoot, szSubKey, 0, KEY_QUERY_VALUE, &hKey)
!= ERROR_SUCCESS)
return FALSE;
LONG lRet = ::RegQueryValueEx(
hKey,
NULL,
NULL,
NULL,
(LPBYTE)QQFullPath,
&dwBufLen);
RegCloseKey(hKey);
return TRUE;
}
//------------------------------------------------------------
//------------------------------------------------------------
//
BOOL GetQQHandle ()
{
BOOL bQQrunning = FALSE;
int a = 0;
// 遍历进程,获得当前运行的QQ的PID,获得相应的句柄
CString szName = TEXT("QQ.exe");
PROCESSENTRY32 pe32 = {sizeof (PROCESSENTRY32)};
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot (
TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return FALSE;
// 遍历当前进程,找出QQ进程
if (::Process32First (hProcessSnap, &pe32))
{
do
{
if (lstrcmpi ((LPCTSTR)pe32.szExeFile, szName) == 0)
{
bQQrunning = TRUE;
a++;
// 获得此QQ进程的句柄
hQQProcess[g_i] = ::OpenProcess (
PROCESS_ALL_ACCESS, false, pe32.th32ProcessID);
g_i++;
}
}
while (::Process32Next (hProcessSnap, &pe32));
}
if (a == 0)
::MessageBox (NULL, TEXT("小子你还没有运行QQ啊"), TEXT("NOTICE"), MB_OK);
::CloseHandle (hProcessSnap);
return bQQrunning;
}
//------------------------------------------------------------
//------------------------------------------------------------
//
BOOL FileRead (LPCTSTR pszPathName)
{
BOOL bExistQQName = FALSE;
// cout << pszPathName << endl;
int i = 0;
const int c_page = 4 * 1024; // 4kb,即一页
char buff[c_page]; // 保存读取文件的内容
char *ptr = buff;
char temp[MAX_PATH]; // 保存找到的QQ号码
DWORD dwRead;
CFile sourceFile;
// 打开QQ安装目录下的 LoginUinList.dat 文件
BOOL bOK = sourceFile.Open (pszPathName,
CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary);
if (!bOK)
::MessageBox (NULL, TEXT("File open failed!"), TEXT("NOTICE"), MB_OK);
// 每一次读取4KB的内容,不过这个小文件才300多字节,读一次就完了
do
{
dwRead = sourceFile.Read (buff, c_page);
do
{
// 如果读到数字,则保存在 temp 数组中
while (*ptr > 47 && *ptr < 58)
{
temp[i] =*ptr;
++i;
++ptr;
}
// 如果i值大于0,表明读到了数字.则可初步认为读到了QQ号码
// 但是否QQ运行时把QQ号码记录在这里呢?
if (i > 0)
{
bExistQQName = TRUE;
::MessageBox (NULL, TEXT("这下看找到没有 by:sudami"), temp, MB_OK);
i = 0;
}
}
while (*ptr++);
}
while (dwRead > 0);
sourceFile.Close ();
return bExistQQName;
}
普通会员上传不了附件,有需要查看源码和程序的可以到偶的网盘里面下载:
http://sudami.atedu.net/
上传的附件:
能力值:
( LV6,RANK:90 )
4 楼
type
TGetQQNumber = class
qqlist: TStrings;
private
procedure GetList(ClassName:String);
public
constructor Create();
destructor Destroy(); override;
end;
constructor TGetQQNumber.Create;
begin
qqlist := TStringList.Create;
GetList('Afx:61790000:2');//QQ2006 STD
GetList('Afx:61800000:2');//QQ2007 Beta3
GetList('Afx:61810000:2');//按规律随意添加的,不知道对不对
GetList('Afx:61820000:2');//按规律随意添加的,不知道对不对
GetList('Afx:61830000:2');//按规律随意添加的,不知道对不对
GetList('Afx:61840000:2');//QQ2007 Beta4
end;
destructor TGetQQNumber.Destroy;
begin
qqlist.Free;
end;
procedure TGetQQNumber.GetList(ClassName: String);
var
Wnd: DWord;
Buf: array[0..255] of char;
i: integer;
begin
Wnd := 0;
repeat
Wnd := FindWindowEx(0, Wnd, pchar(ClassName), nil);
GetWindowText(Wnd, Buf, 255);
if buf <> '' then
begin
for i := 0 to 255 do
begin
if Buf[i] = '_' then
begin
Buf[i] := #0;
break;
end;
end;
qqlist.Add(buf);
end;
until (Wnd = 0);
end;
编译完成的EXE在附件.测试QQ2006STD 2007B3 2007B4能正确获取.其他版本的支持需要找出对应的窗口类名.
上传的附件:
能力值:
( LV12,RANK:1010 )
5 楼
是delphi吗? 没学这个,看懂个大概,关键是:
GetList('Afx:61790000:2');//QQ2006 STD GetList('Afx:61800000:2');//QQ2007 Beta3 GetList('Afx:61810000:2');//按规律随意添加的,不知道对不对 GetList('Afx:61820000:2');//按规律随意添加的,不知道对不对 GetList('Afx:61830000:2');//按规律随意添加的,不知道对不对 GetList('Afx:61840000:2');//QQ2007 Beta4
然后调用FindWindowEx 查找QQ窗口的控件,GetWindowText 获得起QQ号码的吧.
呵呵,谢谢你了. 一会儿改成VC的看看效果.
能力值:
(RANK:1010 )
6 楼
宽 字 符 的 吧
能力值:
( LV12,RANK:1010 )
7 楼
大叔说的是Unicode字符吗?
能力值:
( LV2,RANK:10 )
8 楼
鼠标停在QQ添加的系统托盘区的图标时显示的信息包含QQ号罢?
如果能读取到QQ添加在的系统托盘区的图标的信息……
能力值:
( LV2,RANK:10 )
9 楼
引用易论坛上angzhi得原文:
http://bbs.dywt.com.cn/dispbbs.asp?BoardID=124&ID=55752&replyID=319990 修正后的源码及EXE , 有易友提出源程序出错, 这里说明一下, 源程序是用4.0测试版5编写的 , 用3.8打开会出错 : 点击浏览该文件 前段时间在论坛上, 易友 "wjkplx" 问 "如何取正在运行的QQ号" (dispbbs.asp?BoardID=1&ID=51048), 后来有"方德软件","近在眼前","goomoo","云德武" 几位热心的大侠各自提出了自己的思路及解决办法. 几位的贴子如下: "goomoo":
dispbbs.asp?boardid=1&star=1&replyid=8168&id=55328&skin=0&page=1
近在眼前:
dispbbs.asp?boardid=1&star=1&replyid=9038&id=55314&skin=0&page=1
dispbbs.asp?boardid=1&star=1&replyid=8223&id=55487&skin=0&page=1
方德软件:
dispbbs.asp?BoardID=1&ID=55343
云城武:
dispbbs.asp?BoardID=1&ID=55599 几位易友的方法各不相同, 各有优点, 也都不完美. "方德软件"的方法是查找硬盘文件, 编程简单,但只能取最后一个登陆的QQ号码,不能取多个QQ的号码. "近在眼前"最初的办法好像是搜索QQ目录以数字命名的文件夹, 也同样有 "方德软件" 的缺点, "近在眼前"之后修改的版本, 采用了moogoo的方法. 相对来说, "goomoo" 的方法是最好的, 直接在QQ进程空间里查找QQ号码,因为QQ的任何数据都是放在进程空间里的(包括QQ号码),所以这个方法是绝对能成功的.当然,前提是QQ必须先登陆成功. "goomoo" 的方法可能是考虑得不够周全, 比如有些号码找不到, 而有些找到了又是别的号码."云城武" 的方法跟 "goomoo"是一样的. 我花了两天时间, 仔细地研究了各位的方法, 并到网上搜索了相关的资料, 集合几位大侠的思路, 做出了取QQ登陆号码的程序. 这个程序可以提取腾讯QQ所有版本的登陆成功后的QQ号码. 可以在任何操作系统下使用. 运行速度快, 取号码准确, 目前为止,没有发现取错号.
制作这个程序的过程中,我查阅了很多相关资料, 对系统编程有了进一步的了解, 下面我就编制这个程序的原理过程和一些心得写出来, 给大家参考. 一. 取QQ号码原理: QQ程序在运行过程中, 所有数据都是存放在进程空间中,QQ号码也不例外, 要取QQ号码, 从QQ进程空间着手是最保险的.
怎样确定QQ号码在QQ进程空间的位置? "goomoo"的方法是搜索"clientuin="关键字,这个关键字之后紧跟着就是QQ号码. 但我发现, "clientuin="后面也不一定总是登陆的QQ号码,有时是别的字符,有时是本地登陆的其他QQ号码, 有时又是好友的QQ号码. 所以这个通过这个关键字来定位是不准确的.
经过分析, 我发现,QQ运行过程中会读取"MsgEx.db"文件, 在这个文件的全路径中就包含了QQ号码, 路径格式为: QQ路径 +"\" + QQ登陆号码 + "\MsgEx.db", 找到"\MsgEx.db"关键字, 然后提取关键字前面的第一个"\"和第二个"\"之间的文本,不就是QQ号码了吗? 对,正是这样.
在QQ进程中, "\MsgEx.db" 的地方很多, 有些前面跟的不是QQ号码.为了保证取到号码的正确性, 我们需要加入一些判断技巧. 大家知道,QQ号码都是数字格式的, 所以只要我们判断取出来的号码是不是数字, 如果不是数字,就继续查找,直到找到是数字的文本为止.
二. 怎样搜索QQ进程空间的数据? 1.应用程序进程
进程是当前操作系统下一个被加载到内存的、正在运行的应用程序的实例。每一个进程都是由内核对象和地址空间所组成的,内核对象可以让系统在其内存放有关进程的统计信息并使系统能够以此来管理进程,而地址空间则包括了所有程序模块的代码和数据以及线程堆栈、堆分配空间等动态分配的空间。进程仅仅是一个存在,是不能独自完成任何操作的,必须拥有至少一个在其环境下运行的线程,并由其负责执行在进程地址空间内的代码。在进程启动的同时即同时启动了一个线程,该线程被称作主线程或是执行线程,由此线程可以继续创建子线程。如果主线程退出,那么进程也就没有存在的可能了,系统将自动撤消该进程并完成对其地址空间的释放。
加载到进程地址空间的每一个可执行文件或动态链接库文件的映象都会被分配一个与之相关联的全局唯一的实例句柄(Hinstance)。 2. 进程空间
在WIN32中,每个应用程序都可“看见”4GB的线性地址空间, 其中最开始的4MB和最后的2GB由操作系统保留,低的2GB为进程的私有空间(如果在Boot.ini文件中使用“/3GB”的开关可以使进程的私有空间增大到3GB,系统空间1GB)。对于每个进程来讲其虚拟的地址空间是连续的,实际上它们是以页面为单位离散的存在于物理内存中,一些可能被交换到硬盘上的页面文件中,而且还有大部分的空间是未提交(Uncommitted)的。一个进程的低2GB私有空间的分布如下表: 范围 大小 作用
-----------------------------------------------------------------------------------------------------------------------------
0x0~~0xFFFF 64 KB 不可访问区域,只是用来防止非法的指针访问,访问该范围的地址会导致访问违例。
0x10000~~0x7FFEFFFF 2 GB 减去至少192 KB 进程的私有地址空间
0x7FFDE000~~0x7FFDEFFF 4 KB 进程中第一个线程的线程环境块,即TEB(Thread environment block)
0x7FFDF000~~0x7FFDFFFF 4 KB 进程的进程环境块,即PEB(Process environment block)
0x7FFE0000~~0x7FFE0FFF 4 KB 一个共享的只读用户数据块,该块映射到到系统空间的一个数据块,
其中存放的是一些系统信息如系统时间、时钟的滴答数、系统版本号等。
这样访问这些信息的时候系统就不用切换到核心模式。
0x7FFE1000~~0x7FFEFFFF 60 KB 不可访问
0x7FFF0000~~0x7FFFFFFF 64 KB 不可访问,用于防止线程的缓冲跨越两种模式空间的边界
一个进程的高2GB空间具体分配如下:
0xFFFFFFFF-0xC0000000的1GB 用于VxD、存储器管理和文件系统;
0xBFFFFFFF-0x80000000的1GB 用于共享的WIN32 DLL、存储器映射文件和共享存储区;
虚拟内存通常是由固定大小的块来实现的,在WIN32中这些块称为“页”,每页大小为4,096字节。在Intel CPU结构中,通过在一个控制寄存器中设置一位来启用分页。启用分页时CPU并不能直接访问内存,对每个地址要经过一个映射进程,通过一系列称作“页表”的查找表把虚拟内存地址映射成实际内存地址。通过使用硬件地址映射和页表WIN32可使虚拟内存即有好的性能而且还提供保护。利用处理器的页映射能力,操作系统为每个进程提供独立的从逻辑地址到物理地址的映射,使每个进程的地址空间对另一个进程完全不可见。
........
查看全部 :
http://bbs.dywt.com.cn/dispbbs.asp?BoardID=124&ID=55752&replyID=319990
能力值:
( LV2,RANK:10 )
10 楼
能力值:
( LV12,RANK:1010 )
11 楼
谢谢你的关注, 易语言的看不懂,
现在有些忙,过段时间应该能写个从托盘处获取QQ号码的VC版了~
能力值:
( LV2,RANK:10 )
12 楼
这是Delphi版的,保证可以用,不用那么麻烦。
Program FindQQ;
uses
windows;
var
WINText:PChar ;
TXTLen:Integer;
QQHao:string ;
QQWnd:HWND ;
begin
QQWnd:=FindWindow ('Afx:61790000:2',nil);
if QQWnd >0 then
begin
TXTLen:=GetWindowTextLength (QQWnd);
GetMem (WINText,TXTLen+1);
GetWindowText (QQWnd,WINText,TXTLen+1);
qqhao:=string( WINText);
Delete (QQHao,Pos ('_',QQHao),100);
MessageBox( 0,PChar(QQHao),'QQ号',MB_OK);
FreeMem (WINText);
end;
end.
QQ:631113025
能力值:
( LV2,RANK:10 )
13 楼
楼主上的方法好像对QQ2007无效呀?
能力值:
( LV2,RANK:10 )
14 楼
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; FileName: TrayIcon.asm
; Function: Demo the way to enum the icons in system tray
; Author: Purple Endurer | 紫郢剑侠㊣ (PurpleEndurer@163.com)
; DevEnv: Win2000 pro SP4, MASM32 v8
;
; log
; ----------------------------------------------------------------------------------
; 2007-09-29 Can run under Win XP
; 2007-09-22 Created!
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
GetSysTrayToolBarHandle proto
EnumSubCtl proto :HWND, :LPARAM
GetSysTrayIconCount proto
EnumSysTrayIcon proto
.data
g_szAppName db "EnumSysTrayIcon", 0
g_szTaskBarCls db "Shell_TrayWnd", 0
g_szSysPagerCls db "SysPager", 0 ;WinXP need!
g_szTrayNotifyWndCls db "TrayNotifyWnd", 0
g_szToolbarWindow32Cls db "ToolbarWindow32", 0
g_szFailGetSysTray db "Fail to get system tray!", 0
g_hSysTray HANDLE ?
g_dwTrayIconCount dword ?
g_stTbButton TBBUTTON <>
g_szIconText db MAX_PATH dup (?)
.code
start:
invoke GetSysTrayToolBarHandle
test eax, eax ; .if eax==NULL
.if ZERO?
invoke MessageBox, NULL, addr g_szFailGetSysTray, addr g_szAppName, MB_ICONERROR
.else
mov g_hSysTray, eax
invoke EnumSysTrayIcon
.endif
invoke ExitProcess,NULL
;////////////////////////////////////////////////////////////////////////////////
; Function: Get the handle ToolbarWindow32 of in system tray
; Shell_TrayWnd -> TrayNotifyWnd -> (WinXP:SysPager) -> ToolbarWindow32
; Onput: if fail eax=NULL, else eax = handle
;/////////////////////////////////////////////////////////////////////////////////
GetSysTrayToolBarHandle proc
;--- Get the handle of task bar
invoke FindWindow, addr g_szTaskBarCls, NULL
cmp eax, NULL
je @GetSysTrayToolBarHandleRet ; fail
; HWND FindWindowEx(
; HWND hwndParent, // handle to parent window
; HWND hwndChildAfter, // handle to a child window
; LPCTSTR lpszClass, // pointer to class name
; LPCTSTR lpszWindow // pointer to window name
; );
;--- Get the handle of TrayNotifyWnd in task bar
invoke FindWindowEx, eax, NULL, addr g_szTrayNotifyWndCls, NULL
cmp eax, NULL
je @GetSysTrayToolBarHandleRet
;--- (WinXP Only) Get the handle of g_szSysPager in TrayNotifyWnd
push eax
invoke FindWindowEx, eax, NULL, addr g_szSysPagerCls, NULL
.if (eax==NULL)
pop eax
.else
pop edi
.endif
;--- Get the handle of ToolbarWindow32 in TrayNotifyWnd
invoke FindWindowEx, eax, NULL, addr g_szToolbarWindow32Cls, NULL
@GetSysTrayToolBarHandleRet:
ret
GetSysTrayToolBarHandle endp ;/////////////////////////////////////////////////////////////////////////////////
; Function: Enum the Child window in task bar
;/////////////////////////////////////////////////////////////////////////////////
EnumSubCtl proc proc hWnd: HWND, lParam: LPARAM
invoke GetClassName, hWnd, addr g_szIconText, sizeof g_szIconText
invoke MessageBox, NULL, addr g_szIconText, addr g_szIconText, MB_OK
mov eax, TRUE
ret
EnumSubCtl endp ;/////////////////////////////////////////////////////////////////////////////////
; Function: Get the count of icon in system tray
;/////////////////////////////////////////////////////////////////////////////////
GetSysTrayIconCount proc
invoke SendMessage,g_hSysTray, TB_BUTTONCOUNT, 0, 0
mov g_dwTrayIconCount, eax
ret
GetSysTrayIconCount endp
;///////////////////////////////////////////////////////////////////////
; Function: Enum the icon in system tray
;///////////////////////////////////////////////////////////////////////
EnumSysTrayIcon proc
local dwProcID, dwReaded: dword
local hProcess: HANDLE
local pMem: dword
invoke GetSysTrayIconCount
invoke GetWindowThreadProcessId, g_hSysTray, addr dwProcID
invoke OpenProcess, PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE, FALSE, dwProcID
mov hProcess, eax
invoke VirtualAllocEx, hProcess, NULL, 1024, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE
mov pMem, eax
xor eax, eax
.while (eax < g_dwTrayIconCount)
push eax
invoke SendMessage, g_hSysTray, TB_GETBUTTON, eax, pMem
invoke ReadProcessMemory, hProcess, pMem, addr g_stTbButton, sizeof g_stTbButton, addr dwReaded
invoke SendMessage, g_hSysTray, TB_GETBUTTONTEXT, g_stTbButton.idCommand, pMem
inc eax ; If fail, the return value is -1
jz @F ; Fail, skip
invoke ReadProcessMemory, hProcess, pMem, addr g_szIconText, sizeof g_szIconText, addr dwReaded
invoke MessageBox, NULL, addr g_szIconText, addr g_szAppName, NULL
@@:
pop eax
inc eax
.endw
invoke VirtualFreeEx, hProcess, pMem, 0, MEM_RELEASE
invoke CloseHandle, hProcess
ret
EnumSysTrayIcon endp
end start Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1795880
能力值:
( LV9,RANK:380 )
15 楼
LZ,如果有个汇编版本,那就更加完美了