//定义
type
PlayerInfo = record //客户端信息
ID: pchar;
GameHwnd: int64; //游戏句柄
ClientHwnd: int64; //dll的窗体句柄
Account: pchar; //账号
PassWord: pchar; //密码
RealmName_1: pchar; //服务器
RealmName_2: pchar;
playername:pchar;
Team:pchar;//队伍
Task:pchar;//功能
CmdCode:pchar;
Gamepath:pchar;
end;
pplayerinfo = ^playerinfo;
var
pplayer: PlayerInfo; {这个将会已指针的方式传递给线程, 它应该是全局的}
T_Event: Cardinal = 0; //事件内核
function LoginGame(ptr: pointer): boolean; stdcall;
//登录游戏的线程
var
i, c: Integer;
num: integer; //ID
hmodule: thandle;
installkeyProc: function(hwindow: hwnd): boolean;
gamehprocess, module: Cardinal;
gameh, childhwnd, filehwnd: int64;
TextFile: TStringList;
filepath: string;
Curp: PlayerInfo; {因为指针参数给的点随时都在变, 需用线程的局部变量存起来}
//临时变量
ID: pchar;
GameHwnd: int64; //游戏句柄
ClientHwnd: int64; //dll的窗体句柄
Account: pchar; //账号
PassWord: pchar; //密码
RealmName_1: pchar; //服务器
RealmName_2: pchar;
playername:pchar;
Team:pchar;//队伍
Task:pchar;//功能
CmdCode:pchar;
Gamepath:pchar;
begin
EnterCriticalSection(CS); //进入临界区
try
result := False;
Curp := pPlayerInfo(ptr)^;
//这里开始往下断点无效,会自动跳过
ID:=Curp.ID; //这个createthread传递进来的结构体,参数多了,传递的值会出错
ClientHwnd:=Curp.ClientHwnd;
Account:=Curp.Account;
PassWord:=Curp.PassWord;
RealmName_1:=Curp.RealmName_1;
RealmName_2:=Curp.RealmName_2;
playername:=Curp.playername;
Team:=Curp.Team;
task:=Curp.Task;
//直到这里可以下断点,中间这一块全部跳过
cmdcode:=Curp.CmdCode;
Gamepath:=Curp.Gamepath;
SetEvent(T_Event); //设置触发
filepath := Gamepath + '\data\config.ini';
if FileExists(filepath) then
begin
//如果文件存在,则进行修改和添加
TextFile := TStringList.Create;
TextFile.LoadFromFile(filepath);
for I := 0 to TextFile.Count - 1 do
begin
if Pos('SaveAccount', TextFile[i]) > 0 then
begin
TextFile.Delete(i);
TextFile.Insert(i, 'SaveAccount = ' + '0');
end;
end;
TextFile.SaveToFile(filepath);
if TextFile <> nil then
begin
TextFile.Free;
TextFile := nil;
end;
end;
//参数一:进程路径
//参数二:命令行
//参数八:子进程工作路径
if createprocess(pchar(gamepath+'\asktao.mod'),
pChar('des:'+CmdCode),
nil, nil, False,
0,
nil, gamepath, StartupInfo, ProcessInfo) then
begin
gameh := GetHwndFromProcess(ProcessInfo.dwProcessId);
for c := 0 to 60 do
begin
if gameh = 0 then
begin
Sleep(1000);
gameh := GetHwndFromProcess(ProcessInfo.dwProcessId);
end
else
break;
end;
end;
if gameh > 0 then
begin
if KeyHook(gameh) then
FormMain.Memo1.Lines.Add('dll安装成功');
//安装完成后,客户端窗体会创建一个DLL窗体,类名为Tform1
//遍历所有进程,跟进程ID相同,并且窗体类名为Tform1
//则代表dll窗体初始化成功,可以发送Data告诉他去登陆
for c := 0 to 30 do
begin
childhwnd := GetChildwindows(ProcessInfo.dwProcessId);
if childhwnd > 0 then
begin
Break;
end
else
Sleep(1000);
end;
//成功创建窗口,可以开始发送数据,并让他开始自动登陆
//如果child窗口为0,则表示登陆失败,或者creatprocess开始是循环
//失败了重新再开一个窗口,记得关闭这个窗口
end;
result := True;
Isloading := false;
LeaveCriticalSection(CS); //离开临界区
ExitThread(0);
except
result := false;
ExitThread(0);
end;
end;
procedure TFormMain.Button1Click(Sender: TObject);
var
i: integer;
num: integer;
UserIni: TIniFile;
list: tstringlist;
filepath: string;
sr: TSearchRec;
Section, Key: string; { 分别表示 ini 文件的小节与关键字 }
begin
filepath := ExtractFilePath(Application.ExeName);
filepath := filepath + '\区组信息.ini';
if not fileExists(filepath) then
begin
MessageBox(Handle, '服务器列表文件丢失', '错误信息', 0);
Exit;
end;
for i := 0 to FormMain.listview1.Items.Count - 1 do
begin
if FormMain.ListView1.Items[i].Checked = True then
begin
num := StrToInt(FormMain.ListView1.Items[i].Caption);
pplayer.ID := pchar(inttostr(num));
pplayer.GameHwnd := 0;
pplayer.ClientHwnd := self.Handle;
pplayer.Account := pchar(FormMain.ListView1.Items[i].SubItems[0]);
pplayer.PassWord := pchar(FormMain.ListView1.Items[i].SubItems[1]);
pplayer.RealmName_1 := pchar(FormMain.ListView1.Items[i].SubItems[2]);
pplayer.RealmName_2 := pchar(FormMain.ListView1.Items[i].SubItems[3]);
pplayer.playername := pchar(FormMain.ListView1.Items[i].SubItems[4]);
pplayer.Team:= pchar(FormMain.ListView1.Items[i].SubItems[5]);
pplayer.task:= pchar(FormMain.ListView1.Items[i].SubItems[9]);
pplayer.Gamepath:=pchar(formmain.Edit游戏路径.text);
//根据服务器列表设置
UserIni := TIniFile.Create(filepath);
// 判断文件大小
if FindFirst(filepath, faAnyFile, sr) = 0 then
begin
if sr.size > 0 then
begin
// 如果文件不为空
section:='DES';
key:=pplayer.RealmName_1;
pplayer.CmdCode:=pchar(userini.ReadString(section,key,''));
end
else
begin
MessageBox(Handle, '服务器列表文件丢失', '错误信息', 0);
FindClose(sr);
if UserIni <> nil then
begin
UserIni.Free;
UserIni := nil;
end;
Exit;
end;
end;
//关闭由FindFirstFile函数创建的一个搜索句柄
FindClose(sr);
if UserIni <> nil then
begin
UserIni.Free;
UserIni := nil;
end;
hthread := createthread(nil, 0, @LoginGame, @pplayer, 0, threadid);
if WaitForSingleObject(T_Event, INFINITE) = WAIT_OBJECT_0 then
ResetEvent(T_Event); //设置为未触发
CloseHandle(hthread);
end;
end;
end;
不知道为什么,logingame线程,传递的自定义结构体参数过多,会传递不正确,而且其中有注释的地方会断点无效,运行起来会自动跳过这段代码,求大神解救,谢谢。。
一般句柄都是32位双字
从你结构定义看你想节约内存,但结构成员可能会自动对齐
pchar的类型有点忘了,是指针吗?
没有看到你为你的结构分配内存,不知在Delphi中是否是自动的
面向对象效率稍低可能更便于程序维护
一点愚见供参考
可能断点处是无效代码,被优化,或者你重新build