2008年10月26日
为什么写这个:
1,像我这么爱干净的人,当然不能容忍和MM聊天的时候,看到一个内衣广告在上面一闪一闪,这不引诱老纳么;
2,为什么不用其它外挂?珊瑚虫已S,再没用过其它。现有的外挂实现了一些我不想要的功能,看IP也没必要,聊天的都是熟人。另外,不知道它做了些什么事情;
3,打发这个无聊的周末。
怎样实现:
1,万能的HOOK
现在用到的是全局的SHELL HOOK,Hook的是窗口创建完成的消息;
g_hShellHook = SetWindowsHookEx( WH_SHELL,
(HOOKPROC)ShellHook,
g_hInstance,
0);
ShellHook 的实现如下:
static LRESULT CALLBACK ShellHook(UINT nCode, WPARAM wParam, LPARAM lParam)


{
if(nCode < 0)
goto CallOrg;
if( HSHELL_WINDOWCREATED == nCode )

{
if( !isQQWnd( (HWND)wParam ) )
goto CallOrg;
EnumChildWindows( (HWND)wParam, EnumChildProc, (LPARAM)0 );
}
CallOrg:
return CallNextHookEx( g_hShellHook, nCode, wParam, lParam);
}

在收到窗口创建后的消息时,就判断这个窗口是不是QQ的,这里用到了 GetWindowThreadProcessId ,它返回窗口相关的进程ID
BOOL isQQWnd(HWND hWnd)


{
if( g_pContext == NULL )
return FALSE;

if( g_dwQQProcessID == 0 )
g_dwQQProcessID = GetQQProcessID();
DWORD dwWndProcessID;
if( GetWindowThreadProcessId( hWnd, &dwWndProcessID ) == 0 )
return FALSE;
return dwWndProcessID == g_dwQQProcessID;

}

然后枚举它的子窗口,看它的子窗口有没有广告控件,有的话就给子控件发送个WM_CLOSE的消息.
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam )


{
DWORD dwID = GetDlgCtrlID( hwnd );
if( dwID == 0x3e9 )

{
HWND hPrarent = GetParent( hwnd );
PostMessage(hwnd, WM_CLOSE, 0, 0 );
Sleep( 10 );
PostMessage(hPrarent, WM_PAINT, 0, 0 );
}
else if( dwID == 0x643f )

{
PostMessage(hwnd, WM_CLOSE, 0, 0 );
}

return TRUE;
}

其中的两个硬编码是用 spy++ 分析出来的,可能因为版本的不同,会有差异。所以我不确定能不能关闭其它版本的QQ广告。我使用的版本是QQ2008贺岁版。
--------------------------------------------------------------------------
后记:
尽管实现的技术很简单,但还是花了我大半天的时间. 写完之后觉得枚举子窗口的方式太低效, 或者还有其它高效点的方式。另外还有全局钩子,可能没有必要。如果下午周末持续无聊,我会尝试改进一下。
QQ的聊天对话框很简单,不像MSN的对话框,铁板一块,用spy++啥都看不到.但是可以用 AccExplorer 分析.想在MSN的对话框上加点东西进去,实现起来很困难。对这方面有研究的同学不妨与我讨论一下实现,一起学习、进步。
代码的行数没数,有效代码估计也就百把行吧,呵呵,我承认我是标题党。
附: 源代码 + bin
2008年2月19日
# -*- coding: cp936 -*-
import re
from os.path import dirname
import shutil
import os
pattern = '^#\s*include\s+(<)(.+)(>)(.*)$'
prog = re.compile(pattern)
find_sets = []
def create_dir(file_dir):
#print dirname(_dir);
_dir = dirname(file_dir)
if not os.path.exists(_dir):
os.makedirs(_dir)
def copyHeadFile(root_dir, src_path, des_path, deep = 0):
if((root_dir + src_path) in find_sets):
return
if( not os.path.exists(root_dir + src_path) ):
return
create_dir(des_path + src_path)
shutil.copyfile(root_dir + src_path, des_path + src_path);
find_sets.append(root_dir + src_path)
src_file = open(root_dir + src_path, 'r')
print ''.rjust(deep) + des_path + src_path
for line in src_file:
if prog.search(line):
line = re.sub('(^#\s*include\s+(<))|(>)(.*)$', '', line)
line = line.replace('/', '\\')
line = line.rstrip('\n')
copyHeadFile( root_dir, line, des_path, (deep + 4))
copyHeadFile("D:\\Program Files\\Microsoft Visual Studio 8\\VC\\include\\", "stdafx.h", "d:\\need_hpp\\" )
Python偶而玩玩也很爽。 这个脚本的来例:我写的demo用到了不少boost的东西,代码交给领导检查的时候,又不能把整个boost 都拷贝给他,这个脚本能把引用到的头文件导出到指定的目录里面。
2007年11月23日
2007年11月22日星期四 下午7时29分
外面已经一片7黑。室友H君还没回来,他怕一回来就玩游戏。我不怕玩游戏,一个人,在哪都一样,只喜欢安静。
一段音乐,一杯咖啡,一本书,一段代码,一个晚上。有点喜欢这种感觉了。
乐心说得对,要对生活有要求。呵呵。 看来我的要求也不高。
上次星期公司新员工培训,内容是“我的五样”,“七个习惯”。我的五样,就是先写下自己最在乎的五样东西,然后在忧怨的音乐声中,一个一个的划去,只留下最后一个,以期帮你找到自己的目标。 我只写了三样,而且一样都没有划去,我觉得它们并不矛盾,而且那就是我生命的意义。想知道是哪三样吗? 嘿嘿,我可不告诉你。 接着就是《高效能人士的七个习惯》,这本书我早就看过电子版的,当时一边看一边想:这不就是说我的习惯吗?kao。 讲课的老师水平一般,很能忽悠,还不如给我们放陈安之老师的成功学。一堂培训下来,也没什么长进,浪费我一下午的时间。完了之后,集体去楼下的西餐厅吃蛋炒饭,味道还不错。这个星期又有培训,也不知道能不能吃到好吃的蛋炒饭。
想想最近还有什么有趣的事。前天项目组搞每月一次的聚餐,我们一行八人,去了附近的一家小肥羊。涮涮涮,很开心。喝了白酒+啤酒。回到宿舍,晕呼呼的睡着了,没盖被子,结果睡着睡着,半夜里两鼻孔被堵起来了,难受,翻出一粒感康,服下,半梦半醒到天亮。
2007年11月14日
今天是星期五,来广州那天是星期二,离开TW是上个星期五,离开SPL是上个星期二。离开SPL的时候,实在没有想到自己会在这个陌生的地方开始谋生。短短的十来天,变化的东西很多,而不变的只有一心想成为优秀的程序员的理想(我想,这也是变化的原因)。
为什么离开SPL:
一、 呆了两年多,对外面的事物很好奇,有些东西,如果不身临其境的去体会,永远无法知道;
二、 真的想知道,一个大的项目是怎么被分割成很多小部分,然后有条不紊被执行,然后一次交付,然后有计划的升级、维护;
三、 不喜欢三天两头的为程序加新功能;
四、 不喜欢一个星期上六天班;
五、 不喜欢宿舍太吵,一两点钟还被关门的声音震醒;
六、 不喜欢技术没有进步,整天干同样的活(一个游戏天天玩通关,你还喜欢玩吗?);
七、 不喜欢一个人在战斗的时候,看着旁边的胖子偷懒,而且工资比你还高。
为什么离开TW:
一、对烟厂的业务实在没有兴趣,做得好还好,做得不好,被开除了,我应该去干嘛?我可以去干嘛?当初花那么多时间去学习的东西,然后离开的时候,一无是处,是不是浪费自己的时间;
二、对工控不感兴趣;看着那些电气设备,我想自己如果在这行发展,不会比那个有电子和计算机双学位的同学更牛;
三、对带头大哥的技术水平感到失望,尤其是看了他写的代码之后,本来一个很简单的东西,经过他的手就变得异常复杂,还故作高深。整个程序充满了硬编码,而且把逻辑和界面混淆在一起;可能他做为带头大哥,在别的地方,如业务、工控方面有所建树,但是我对那些一点兴趣都没,我怎能强迫自己跟着你?
四、感觉不会有太大的长进,我一向认为写低级界面是体力活;
五、不喜欢在烟厂职工面前装孙子讨好他们,凭什么?我在SPL还是爷呢。
够了,做自己不喜欢的工作,就像出卖自己的灵魂。不如早点结束,趁自己有选择的能力。
辗转来到广州:
只所以在这待着是因为:
一、我喜欢系统底层,我以前就喜欢,只是没有时间去了解;
二、项目组的同事相处起来不错,没什么架子,很好交流;
三、广州和长沙的消费似乎差不多,而且这公司还答应包住,所以,每月能剩下的钱就多点了。
四、即便是被开除了,在广州这地,混个饭似乎也不难,如果没有虚度时光的话。这边IT公司挺多的;
五、趁着年轻,想出来见见世面(如果这也是理由的话);
自己做出的这些决定,放了一些人的鸽子,我向你们道歉,你们都是好人,我辜负了你们对我的信任,那是因为我的优柔寡断和性格上的其它缺陷引起的。这里提到的一些人被定义为:TW的HR和YM大哥,还有雨花亭的杨大哥。
HR在给我办入职的时候和我说:你不会做两三天就走人吧?我说:应该不会吧。可是我走了,为了我所谓的理想,我对不起你;
YM:我们最后一次分开时,我对你说:做这个主要是对业务的理解吧?你拍拍我的肩膀对我说:所以你要每天下车间去看看。我知道你是为我好,如你所说,在长沙找个这样的工作不容易。可这并不是我想要的生活,也许在将来的某天,我会后悔自己失去了一次稳定的机会,但,决不是现在。再次向你说声对不起。
雨花亭的杨大哥:准备和你合租房子的前一天,我离开长沙了,所以你的鸽子不得不放。
想起来是自己的不对,就觉得挺难过,而且从心里开始BS自己,如果你看到这些,也请BS一下我,让我能在你BS的眼神中吸取教训,如果下次有类似的事情,会处理得好。 写着写着就觉得有些压抑,而我也不知道怎样才能不压抑些。
放一些图片吧,作为记录,而这一切,都已经是回忆。
2007年8月9日
今天发生一件有趣的事情,我要为程序换个图标..
程序有很多ICO资源,例如 ICO_1,ICO_2,ICO_3,ICO_4....
我新增了一个APP_ICO(程序图标要换成这个). 我把以前的图标删了,然后ID改为以前那个,可是ReBuild之后,程序图标竟然是 ICO_1。很奇怪。
找了半天,发现ICO_1的ID值是最小的。于是我把APP_ICO的ID值改为最小。Rebuild.终于把程序图标给换了过来。
2006年12月13日
这样的帖子,不知道可不可以放到首页..如果不行,麻烦管理员清理. 谢谢.
HANDLE GetQQProcess();
bool
SeachQQNumber(HANDLE _hProcess,
string
&
strQQ);
int
_tmain(
int
argc, _TCHAR
*
argv[])

{
HANDLE hProces
=
GetQQProcess() ;
if
(hProces
==
NULL)
cout
<<
"
No run QQ!
"
<<
endl;

string
strQQ;
SeachQQNumber(hProces,strQQ);
cout
<<
strQQ
<<
endl;
system(
"
pause
"
);
return
0
;
}
bool
SeachQQNumber(HANDLE _hProcess,
string
&
strQQ)

{
SuspendThread(_hProcess);
DWORD dwBaseAddress;
MEMORY_BASIC_INFORMATION mbi;

char
process_mem[
4096
]
=
{
0
}
;
DWORD number_of_bytes_read
=
0
;
SYSTEM_INFO si;
GetSystemInfo(
&
si);
dwBaseAddress
=
(DWORD)si.lpMinimumApplicationAddress;
while
(dwBaseAddress
<
(DWORD)si.lpMaximumApplicationAddress)

{
mbi.BaseAddress
=
(LPVOID)dwBaseAddress;
VirtualQueryEx(_hProcess, (LPVOID)dwBaseAddress,
&
mbi,
sizeof
(mbi));
dwBaseAddress
=
(DWORD)mbi.BaseAddress
+
mbi.RegionSize;
if
(mbi.State
!=
MEM_COMMIT
||
mbi.AllocationProtect
!=
PAGE_READWRITE)
//
跳过未分配或不可读写的区域
{
continue
;
}
//
搜索
for
(DWORD i
=
(DWORD)mbi.BaseAddress; i
<
dwBaseAddress; i
+=
4096
)

{
if
(
!
ReadProcessMemory(_hProcess,LPCVOID(i),process_mem,
4096
,
&
number_of_bytes_read))
break
;
for
(
int
j
=
0
;j
<
4096
-
9
;j
++
)

{
if
(
!
memcmp(
&
process_mem[j],
"
\\MsgEx.db
"
,
9
) )

{
//
printf("begin\n");
for
(
int
k
=
j
-
1
; k
>
j
-
12
; k
--
)

{
if
(process_mem[k]
>=
'
0
'
&&
process_mem[k]
<=
'
9
'
)

{
strQQ
=
process_mem[k]
+
strQQ;
}
else
break
;
}
if
(strQQ.length())

{
ResumeThread(_hProcess);
return
true
;
}
}
}
}
}
ResumeThread(_hProcess);
return
false
;
}
HANDLE GetQQProcess()

{
PROCESSENTRY32 pe;
pe.dwSize
=
sizeof
(PROCESSENTRY32);
HANDLE hSnapshot
=
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
0
);
Process32First(hSnapshot,
&
pe);

do
{
if
(
!
_tcsicmp(pe.szExeFile,_T(
"
qq.exe
"
)))

{
CloseHandle(hSnapshot);
return
OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe.th32ProcessID);
}
pe.dwSize
=
sizeof
(PROCESSENTRY32);
}
while
(Process32Next(hSnapshot,
&
pe));
CloseHandle(hSnapshot);
return
NULL;
}
摘要: #include
"
stdafx.h
"
#include
<
iostream
>
#include
"
ace/INET_Addr.h
"
#include
...
阅读全文
2006年11月22日
最近工作比较闲. 因此看了一些书,一些电影.
<设计模式>开始看第二遍.. 感觉实际开发中用不着.. 来公司一年多,项目实在少.真想找个高人带着我乘风破浪..不说乘风破浪,平时有个人讨论都好.
看了一会儿<wxWidgets>. 随便一个对话框程序都占了几M内存,文件牛大..算了. 跨平台现在还用不着,放弃.
看了一会儿<病毒入门>.汇编看得想死..罗云彬老师的Win32汇编书写得像个<Window程序设计>的翻版.
看了一会儿<Python>. .现在的开发用不着.. 屠龙之技.
昨天发现用Flash做界面真是好. 又漂亮又简单, 现在的Flash8.0可以很好的和本地程序交互了. 感觉是黑暗中的明灯.
看名字叫<越狱>的电影. 觉得外国连续剧可看性很高..T-Bag是只打不死的小强. 麦克.Scofield真牛. 外国政治也黑暗. 外国监狱真好. 司法制度真体帖.
觉得自己会用的形容词很少.尽是些 "真","很","好"
哈哈.
这周末王斌和周芬结婚了. 我要回家参加他们的婚礼. 心情有些许复杂. 难以名状. . 尽管如此,我还是要给他们献上杨某人最诚挚的祝福. 无论如何,一定要幸福.
2006年11月7日
如果我能存时间入瓶 我最想做的事情 就是保存每个日子 直到我们老去
只为能与你再次共度 如果我能让时光永驻 我会珍藏每个日子 然后 再一次 与你共度
你找到你想做的事情时 却总是发现 已没有足够时间 我历经寻寻觅觅 才发现
你就是那个 我愿共度一生的人 如果我有盒子 盛着从未实现的梦与希望
那么它将会空荡荡 除了那些 你为我圆梦的记忆
2006年10月27日
一大早醒来,想了很多. 睡不着.
不能再玩游戏了.希望部门的技术氛围能浓一些, 在一起,不是讨论游戏,而是讨论技术.
玩了这么些年游戏,得到了什么,失去了什么.不想再作追究.只是不想再为了它失去一些宝贵的东西,譬如时间.
2006年10月25日
例 7.14. 处理开始字符
...
>>> phonePattern = re.compile(r'^\D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') 1
>>> phonePattern.search('(800)5551212 ext. 1234').groups() 2
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups() 3
('800', '555', '1212', '')
>>> phonePattern.search('work 1-(800) 555.1212 #1234') 4
>>>
| 1 |
这个正则表达式和前面的几乎相同,除了在第一个记忆组(区号)前面匹配\D*,0或者多个非数字字符。注意,此处你没有记忆这些非数字字符(他们没有被括号括起来)。如果你发现他们,只是跳过他们,接着只要匹配上就开始记忆区号。
|
| 2 |
你可以成功的解析电话号码,即使在区号前面有一个左括号。(在区号后面的右括号也已经被处理,它被看成非数字字符分隔符,由第一个记忆组后面的 \D*匹配。)
|
| 3 |
进行仔细的检查,保证你没有破坏前面能够匹配的任何情况。由于首字符是完全可选的,这个模式匹配字符串的开始,接着是0个非数字字符,接着是一个有三个数字字符的记忆组(800),接着是1个非数字字符(连字符),接着是一个有三个数字字符的记忆组(555),接着是1个非数字字符(连字符),接着是一个有四个数字字符的记忆组(1212),接着是0个非数字字符,接着是一个有0个数字位的记忆组,最后是字符串的结尾。
|
| 4 |
此处是正则表达式让我产生了找一个硬东西挖出自己的眼睛的冲动。为什么这个电话号码没有匹配上?因为在它的区号前面有一个 1,但是你认为在区号前面的所有字符都是非数字字符(\D*)。 Aargh. |
2006年10月24日
<载自:Dive Into Python>
你可能经常看到罗马数字,即使你没有意识到他们。你可能曾经在老电影或者电视中看到他们(“版权所有 MCMXLVI” 而不是 “版权所有1946”),或者在某图书馆或某大学的贡献墙上看到他们(“成立于 MDCCCLXXXVIII”而不是“成立于1888”)。你也可能在某些文献的大纲或者目录上看到他们。这是一个表示数字的系统,他能够真正回溯到远古的罗马帝国(因此而得名)。
在罗马数字中,利用7个不同字母进行重复或者组合来表达各式各样的数字。
-
I = 1
-
V = 5
-
X = 10
-
L = 50
-
C = 100
-
D = 500
-
M = 1000
下面是关于构造罗马数字的一些通用的规则的介绍:
- 字符是叠加的。 I表示1, II表示2, 而III表示3. VI 表示 6 (字面上为逐字符相加, “5 加 1”), VII 表示 7, VIII 表示 8.
- 能够被10整除的字符(I, X, C, 和 M)至多可以重复三次. 对于4, 你则需要利用下一个最大的能够被5整除的字符进行减操作得到,你不能把4 表示成 IIII; 而应表示为 IV (比“5小 1”)。数字40写成XL (比50小10), 41 写成 XLI, 42 写成 XLII, 43 写成 XLIII, 而 44 写成 XLIV (比50 小10, 然后比5小1).
- 类似的,对于数字 9,你必须利用下一个能够被10整除的字符进行减操作得到: 8 表示为 VIII, 而 9 则表示为 IX (比10 小1), 而不是 VIIII (因为字符I 不能连续重复四次)。数字90 表示为 XC, 900 表示为 CM.
- 被5整除的字符不能重复。数字10 常表示为X, 而从来不用VV来表示。数字100常表示为C, 也从来不表示为 LL.
- 罗马数字经常从高位到低位书写,从左到右阅读,因此不同顺序的字符意义大不相同。DC 表示 600; 而CD 是一个完全不同的数字(为400, 也就是比500 小100). CI 表示 101; 而IC 甚至不是一个合法的罗马字母(因为你不能直接从数字100减去1; 比需要写成XCIX, 意思是 比100 小10, 然后加上数字9,也就是比 10小1的数字).
|
| 本章译者注:“被5整除的数”这个译法并不严谨,因为所有被10整除的数也能够被5整除,此处表达的含义是:那些包含有5的含义的罗马数字字符。 |
2006年10月20日