library kbhook; { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. } uses windows; var hHk: HHOOK; BFirst:Boolean=True; //{$R*.res} procedure ModMemData(); var pData: pointer; dwOldProtect: DWORD; mbi_thunk: TMemoryBasicInformation; begin pData := pointer($00403296); //查询页信息。 VirtualQuery(pData, mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); //改变页保护属性为读写。 VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, mbi_thunk.Protect); //清零。 PByte(pData)^:=0; //恢复页的原保护属性。 VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, dwOldProtect); end; function keyHookProc(nCode: Integer; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; const _KeyPressMask = $80000000; begin Result :=0; if nCode <0 then begin Result := CallNextHookEx(hhk, nCode, wParam, lParam); Exit; end else begin if BFirst then // 侦测 Ctrl + B 组合键 //if ((lParam and _KeyPressMask) =0) and (GetKeyState(vk_Control) <0) and // (wParam = VK_F2) then //(GetKeyState(vk_Control) <0) and (wParam =Ord('B')) then begin Result :=1; ModMemData; BFirst:=False; //MessageBox(0,'ok','',MB_OK); // MessageBox(0, pchar(GetModuleName(GetModuleHandle(nil))), // pchar(inttostr(GetCurrentThread)),0); end; end; end; function SetKbHook(threadid: DWORD): boolean; stdcall; export; //外部调用 begin if threadid <>0 then begin hHk := SetWindowsHookEx(WH_GETMESSAGE,@keyHookProc, HInstance, threadid); result := hhk <>0; end else begin Result := UnHookWindowsHookEx(hHk); end; BFirst:=True; end; exports SetKbHook; end.
LineGame.pas
...{******************************************************************************* Copyright (C), 2004, 风月工作室. 作者: 追风逐月 版本: 1.0 日期: 2005年12月28日 描述: QQ连连看游戏控制类 修改历史: 徐明 2005/12/281.0 创建该文件 ... ********************************************************************************} unit LineGame; interface uses Windows, Messages, ShellAPI, Classes; const MAP_HLENGTH =19; MAP_VLENGTH =11; MAPCOUNT =100; gLeft =16; gTop =184; hwidth =31; vWidth =35; type TLineGame =class private Maps: array[0..MAP_VLENGTH -1, 0..MAP_HLENGTH -1] of integer; gh: THandle; RectA: TRect; LineMap: TStringList; ptLines: array[1..MAPCOUNT] of Tlist; FGameThreadID:integer; procedure SetPtLines; function CanConnect(P1, P2: TPoint): boolean; function CanLine(P1, P2: TPoint): Boolean; function isEmptyPt(pt: TPoint): boolean; function GetMapIndex(Color: integer): integer; function LeftMapCount: integer; procedure GetColor(x, y: Integer; var col: Cardinal); function GetColorMx(i, j: integer): Cardinal; function isBackGround(Color: Integer): boolean; procedure SendMouse(x1, y1, x2, y2: Integer); function GetMapPos(i, j: integer): Tpoint; function Search(var P1, P2: TPoint): boolean; function isSameMap(Color1, Color2: integer): boolean; procedure GetBox; procedure SetMemData(hnd:THandle); public constructor Create; destructor Destroy; override; procedure AutoStart; procedure RunStep; procedure KillAll; end; function SetKbHook(threadid:DWORD):bool;stdcall; external 'kbhook.dll' ; implementation function StrToInt(const S: string): Integer; var E: Integer; begin Val(S, Result, E); //if E <> 0 then ConvertErrorFmt(@SInvalidInteger, [S]); end; ...{ TLineGame } ...{************************************************* 函数名: TLineGame.GetColor 描 述: 获取指定位置(屏幕坐标)的颜色值 参 数: x, y: Integer; var col: Cardinal 返回值: None *************************************************} procedure TLineGame.GetColor(x, y: Integer; var col: Cardinal); var WindowDC: THandle; begin WindowDC := GetWindowDC(gh); col := GetPixel(WindowDC, x, y); ReleaseDC(gh, WindowDC); end; ...{************************************************* 函数名: TLineGame.GetColorMx 描 述: 获取指定位置(对子矩阵坐标)的评估值 参 数: i, j: integer 返回值: Cardinal - 评估值 *************************************************} function TLineGame.GetColorMx(i, j: integer): Cardinal; var x, y: integer; col1, col2: Cardinal; begin x := gLeft +14+ hwidth * i; y := gTop +18+ vwidth * j; GetColor(x, y, col1); x := x -6; GetColor(x, y, col2); result := col1 + col2; end; ...{************************************************* 函数名: TLineGame.Search 描 述: 搜索可以消除的对子的位置 参 数: var P1, P2: TPoint 可以消除的对子坐标 返回值: boolean *************************************************} function TLineGame.Search(var P1, P2: TPoint): boolean; var i, j, k: integer; LineList: TList; begin result :=false; for i := Low(ptlines) to High(ptlines) do begin LineList := ptLines[i]; for j :=0 to LineList.Count -1do for k := j +1 to LineList.Count -1do begin p1 := pPoint(LineList.Items[j])^; p2 := pPoint(LineList.Items[k])^; if CanConnect(p1, p2) then begin result :=true; Dispose(LineList.Items[k]); LineList.Delete(k); Maps[p1.X, p1.Y] :=-2; Dispose(LineList.Items[j]); LineList.Delete(j); Maps[p2.X, p2.Y] :=-2; exit; end; end; end; end; ...{************************************************* 函数名: TLineGame.CanConnect 描 述: 判断两点是否连通 参 数: P1, P2: TPoint 返回值: boolean *************************************************} function TLineGame.CanConnect(P1, P2: TPoint): boolean; var mpt1, mpt2: TPoint; begin result :=false; if (p1.x = p2.X) and (p1.y = p2.Y) then exit; //可以直线相连 Result := Canline(P1, p2); if result then exit; //一个拐点 mpt1.X := p1.X; mpt1.Y := p2.Y; Result := (isEmptyPt(mpt1)) and Canline(P1, mpt1) and Canline(mpt1, P2); if result then exit; mpt1.X := p2.X; mpt1.Y := p1.Y; Result := (isEmptyPt(mpt1)) and Canline(P1, mpt1) and Canline(mpt1, P2); if result then exit; //两个拐点 //以p1为基准 //获取y坐标方向的空点 mpt1.y := p1.Y; mpt2.Y := p2.Y; mpt1.X := p1.X -1; while (mpt1.x >-1) and (isEmptyPt(mpt1)) do begin mpt2.X := mpt1.X; if isEmptyPt(mpt2) then result := CanLine(mpt1, mpt2) and CanLine(mpt2, p2); if result then exit; dec(mpt1.X); end; mpt1.X := p1.X +1; while (mpt1.x < MAP_VLENGTH) and (isEmptyPt(mpt1)) do begin mpt2.X := mpt1.X; if isEmptyPt(mpt2) then result := CanLine(mpt1, mpt2) and CanLine(mpt2, p2); if result then exit; inc(mpt1.X); end; //获取x坐标方向的空点 mpt1.x := p1.x; mpt2.x := p2.x; mpt1.y := p1.y -1; while (mpt1.y >-1) and (isEmptyPt(mpt1)) do begin mpt2.y := mpt1.y; if isEmptyPt(mpt2) then result := CanLine(mpt1, mpt2) and CanLine(mpt2, p2); if result then exit; dec(mpt1.y); end; mpt1.y := p1.y +1; while (mpt1.y < MAP_HLENGTH) and (isEmptyPt(mpt1)) do begin mpt2.y := mpt1.y; if isEmptyPt(mpt2) then result := CanLine(mpt1, mpt2) and CanLine(mpt2, p2); if result then exit; inc(mpt1.y); end; end; ...{************************************************* 函数名: TLineGame.CanLine 描 述: 判断两点是否可以直线相连 参 数: P1, P2: TPoint 返回值: Boolean *************************************************} function TLineGame.CanLine(P1, P2: TPoint): Boolean; var i: integer; begin result :=false; // 横1....1 if (p1.y = p2.Y) then begin if p1.x > p2.X then begin result := CanLine(P2, P1); end else begin result :=true; for i := p1.X +1 to p2.X -1do begin result := Maps[i, p1.Y] =-2; if not result then exit; end; end; end elseif (p1.x = p2.x) then // 竖 begin if p1.y > p2.y then begin result := CanLine(P2, P1); end else begin result :=true; for i := p1.y +1 to p2.y -1do begin result := Maps[p1.x, i] =-2; if not result then exit; end; end; end; end; ...{************************************************* 函数名: TLineGame.isEmptyPt 描 述: 是否空白点 参 数: pt: TPoint 返回值: boolean *************************************************} function TLineGame.isEmptyPt(pt: TPoint): boolean; begin result := Maps[pt.X, pt.Y] =-2; end; ...{************************************************* 函数名: TLineGame.Create 描 述: 创建TlineGame类 参 数: None 返回值: None *************************************************} constructor TLineGame.Create; var i: integer; Res: TResourceStream; begin LineMap := TStringList.Create; Res := TResourceStream.Create(HInstance,'SRC1', PChar('FILE1')); LineMap.LoadFromStream(res); Res.Free; for i :=1 to MAPCOUNT do begin ptLines[i] := TList.Create; end; end; ...{************************************************* 函数名: TLineGame.Destroy 描 述: 消耗TLineGame类 参 数: None 返回值: None *************************************************} destructor TLineGame.Destroy; var i: integer; begin LineMap.Free; for i := MAPCOUNT downto 1do begin ptLines[i].Free; end; SetKbHook(0); end; ...{************************************************* 函数名: TLineGame.SetPtLines 描 述: 根据矩阵设置对子队列 参 数: None 返回值: None *************************************************} procedure TLineGame.SetPtLines; var i, j: integer; pt: pPoint; mapValue: integer; begin try for i :=1 to MAPCOUNT do for j := ptLines[i].Count -1 downto 0do begin Dispose(ptLines[i].Items[j]); ptLines[i].Delete(j); end; for i :=0 to MAP_VLENGTH -1do for j :=0 to MAP_HLENGTH -1do begin new(pt); pt.X := i; pt.Y := j; mapValue := Maps[i, j]; if mapValue <>-2 then begin ptLines[mapValue].Add(pt); end; end; except end; end; ...{************************************************* 函数名: TLineGame.isSameMap 描 述: 判断两点是否相似,如相似则认为是同一类型的点 参 数: Color1, Color2: integer 返回值: boolean *************************************************} function TLineGame.isSameMap(Color1, Color2: integer): boolean; var r1, g1, b1: Integer; r2, g2, b2: Integer; begin r1 := GetRValue(Color1); g1 := GetGValue(Color1); b1 := GetBValue(Color1); r2 := GetRValue(Color2); g2 := GetGValue(Color2); b2 := GetBValue(Color2); Result := (abs(r1 - r2) <5) and (abs(g1 - g2) <5) and (abs(b1 - b2) <5) end; ...{************************************************* 函数名: TLineGame.GetMapIndex 描 述: 根据颜色值,判断其所属的类型队列的位置 参 数: Color: integer 返回值: integer *************************************************} function TLineGame.GetMapIndex(Color: integer): integer; var i: integer; Color1: integer; begin result :=-2; for i :=0 to LineMap.Count -1do begin Color1 := StrToInt(LineMap.Names[i]); if isSameMap(Color, Color1) then begin result := strtoint(LineMap.ValueFromIndex[i]); exit; end; end; end; ...{************************************************* 函数名: TLineGame.LeftMapCount 描 述: 计算ptLine中剩余的点数 参 数: None 返回值: integer *************************************************} function TLineGame.LeftMapCount: integer; var i: integer; begin Result :=0; for i :=1 to MAPCOUNT do begin inc(Result, ptLines[i].Count); end; end; ...{************************************************* 函数名: TLineGame.GetBox 描 述: 获取游戏界面布局数据 参 数: None 返回值: None *************************************************} procedure TLineGame.GetBox; var i, j: Integer; color1: Cardinal; begin gh := FindWindow(nil, PChar('QQ连连看')); //生成数组 GetWindowRect(gh, Recta); for i :=0 to MAP_VLENGTH -1do for j :=0 to MAP_HLENGTH -1do begin color1 := GetColorMx(j, i); if isBackGround(color1) then maps[i, j] :=-2 else maps[i, j] := GetMapIndex(color1); end; end; ...{************************************************* 函数名: TLineGame.isBackGround 描 述: 判断是否游戏中的背景 参 数: Color: Integer 返回值: boolean *************************************************} function TLineGame.isBackGround(Color: Integer): boolean; var r, g, b: Integer; begin r := GetRValue(Color); g := GetGValue(Color); b := GetBValue(Color); Result := (Abs(110- r) <20) and (abs(154- g) <20) and (abs(236- b) <20); end; ...{************************************************* 函数名: TLineGame.GetMapPos 描 述: 获取对子矩阵中点在游戏中的位置 参 数: i, j: integer 返回值: Tpoint *************************************************} function TLineGame.GetMapPos(i, j: integer): Tpoint; begin result.x := Recta.Left + gLeft +16+ hwidth * j; result.y := recta.Top + gTop +18+ vwidth * i; end; ...{************************************************* 函数名: TLineGame.SendMouse 描 述: 模拟发送消除对子的消息 参 数: x1, y1, x2, y2: Integer 返回值: None *************************************************} procedure TLineGame.SendMouse(x1, y1, x2, y2: Integer); var pos1, pos2: TPoint; Recta: TRect; begin GetWindowRect(gh, Recta); pos1 := GetMapPos(x1, y1); PostMessage(gh, WM_LBUTTONDOWN, 0, MakeLong(pos1.X - Recta.Left, pos1.y - Recta.Top)); Pos2 := GetMapPos(x2, y2); PostMessage(gh, WM_LBUTTONDOWN, 0, MakeLong(pos2.X - Recta.Left, pos2.y - Recta.Top)); end; ...{************************************************* 函数名: TLineGame.RunStep 描 述: 消除一组对子 参 数: 返回值: None *************************************************} procedure TLineGame.RunStep(); var p1, p2: TPoint; begin gh := FindWindow(nil, PChar('QQ连连看')); SetMemData(gh); GetBox; SetPtLines; if Search(p1, p2) then begin SendMouse(p1.X, p1.Y, p2.X, p2.Y); end; end; ...{************************************************* 函数名: TLineGame.KillAll 描 述: 消除所有对子 参 数: 返回值: None *************************************************} procedure TLineGame.KillAll(); var p1, p2: TPoint; SearchFail: Boolean; begin gh := FindWindow(nil, PChar('QQ连连看')); SetMemData(gh); GetBox; SetPtLines; repeat SearchFail :=true; while Search(p1, p2) do begin SearchFail := False; SendMouse(p1.X, p1.Y, p2.X, p2.Y); end; until (LeftMapCount =0) or SearchFail; end; ...{************************************************* 函数名: TLineGame.AutoStart 描 述: 自动开始游戏 参 数: None 返回值: None *************************************************} procedure TLineGame.AutoStart; begin gh := FindWindow(nil, PChar('QQ连连看')); PostMessage(gh, WM_LBUTTONDOWN, 0, MakeLong(684, 532)); PostMessage(gh, WM_LBUTTONUP, 0, MakeLong(684, 532)); end; procedure TLineGame.SetMemData(hnd: THandle); var ThreadProcessID:integer; begin ThreadProcessID:=GetWindowThreadProcessId(hnd,nil); if ThreadProcessID=FGameThreadID then exit; FGameThreadID:=ThreadProcessID ; SetKbHook(FGameThreadID); end; end.
QQLLK.dpr
...{************************************************* Copyright (C), 2004, 风月工作室. 作者: 追风逐月 版本: 1.0 日期: 2005年02月01日 描述: 修改历史: 徐明 2005/02/011.0 创建该文件 ... *************************************************} ...{$J+} program QQLLK; uses Windows, Messages, SysUtils, ShellAPI, LineGame in 'LineGame.pas'; ...{$R qqllk.res} const //资源常量定义// ;不要修改! MAINICON ='MAINICON'; IDD_MAINDLG =1000; MAIN_SINGLE =1002; MAIN_ALL =1003; MAIN_OPTION =1006; MAIN_ABOUT =1001; MAIN_EXIT =1004; IDD_ABOUTDLG =3000; ABOUT_OK =3001; ABOUT_CLOSE =3002; ABOUT_FILE =3003; ABOUT_AUTHOR =3004; ABOUT_MEMO =3005; IDD_OPTIONDLG =2000; OPTION_OK =2001; OPTION_CANCEL =2002; OPTION_ABOUT =2003; OPTION_CLOSE =2004; OPTION_AUTOSTART =1000; OPTION_AUTOTOOLS =1001; OPTION_RANDOM =1006; OPTION_COMPUTER =1007; OPTION_TIMER =1008; const //常量数据声明// (*颜色设定*) //clBackground = $8B190B; //背景颜色 clBackground = $87D34; //背景颜色 clText = $E4E4E4; //文字颜色 //clFrom = $871200; //标题栏渐变起始颜色 //clTo = $808080; //标题栏渐变结束颜色 clFrom = $87D34; //标题栏渐变起始颜色 clTo = $808080; //标题栏渐变结束颜色 ID_HOTKEYF2 =200; //热键F2 ID_HOTKEYF3 =300; //热键F3 ID_HOTKEYCTRLF4 =400; //热键CTRL+F4 szMainCaption ='QQ连连看外挂'; ...{*选项对话框*} szOptionCaption ='选项'; //关于对话框标题 (*关于对话框*) szAboutCaption ='关于 QQ连连看外挂'; //关于对话框标题 szFile ='版本 1.1.0.0'; //注册机说明 szAuthor ='『由[追风逐月]编写』'; //注册机作者 szGreet =//字幕内容每行不要超过32个字符(16个汉字) '本软件由风月工作室出品'#10#10+'〖联系方式〗'#10#10'coolchyni@gmail.com'#10#10+ '〖快捷键〗'#10#10+'F2:消除一组对子'#10'F3:消除所有对子'#10'CTRL+F4:显示/隐藏窗口'#10#10+ '〖特别感谢〗'#10#10+ '各位QQ游戏爱好者'#10'我的哥们'#10'以及所有曾帮助过我的人'#10#10+ '〖免责声明〗'#10#10'本软件属于免费软件'#10'可以自由使用'#10'由此造成的一切后果(如QQ号被封)'#10'均与作者无关'#10#10+ '〖版本信息〗'#10#10'[1.0.0.0]'#10'实现外挂程序基本功能'#10'[1.1.0.0]'#10'使用内存补丁的方法,'#10'去掉了原程序包中的连连看替换文件.'#10'' ; var BKC: HBRUSH; //背景画刷 //h_Cur: HCURSOR; //鼠标指针句柄 h_Inst: HINST; //程序图标句柄 h_Icon: HICON; //实例句柄 h_mainDlg: HWND; g_AutoStart: boolean=false; //自动开始 g_AutoTools: boolean=false; //自动使用工具 g_Random: boolean=false; //隐藏窗口 g_Computer: boolean=false; //电脑托管 g_timer: array[0..254] of char='1000'; //消除频率 g_internal:integer=1000; //定时间隔 LineGames: TLineGame; //游戏类 function LinesInStr(srcStr: string): smallint; var i: integer; begin Result :=1; for i :=0 to Length(srcStr) -1do if srcStr[i] = #10 then Result := Result +1; if Result >1 then Result := Result -1; end; // //动态显示窗体函数 procedure AnimateShow(hDlg: HWND); var Rt: TRECT; x, y, i: smallint; h_Rgn: HRGN; begin ShowWindow(hDlg, SW_HIDE); GetWindowRect(hDlg, Rt); x := (Rt.right - Rt.left) div 2; y := (Rt.bottom - Rt.top) div 2; for i :=0 to (Rt.Right div 2) do begin h_Rgn := CreateRectRgn(x - i, y - i, x + i, y + i); SetWindowRgn(hDlg, h_Rgn, True); ShowWindow(hDlg, SW_SHOW); DeleteObject(h_Rgn); end; SetWindowPos(hDlg, HWND_TOPMOST, rt.Left, rt.Top, rt.Right - rt.Left, rt.Bottom - rt.Top, 0); end; // //绘制标题栏函数 //hDC: 绘制窗体的设备环境句柄 //hIco: 标题栏图标句柄 //szCaption: 标题栏标题 //rect: 标题栏矩形区域 //clBegin: 标题栏渐变起始颜色 //clEnd: 标题栏渐变结束颜色 procedure PaintCaption(h_DC: HDC; h_Ico: HICON; const szCaption: string; rect: TRECT; clBegin: COLORREF; clEnd: COLORREF); var brush: HBRUSH; _logbrush: LOGBRUSH; //上色画刷 colorrect: TRECT; //上色矩形区域 h_font: HFONT; //标题栏字体 Haf, i: smallint; R, G, B, fr, fg, fb, dr, dg, db: smallint; begin fr := GetRValue(clFrom); //分解颜色 fg := GetGValue(clFrom); fb := GetBValue(clFrom); dr := GetRValue(clTo); dg := GetGValue(clTo); db := GetBValue(clTo); Haf := (rect.right - rect.left) div 2; //计算标题栏矩形区域中心 //设定上色矩形区域高度 colorrect.top :=0; colorrect.bottom := rect.bottom - rect.top; //建立渐变上色画刷 _logbrush.lbStyle := BS_SOLID; _logbrush.lbHatch :=0; for i :=0 to Haf do begin //设定左半上色矩形区域一次填充位置 colorrect.left := MulDiv(i, Haf, Haf); colorrect.right := MulDiv(i +1, Haf, Haf); //颜色渐变 R := fr + MulDiv(i, dr, Haf); G := fg + MulDiv(i, dg, Haf); B := fb + MulDiv(i, db, Haf); if (R >255) then R :=255; if (G >255) then G :=255; if (B >255) then B :=255; _logbrush.lbColor := RGB(R, G, B); brush := CreateBrushIndirect(_logbrush); FillRect(h_DC, colorrect, brush); //填充左半区域 //设定右半上色矩形区域一次填充位置 colorrect.left := (rect.right - rect.left) - (MulDiv(i, Haf, Haf)); colorrect.right := (rect.right - rect.left) - (MulDiv(i +1, Haf, Haf)); FillRect(h_DC, colorrect, brush); //填充右半区域 DeleteObject(brush); end; _logbrush.lbColor := $9E6A54; brush := CreateBrushIndirect(_logbrush); FrameRect(h_DC, rect, brush); //绘制标题栏边框 DeleteObject(brush); SetTextColor(h_DC, $FFFFFF); SetBkMode(h_DC, TRANSPARENT); //设定标题栏字体属性 rect.left :=2; rect.top :=2; rect.bottom := rect.Bottom -2; h_font := CreateFont(-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, '宋体'); //(宋体9号粗体字) SelectObject(h_DC, h_font); if h_Ico <>0 then //若有图标则会制图标 begin DrawIconEx(h_DC, 2, 2, h_Ico, 16, 16, 0, 0, DI_NORMAL); rect.left :=20; end; //绘制标题栏标题 DrawText(h_DC, PChar(szCaption), -1, rect, DT_SINGLELINE or DT_VCENTER); DeleteObject(h_font); end; // //绘制按钮函数 //pdis: 绘制内容结构指针 procedure DrawButton(pdis: PDRAWITEMSTRUCT); var szText: array[0..9] of char; //按钮文字 begin FillRect(pdis.hDC, pdis.rcItem, BKC); //以背景色填充按钮 SetTextColor(pdis.hDC, clText); SetBkMode(pdis.hDC, TRANSPARENT); //尚未点击,绘制按钮边框-突起状态 DrawEdge(pdis.hDC, pdis.rcItem, BDR_RAISEDOUTER, BF_RECT); GetWindowText(pdis.hwndItem, szText, sizeof(szText)); DrawText(pdis.hDC, szText, -1, pdis.rcItem, DT_SINGLELINE or DT_CENTER or DT_VCENTER); //已被按下,绘制按钮边框-凹陷状态 //if (pdis.itemState and ODS_SELECTED)=ODS_SELECTED then if (pdis.itemState and ODS_SELECTED) <>0 then begin SetTextColor(pdis.hDC, $00DDFF); DrawText(pdis.hDC, szText, -1, pdis.rcItem, DT_SINGLELINE or DT_CENTER or DT_VCENTER); DrawEdge(pdis.hDC, pdis.rcItem, BDR_SUNKENOUTER, BF_RECT); end; end; function ScrollProc(h_Wnd: HWND; Msg, wParam, lParam: DWORD): LRESULT; stdcall; var h_DC: HDC; ps: TPAINTSTRUCT; rc: TRECT; h_font: HFONT; begin case Msg of WM_PAINT: begin //绘制字幕内容 h_DC := BeginPaint(h_Wnd, ps); GetClientRect(h_Wnd, rc); SetTextColor(h_DC, clText); SetBkMode(h_DC, TRANSPARENT); h_font := CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, '宋体'); SelectObject(h_DC, h_font); DrawText(h_DC, szGreet, -1, rc, DT_CENTER); EndPaint(h_Wnd, ps); DeleteObject(h_font); end; else begin //l:=GetWindowLong(h_Wnd,GWL_USERDATA); //CallWindowProc(@l,h_Wnd,Msg,wParam,lParam); end; end; result :=1; end; function AboutProc(hDlg: HWND; Msg, wParam, lParam: DWORD): LRESULT; stdcall; const rcCaption: TRECT = (); i: smallint =0; w: smallint =0; h: smallint =0; h_Memo: HWND =0; memo: HWND =0; lines: smallint =1; //字幕行数 var h_dc: HDC; ps: TPAINTSTRUCT; pdis: PDRAWITEMSTRUCT; pt: TPOINT; rcMemo: TRECT; lUser: integer; h_Font: HFONT; h_File: HWND; begin case Msg of WM_INITDIALOG: begin GetClientRect(hDlg, rcCaption); rcCaption.bottom := rcCaption.top +20; h_Memo := GetDlgItem(hDlg, ABOUT_MEMO); h_File := GetDlgItem(hDlg, ABOUT_FILE); h_Font := CreateFont(-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, '宋体'); SendMessage(h_File, WM_SETFONT, h_Font, 0); SetDlgItemText(hDlg, ABOUT_FILE, szFile); SetDlgItemText(hDlg, ABOUT_AUTHOR, szAuthor); SetWindowText(hDlg, szAboutCaption); GetClientRect(h_Memo, rcMemo); //得到字幕显示区域大小 w := rcMemo.right - rcMemo.left; h := rcMemo.bottom - rcMemo.top; i := h; lines := LinesInStr(szGreet); //计算字幕行数 //建立显示字幕子窗体 memo := CreateWindow('Static', '', WS_VISIBLE or WS_CHILD or SS_CENTER, 0, h, w, 12* lines, h_Memo, 0, h_Inst, nil); //设定子窗体消息处理函数 lUser := SetWindowLong(memo, GWL_WNDPROC, integer(@ScrollProc)); SetWindowLong(memo, GWL_USERDATA, lUser); AnimateShow(hDlg); SetTimer(hDlg, 168, 80, nil); //设定定时器每80毫秒触发一次 result :=1; end; WM_TIMER: begin //定时器触发时移动子窗体,形成字幕 Sleep(20); i := i -1; SetWindowPos(memo, 0, 0, i, w, 12* lines, 0); if (-(i + (12* lines)) >0) then i := h; //字幕到达尾部时,重新开始循环 end; WM_LBUTTONDOWN: begin pt.x := LOWORD(lParam); pt.y := HIWORD(lParam); if (PtInRect(rcCaption, pt)) then PostMessage(hDlg, WM_NCLBUTTONDOWN, HTCAPTION, 0); end; WM_PAINT: begin h_dc := BeginPaint(hDlg, ps); PaintCaption(h_dc, h_Icon, szAboutCaption, rcCaption, clFrom, clTo); EndPaint(hDlg, ps); end; WM_COMMAND: begin case wParam of ABOUT_OK: begin KillTimer(hDlg, 168); //销毁定时器 EndDialog(hDlg, 0); end; ABOUT_CLOSE: begin KillTimer(hDlg, 168); //销毁定时器 EndDialog(hDlg, 0); end; end; result :=0; end; WM_DRAWITEM: begin pdis := PDRAWITEMSTRUCT(lParam); DrawButton(pdis); Result :=0; end; /// //响应绘制窗体内容消息 WM_CTLCOLORDLG: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; WM_CTLCOLORSTATIC: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; else Result :=0; end; end; function OptionProc(hDlg: HWND; Msg, wParam, lParam: DWORD): LRESULT; stdcall; const rcCaption: TRECT = (); i: smallint =0; w: smallint =0; h: smallint =0; h_Memo: HWND =0; memo: HWND =0; lines: smallint =1; //字幕行数 var h_dc: HDC; ps: TPAINTSTRUCT; pdis: PDRAWITEMSTRUCT; pt: TPOINT; h_Font: HFONT; h_File: HWND; e: integer; begin case Msg of WM_INITDIALOG: begin GetClientRect(hDlg, rcCaption); rcCaption.bottom := rcCaption.top +20; h_Memo := GetDlgItem(hDlg, ABOUT_MEMO); h_File := GetDlgItem(hDlg, ABOUT_FILE); h_Font := CreateFont(-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH or FF_DONTCARE, '宋体'); SendMessage(h_File, WM_SETFONT, h_Font, 0); CheckDlgButton(hdlg, OPTION_AUTOSTART, ord(g_AutoStart)); CheckDlgButton(hdlg, OPTION_AUTOTOOLS, ord(g_AutoTools)); CheckDlgButton(hdlg, OPTION_RANDOM, ord(g_Random)); CheckDlgButton(hdlg, OPTION_COMPUTER, ord(g_Computer)); SetDlgItemText(hDlg, OPTION_TIMER, g_timer); result :=1; end; WM_LBUTTONDOWN: begin pt.x := LOWORD(lParam); pt.y := HIWORD(lParam); if (PtInRect(rcCaption, pt)) then PostMessage(hDlg, WM_NCLBUTTONDOWN, HTCAPTION, 0); end; WM_PAINT: begin h_dc := BeginPaint(hDlg, ps); PaintCaption(h_dc, h_Icon, szOptionCaption, rcCaption, clFrom, clTo); EndPaint(hDlg, ps); end; WM_COMMAND: begin case wParam of OPTION_OK: begin g_AutoStart := IsDlgButtonChecked(hDlg, OPTION_AUTOSTART) = BST_CHECKED; g_AutoTools := IsDlgButtonChecked(hDlg, OPTION_AUTOTOOLS) = BST_CHECKED; g_Random := IsDlgButtonChecked(hDlg, OPTION_RANDOM) = BST_CHECKED; g_Computer := IsDlgButtonChecked(hDlg, OPTION_COMPUTER) = BST_CHECKED; GetDlgItemText(hDlg, OPTION_TIMER, g_timer, 255); //LineGames.AutoStart; Val(g_timer, g_internal, E); if (E <>0) or (g_internal <500) or (g_internal >10000) then begin g_internal :=1000; MessageBox(hDlg, pchar('请输入一个有效的整数(500~10000)!'), pchar('输入错误'), MB_ICONERROR); exit; end; if g_autostart or g_Computer then SetTimer(h_mainDlg, 169, g_internal, nil) else KillTimer(h_mainDlg, 169); //设定定时器每1000毫秒触发一次 EndDialog(hDlg, 0); end; OPTION_ABOUT: DialogBox(h_Inst, LPCTSTR(IDD_ABOUTDLG), hDlg, @AboutProc); OPTION_CANCEL, OPTION_CLOSE: begin EndDialog(hDlg, 0); end; end; result :=0; end; WM_DRAWITEM: begin pdis := PDRAWITEMSTRUCT(lParam); DrawButton(pdis); Result :=0; end; /// //响应绘制窗体内容消息 WM_CTLCOLORDLG: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; WM_CTLCOLORSTATIC: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; else Result :=0; end; end; function MainProc(hDlg: HWND; Msg, wParam, lParam: DWORD): LRESULT; stdcall; const rcCaption: TRECT = (); var h_dc: HDC; ps: TPAINTSTRUCT; pdis: PDRAWITEMSTRUCT; pt: TPOINT; begin case Msg of WM_INITDIALOG: begin h_mainDlg := hDlg; GetClientRect(hDlg, rcCaption); rcCaption.bottom := rcCaption.top +20; SetWindowText(hDlg, szMainCaption); AnimateShow(hDlg); if (RegisterHotKey(hDlg, ID_HOTKEYF2, 0, VK_F2) =false) then begin //hotkey注册 //失败了的话... MessageBox(hDlg, pchar('注册热键F2失败!'), pchar('Error'), MB_ICONERROR); PostQuitMessage(0); end; if (RegisterHotKey(hDlg, ID_HOTKEYF3, 0, VK_F3) =false) then begin //hotkey注册 //失败了的话... MessageBox(hDlg, pchar('注册热键F3失败!'), pchar('Error'), MB_ICONERROR); PostQuitMessage(0); end; if (RegisterHotKey(hDlg, ID_HOTKEYCTRLF4, MOD_CONTROL, VK_F4) =false) then begin //hotkey注册 //失败了的话... MessageBox(hDlg, pchar('注册热键CTRL+F4失败!'), pchar('Error'), MB_ICONERROR); PostQuitMessage(0); end; result :=1; end; WM_HOTKEY: //处理WM_HOTKEY消息 begin case HIWORD(lParam) of VK_F3: LineGames.KillAll; vk_F2: LineGames.RunStep; VK_F4: begin if IsWindowVisible(hDlg) then showWindow(hDlg, SW_HIDE) else showWindow(hDlg, SW_SHOW); end; end; result :=0; end; WM_LBUTTONDOWN: begin //响应鼠标左键按下消息,若在标题栏内则使窗体移动 pt.x := LOWORD(lParam); pt.y := HIWORD(lParam); if PtInRect(rcCaption, pt) then PostMessage(hDlg, WM_NCLBUTTONDOWN, HTCAPTION, 0); end; WM_PAINT: begin //响应绘制消息,绘制标题栏 h_DC := BeginPaint(hDlg, ps); PaintCaption(h_DC, h_Icon, szMainCaption, rcCaption, clFrom, clTo); EndPaint(hDlg, ps); end; WM_COMMAND: begin case wParam of MAIN_SINGLE: begin LineGames.RunStep; end; MAIN_ALL: LineGames.KillAll(); MAIN_OPTION: DialogBox(h_Inst, LPCTSTR(IDD_OPTIONDLG), hDlg, @OptionProc); MAIN_ABOUT: DialogBox(h_Inst, LPCTSTR(IDD_ABOUTDLG), hDlg, @AboutProc); MAIN_EXIT: EndDialog(hDlg, 0); end; result :=0; end; WM_DRAWITEM: begin pdis := PDRAWITEMSTRUCT(lParam); DrawButton(pdis); Result :=0; end; WM_TIMER: begin //定时器触发时移动子窗体,形成字幕 if g_AutoStart then LineGames.AutoStart; if g_Computer then LineGames.RunStep; if g_Random then SetTimer(hDlg,169,500+Random(g_internal-500),nil); end; /// //响应绘制窗体内容消息 WM_CTLCOLORDLG: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; WM_CTLCOLORSTATIC: begin SetTextColor(wParam, clText); SetBkMode(wParam, TRANSPARENT); Result := BKC; end; WM_DESTROY: begin UnregisterHotKey(hDlg, ID_HOTKEYF2); //用完记得要收回 UnregisterHotKey(hDlg, ID_HOTKEYF3); //用完记得要收回 UnregisterHotKey(hDlg, ID_HOTKEYCTRLF4); //用完记得要收回 KillTimer(hDlg, 169); PostQuitMessage(0); end; else Result :=0; end; end; // //程序入口函数 // begin h_Inst := GetModuleHandle(nil); //保存实例句柄 BKC := CreateSolidBrush(clBackground); //建立背景画刷 //h_Cur := LoadCursor(h_Inst, LPCTSTR(IDC_HAND)); //载入鼠标指针 h_Icon := LoadIcon(h_Inst, LPCTSTR(MAINICON)); //载入程序图标 //显示协议对话框 LineGames := TLineGame.Create; DialogBox(h_Inst, LPCTSTR(IDD_MAINDLG), 0, @MainProc); LineGames.Free; DeleteObject(BKC); //释放背景画刷 //退出程序 ExitProcess(0); end.
kbhook.DLLlibrary kbhook;{ Important note about DLL memory management: ShareMem must be thefirst unit in your librarys USES clause AND your projects (selectProject-View Source) USES clause if yo