如何运行另一个程序?(200)

  • 主题发起人 主题发起人 blinking1313
  • 开始时间 开始时间
B

blinking1313

Unregistered / Unconfirmed
GUEST, unregistred user!
我有两个EXE程序,分别独立运行,都要用用户名和密码登录,但用户名和密码是一样的。我现在想能否实现这样一个功能:当已经登录其中一个程序后,点击它的一个按钮可以直接登录另一个程序(因为用户名和密码是一样的),而不用再一次录入用户名和密码。
 
你得把用户名和密码发送到另外的那个程序,然后发送点击“确定”按钮的消息就可以了,基本上主要是通过SendMessage()来处理,如果你功力不够,可以用一个变通的办法:点击按钮时把用户名、密码加密写到一个临时文件中,然后直接调用另一个程序,这个程序可以在OnShow事件中加入判断:如果存在那个特定的临时文件就直接读入用户名、密码,解密登录后再删除那个临时文件
 
楼上已经说得很全面了...
 
楼上说了文件和消息2种方式.另外还可以用同享内存和通讯2种方式
 
这种简单的信息传递用发送消息的方式最优!临时文件方式最简单,但比较危险:程序异常中止,文件没被删除,导致下次不用验证就登录了。
 
那如何才能把消息发送给另一个程序呢
 
还有一个简单的方法,就是带参数运行第二个程序。比如,用将用户名密码加密成参数运行第二个程序,第二程序获得参数后解密为用户密码运行就OK了!这样不像用临时文件会留下痕迹。
 
楼上两位的方法是不能解决问题,带参数运行,参数从何得来?那是要用户输入的,怎么可能作为参数。发消息实现方法:主窗体代码:unit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;type TForm1 = class(TForm) private { Private declarations } public procedure WMCOPYDATA(var Message: TWMCopyData); message WM_COPYDATA; end;var Form1: TForm1;type PLoginInfo = ^TLoginInfo; TLoginInfo = packed record //登录信息 Logined: Boolean; UserName: string[16]; Password: string[16]; end;var LoginInfo: PLoginInfo;const LOGIN_FLAG = 111111; //消息标识 LOGINSUCC_FLAG = 222222; //自身作为第二个启动的程序时,会收到这个消息,下同 LOGINFAIL_FLAG = 333333;implementationuses Unit2;{$R *.DFM}{ TForm1 }procedure TForm1.WMCOPYDATA(var Message: TWMCopyData);var CDStruct: TCopyDataStruct; TargetHandle: THandle;begin if Message.CopyDataStruct^.dwData = LOGIN_FLAG then //收到第二个程序发来的消息 begin TargetHandle := Integer(Message.CopyDataStruct^.lpData^); //取得第二个程序的名柄 if LoginInfo^.Logined then //如果自身已登录,消息标识为SUCC begin CDStruct.dwData := LOGINSUCC_FLAG; CDStruct.cbData := SizeOf(TLoginInfo); CDStruct.lpData := LoginInfo; end else CDStruct.dwData := LOGINFAIL_FLAG; //自身未登录(停在登录窗体),消息标识为FAIL SendMessage(TargetHandle, WM_COPYDATA, 0, LParam(@CDStruct)); //把消息内容发给第二个程序 end else if Message.CopyDataStruct^.dwData = LOGINFAIL_FLAG then //自身作为第二个启动的程序时,收到此消息 begin Application.CreateForm(TForm2, Form2); //需要登录 if Form2.ShowModal = mrOk then begin LoginInfo^.Logined := True; LoginInfo^.UserName := '用户名'; LoginInfo^.Password := '密码'; end else Halt; end else if Message.CopyDataStruct^.dwData = LOGINSUCC_FLAG then //已登录,设置自已的登录信息即可 begin LoginInfo^.UserName := PLoginInfo(Message.CopyDataStruct^.lpData)^.UserName; LoginInfo^.Password := PLoginInfo(Message.CopyDataStruct^.lpData)^.Password; LoginInfo^.Logined := True; end;end;end.dpr代码:program Project1;uses Forms, Classes, Windows, Messages, Controls, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2};{$R *.RES}var H, SelfHandle: THandle; CDStruct: TCopyDataStruct;begin Application.Initialize; Application.CreateForm(TForm1, Form1); Form1.Caption := '程序1标识'; //第一个程序的标识 H := FindWindow(nil, '程序2标识'); //第二个程序的标识 SelfHandle := Form1.Handle; New(LoginInfo); LoginInfo^.Logined := False; if H <> 0 then begin CDStruct.dwData := LOGIN_FLAG; CDStruct.cbData := SizeOf(Integer); CDStruct.lpData := @SelfHandle; //把自身句柄传过去,以便能接收消息 SendMessage(H, WM_COPYDATA, 0, LParam(@CDStruct)); end else begin //如果没发现对方程序,则要启动登录窗体 Application.CreateForm(TForm2, Form2); if Form2.ShowModal = mrOk then //登录成功 begin LoginInfo^.UserName := '用户名'; LoginInfo^.Password := '密码'; LoginInfo^.Logined := True; //登录成功标识 end else Halt; end; Application.Run;end.第二个程序的代码与上面完全一样!除了这两句:将: Form1.Caption := '程序1标识'; //第一个程序的标识 H := FindWindow(nil, '程序2标识'); //第二个程序的标识改为 Form1.Caption := '程序2标识'; //标识与上面两句对调了 H := FindWindow(nil, '程序1标识');
 
给你写了一个发消息的简单Demo,你可以参考一下:(代码未加入异常控制)unit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls;type TForm1 = class(TForm) btn1: TButton; procedure btn1Click(Sender: TObject); end;var Form1: TForm1; fwHWND: HWND = 0; OKBtn: HWND = 0;implementation{$R *.dfm}function EnumChildWindowsProc(lHwnd, lParam: Integer): Boolean; stdcall;var WndCaption: array[0..254] of Char; WndClassName: array[0..254] of Char;begin GetWindowText(lHwnd, @WndCaption, 254); GetClassName(lHwnd, @WndClassName, 254); if StrPas(WndClassName) = 'TEdit' then //如果是 Edit 类 begin if SendMessage(lHwnd, EM_GETPASSWORDCHAR, 0, 0) <> 0 then //根据掩码来判断密码框 SendMessage(lHwnd, WM_SETTEXT, 0, Integer(PChar('password'))) else SendMessage(lHwnd, WM_SETTEXT, 0, Integer(PChar('username'))); end; //根据类名及按键的 Caption 来得到 "确定" 按键的句柄 //本来可以在这里直接用 SendMessage(lHwnd, BM_CLICK, 0, 0); 来触发点击的 //但测试时发现有时不起作用, 故将按键句柄传出后在 btn1.Click 中加入上述语句 if (StrPas(WndClassName) = 'TButton') and (Copy(WndCaption, 1, 4) = '确定') then OKBtn := lHwnd; Result := True;end;procedure TForm1.btn1Click(Sender: TObject);var hCurrentWindow: HWND; szText: array[0..1024] of Char;begin //这里只是简单的调用, 可以考虑引用 ShellAPI 单元文件后用以下语句 //ShellExecute(0, 'open', 'demo.exe', '', 'D:/', SW_NORMAL); WinExec(PChar('D:/demo.exe'), SW_NORMAL); //有些程序启动时会有延时, 为了确保能够得到其登录窗体的句柄, 加入延时 Sleep(1000); hCurrentWindow := GetWindow(Handle, GW_HWNDFIRST); while hCurrentWindow <> 0 do begin if GetWindowText(hCurrentWindow, @szText, 255) > 0 then if StrPas(@szText) = '目标程序' then //根据目标程序的登录窗体的标题查找得到该窗体句柄 begin fwHWND := hCurrentWindow; Break; end; hCurrentWindow := GetWindow(hCurrentWindow, GW_HWNDNEXT); end; //枚举登录窗体的控件 if fwHWND <> 0 then EnumChildWindows(fwHWND, @EnumChildWindowsProc, 0); if OKBtn <> 0 then SendMessage(OKBtn, BM_CLICK, 0, 0);end;end.
 
可以改进的地方:1、加入异常控制;2、个人认为更好的方法是在EnumChildWindowsProc中得到用户框、密码框及确定按键的句柄并赋给全局变量;3、在btn1Click中顺序执行以下代码: SendMessage(ChildControl.UserEdit, WM_SETTEXT, 0, Integer(PChar('username'))); SendMessage(ChildControl.PassEdit, WM_SETTEXT, 0, Integer(PChar('password'))); SendMessage(ChildControl.OKButton, WM_LBUTTONDOWN, 0, 0); SendMessage(ChildControl.OKButton, WM_LBUTTONUP, 0, 0);
 
多人接受答案了。
 
后退
顶部