如何向一个隐藏的窗体发送消息?

altans 2005-11-11 09:54:53
假使某应用程序只有一个住窗体,现在调用hide方法使其隐藏,现在问题来了,该如何发送消息给这个应用程序呢?
如 : 如何能做到按下F10就相当与执行了Button1.click呢?(假设Form1上有Button1)
...全文
389 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
fjx99 2005-11-16
  • 打赏
  • 举报
回复

//发送快捷键到指定窗口
class procedure CWindowOperator.SendAccelerator(myHwnd, wID: integer);
begin
{
发送快捷键的消息是WM_COMMAND
WM_COMMAND的解释:
The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.
WM_COMMAND
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam); // item, control, or accelerator identifier
hwndCtl = (HWND) lParam; // handle of control
Parameters
wNotifyCode: Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.
wID: Value of the low-order word of wParam. Specifies the identifier of the menu item, control, or accelerator.
hwndCtl: Value of lParam. Identifies the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
}

SendMessage(myHwnd,WM_COMMAND,1 shl 16 + wID,0);
end;

//设置Combobox选取items里的某一项
class procedure CWindowOperator.ComboboxSetCurSel(myHwnd,iIndex: integer);
var
myParentHwnd: integer;
begin
//改变Combobox当前选择项
SendMessage(myHwnd,CB_SETCURSEL,iIndex,0);

//改变当前选择项,父窗口将收到WM_COMMAND通知消息,wParam的高16位= CBN_SELCHANGE,wParam的低16位带控件的ID。lParam带控件句柄(hWnd),
//取得控件ID,Delphi CBuilder程序不行,得出的控件ID好象等于句柄
//myID := GetWindowLong( myHwnd, GWL_ID ); wParam := CBN_SELCHANGE shl 16 + myID;
myParentHwnd := GetParent(myHwnd);
SendMessage(myParentHwnd,WM_COMMAND, CBN_SELCHANGE shl 16,myHwnd);
end;

//模拟按下主菜单的菜单项
class procedure CWindowOperator.MenuClick(myHwnd, wID: integer);
begin
{
按下主菜单的菜单项的消息是WM_COMMAND
WM_COMMAND的解释:
The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.
WM_COMMAND
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam); // item, control, or accelerator identifier
hwndCtl = (HWND) lParam; // handle of control
Parameters
wNotifyCode: Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.
wID: Value of the low-order word of wParam. Specifies the identifier of the menu item, control, or accelerator.
hwndCtl: Value of lParam. Identifies the control sending the message if the message is from a control. Otherwise, this parameter is NULL.
}

SendMessage(myHwnd,WM_COMMAND,wID,0);
end;

class procedure CWindowOperator.ButtonClick(myHwnd: integer);
var
myParentHwnd: integer;
begin
//发送WM_LBUTTONDOWN(注,OnClick事件此句可以不要,有了此句按钮会多一个下陷的动作,焦点会在按钮上,同时按钮OnMouseDown、OnMouseUp事件会有响应)
//PostMessage(myHwnd,WM_LBUTTONDOWN,MK_LBUTTON,0);

//用户按下按钮时,其父窗口将收到WM_COMMAND通知消息,同时wParam的高16位=BN_CLICKED,wParam的低16位带控件的ID。lParam带控件句柄(hWnd)
//如果按钮是响应OnClick事件,必须发送此消息
myParentHwnd := GetParent(myHwnd);
PostMessage(myParentHwnd,WM_COMMAND, BN_CLICKED shl 16,myHwnd);
end;

class function CWindowOperator.GetWindowByStyle(hWindow, iStyle,iMaxText: integer): integer;
var
hMisdn :integer;
i :integer;
begin
result:= 0;
for i :=1 to 45 do
begin
hMisdn:=CWindowOperator.FindChildWindow(hWindow,'TCUIEdit','',i);
//iStyle=1409351872 iMaxText=15
if (GetWindowLong(hMisdn,GWL_STYLE)=iStyle) and (SendMessage(hMisdn,EM_GETLIMITTEXT,0,0)=iMaxText) then
begin
result:= hMisdn;
end;
end;
end;



end.
fjx99 2005-11-16
  • 打赏
  • 举报
回复

implementation

constructor CWindowProperty.Create(hwnd:integer; ClassName,Caption: string; Position:TPoint);
begin
m_hwnd := hwnd ; //窗口句柄
m_ClassName := ClassName; //窗口类名
m_Caption := Caption ; //窗口标题
m_Position := Position ; //窗口位置
end;


{
//枚举子窗口
//参数:myHwnd -- 子窗口句柄,由windows填值
// myParam -- 附加的参数,这里应传入TList类型变量的地址,以便将句柄存放到TList
}
function myEnumFunc(myHwnd, myParam: integer): BOOL;stdcall;
var
myClassName : array[0..254] of Char;
myCaption : array[0..254] of Char;
WindowPlacement: TWindowPlacement ;
AWindowProperty: CWindowProperty;
begin
//1. 取得窗口类名、标题
Windows.GetClassName (myHwnd,myClassName,254);
Windows.GetWindowText(myHwnd,myCaption ,254);

//2. 得到窗口的位置(Win95系统必须指定WindowPlacement.length)
WindowPlacement.length := SizeOf(WindowPlacement);
GetWindowPlacement(myHwnd,@WindowPlacement);

//3. 客户坐标转换为屏幕坐标
Windows.ClientToScreen(myHwnd,WindowPlacement.ptMaxPosition);

//4. 属性存入TList
AWindowProperty := CWindowProperty.Create(myHwnd,myClassName,myCaption,WindowPlacement.ptMaxPosition);
TList(myParam).Add(AWindowProperty);


//result为true时继续扫描下一个子窗口
result:=true;
end;

class function ComparePosition(Item1, Item2: Pointer): Integer;
var
Window1_X,Window1_Y : integer;
Window2_X,Window2_Y : integer;
begin
Window1_X := CWindowProperty(Item1).m_Position.X;
Window1_Y := CWindowProperty(Item1).m_Position.Y;
Window2_X := CWindowProperty(Item2).m_Position.X;
Window2_Y := CWindowProperty(Item2).m_Position.Y;

//如果Y的位置不等,Y小的窗口(上面的窗口)排在前面
if Window1_Y < Window2_Y then
result := -1
else if Window1_Y > Window2_Y then
result := 1
else
begin
//如果Y的位置相等,X小的窗口(左边的窗口)排在前面
if Window1_X < Window2_X then
result := -1
else if Window1_X < Window2_X then
result := 1
else
result := 0;
end;
end;

{
//根据类名和标题查找窗口,返回窗口句柄
//参数:strClassName -- 窗口类名
// strWindowName -- 窗口标题
}
class function CWindowOperator.FindWindow(strClassName, strWindowName: string): THandle;
begin
if (strClassName = '') and (strWindowName <> '') then
result := Windows.FindWindow(nil,PChar(strWindowName))
else if (strWindowName = '') and (strClassName <> '') then
result := Windows.FindWindow(PChar(strClassName),nil)
else if (strWindowName <> '') and (strClassName <> '') then
result := Windows.FindWindow(PChar(strClassName),PChar(strWindowName))
else
result := 0;
end;

{
//查找指定类名的特定子窗口(包括子窗口的子窗口),返回子窗口句柄
//参数:hWndParent -- 父窗口句柄
// strClassName -- 子窗口类名(如果为空,表示不判断)
// strWindowName -- 子窗口标题(如果为空,表示不判断)
// iIndex -- 子窗体顺序号(按屏幕从上到下,从左到右的顺序),从0开始
}
class function CWindowOperator.FindChildWindow(hWndParent:THandle; strClassName,strWindowName:string; iIndex:integer): THandle;
var
myList : TList ;
AWindowProperty: CWindowProperty;
i : integer ;
begin
myList := TList.Create();

//1. 枚举子窗口,存入myList
Windows.EnumChildWindows(hWndParent,@myEnumFunc,LongInt(myList));

//2. 对myList中的窗口,删除ClassName <> strClassName 的窗口
strClassName := Uppercase(strClassName);
if strClassName <> '' then
begin
for i := myList.Count-1 downto 0 do
begin
AWindowProperty := CWindowProperty(myList.Items[i]);
if Uppercase(AWindowProperty.m_ClassName) <> strClassName then
begin
AWindowProperty.Free();
myList.Delete(i);
end;
end;
end;

//3. 对myList中的窗口,删除Caption <> strWindowName 的窗口
strWindowName := Uppercase(strWindowName);
if strWindowName <> '' then
begin
for i := myList.Count-1 downto 0 do
begin
AWindowProperty := CWindowProperty(myList.Items[i]);
if Uppercase(AWindowProperty.m_Caption) <> strWindowName then
begin
AWindowProperty.Free();
myList.Delete(i);
end;
end;
end;

if iIndex > myList.Count -1 then
begin
result := 0;
end
else
begin
//4. 对myList中的窗口,按照屏幕位置从上到下,从左到右排序
myList.Sort(@ComparePosition);
//5. 返回窗口句柄
result := CWindowProperty(myList.Items[iIndex]).m_hwnd;
end;
//释放myList
for i := myList.Count-1 downto 0 do
begin
AWindowProperty := CWindowProperty(myList.Items[i]);
AWindowProperty.Free();
myList.Delete(i);
end;
myList.Free();
end;

//取得窗口标题
class function CWindowOperator.GetWindowText(myHwnd: integer): string;
var
buf : array[0..256] of char;
begin
SendMessage(myHwnd,WM_GETTEXT,40,integer(@buf));
result := string(buf);
end;

//设置窗口标题
class procedure CWindowOperator.SetWindowText(myHwnd:integer; strText:string);
begin
SendMessage(myHwnd,WM_SETTEXT,0,LongInt(Pchar(strText)));
end;

//用指定文本替换编辑控件中的当前选定内容(edit,richedit,memo,ComboBox)
class procedure CWindowOperator.EditReplaceSel(myHwnd:integer; strText:string);
begin
SendMessage(myHwnd,EM_REPLACESEL,1,integer(PChar(strText))); //1--表示可以撤销,0--不可撤销
end;

class procedure CWindowOperator.SendKey(myHwnd: integer;VKey: Word);
begin
SendMessage(myHwnd,WM_KEYDOWN, VKey , 0);
SendMessage(myHwnd,WM_CHAR , VKey , 1);
SendMessage(myHwnd,WM_KEYUP , VKey , 0);
end;

class procedure CWindowOperator.SendEnterKey(myHwnd: integer);
begin
SendMessage(myHwnd,WM_KEYDOWN, VK_RETURN, 1);
SendMessage(myHwnd,WM_CHAR , 13 , 1);
SendMessage(myHwnd,WM_KEYUP , VK_RETURN, 1);
{
同理, 傳送 'A' 時, 應先送
KEYDOWN,'a'
WM_CHAR,'A'
KEYUP,'a'

才能正常運作, 省略掉後面的 message, 會有意外發生.
}
end;
fjx99 2005-11-16
  • 打赏
  • 举报
回复
同意上面的:先用FindWindowEx、EnumChildWindows找出按钮句柄,再发消息控制

unit ut_WindowOperator;

interface
uses
SysUtils,Windows,Messages,Classes,Forms;

type

CWindowOperator = class
public
class function FindWindow(strClassName,strWindowName:string):THandle;//根据类名和标题查找窗口,返回窗口句柄

//查找特定子窗口(包括子窗口的子窗口),返回子窗口句柄
//参数:hWndParent -- 父窗口句柄
// strClassName -- 子窗口类名(如果为空,表示不判断)
// strWindowName -- 子窗口标题(如果为空,表示不判断)
// iIndex -- 子窗体顺序号(按屏幕从上到下,从左到右的顺序),从0开始
class function FindChildWindow(hWndParent:THandle; strClassName,strWindowName:string; iIndex:integer):THandle;
class function GetWindowText(myHwnd:integer):string ;//取得窗口标题

class procedure SetWindowText(myHwnd:integer; strText:string);//设置窗口标题
class procedure EditReplaceSel(myHwnd:integer; strText:string);//用指定文本替换编辑控件中的当前选定内容(edit,richedit,memo,ComboBox,DBCombobox)
class procedure ComboboxSetCurSel(myHwnd:integer; iIndex:integer);//设置Combobox选取items里的某一项(DBCombobox不是从Combobox继承的,是从edit继承的,因此不行)

class procedure SendKey(myHwnd:integer; VKey:Word);//发送模拟键到指定窗口
class procedure SendEnterKey(myHwnd:integer);//发送回车到指定窗口
class procedure SendAccelerator(myHwnd:integer; wID:integer);//发送快捷键到指定窗口,myHwnd=窗口句柄,wID=快捷键id
class procedure ButtonClick(myHwnd:integer);//模拟按下按钮
class procedure MenuClick(myHwnd:integer; wID:integer);//模拟按下主菜单的菜单项,myHwnd窗口句柄,wID=菜单项id

class function GetWindowByStyle(hWindow:integer;iStyle:integer;iMaxText:integer):integer;//Coded by Fr
end;


CWindowProperty = class
public
m_hwnd : integer; //窗口句柄
m_ClassName : string ; //窗口类名
m_Caption : string ; //窗口标题
m_Position : TPoint ; //窗口位置

constructor Create(hwnd:integer; ClassName,Caption:string; Position:TPoint);
end;
xixuemao 2005-11-16
  • 打赏
  • 举报
回复
FindWindowEx(handle,0,'TButton','button1');
看看返回的是否为0不就可以了。
用hook然后发消息完全可以解决的。
altans 2005-11-16
  • 打赏
  • 举报
回复
to naughtyboy(重归起跑线) :
我使窗体显示出来的办法是用的api函数findwindow和showwindow,所以仅仅得到的是窗体的句柄,现在的问题也就是:得到窗口的句柄之后如何才能判断窗体上有没有组件button1?下面是我的代码:请指教 !!


function myHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
handle : THandle;
i : integer;
begin
Result:= 0;
if nCode<0 then
begin
Result:= CallNextHookEx(MyHook, nCode, wParam, lParam);
Exit;
end
else
IF NCODE= HC_ACTION THEN
begin
lParam := 0;
if (wParam=ord('m')) or (wParam=ord('M')) or (wParam=vk_f10) then
begin
handle := findwindow('TForm1','Form1') ;
ShowWindow(handle,SW_Normal);
//得到Form1的句柄handle后,如何判断form1上是否有组件button1呢?

end;
end;
end;
altans 2005-11-16
  • 打赏
  • 举报
回复
to skertone() :
我刚用你的程序测试了下,发现不还是不行的,代码如下:(先按Button2 hide form,在按f12或f10都没反映 ),我想还是要用键盘hook才行吧


procedure TForm1.FormCreate(Sender: TObject);
begin
HotKeyID := GlobalAddAtom('NewHotKeyRegister');
if HotKeyID <> 0 then
RegisterHotKey(Handle,HotKeyID,0,VK_F12)

end;

procedure TForm1.HotKeyPress(var Msg: TMessage);
begin
if (Msg. LParamHi = VK_F10) AND (Msg. LParamLo = 0) then
begin
button1.Click ;

end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
UnregisterHotKey(Handle,HotKeyID);
DeleteAtom(HotKeyID);

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Showmessage('sdfsdf');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
hide;
end;

xuancaoer 2005-11-16
  • 打赏
  • 举报
回复
mark
altans 2005-11-15
  • 打赏
  • 举报
回复
to naughtyboy(重归起跑线) :
我也知道用键盘Hook,但是只能做到按f10使隐藏的窗口显示出来,但是没办法实现按f10,就相当于Button1.click;
能指点下吗,谢谢 !
skertone 2005-11-15
  • 打赏
  • 举报
回复
贴个应用啦,这样代码完全些
就是俺喜欢在玩CS时按T键涂雅,又想不停地换图,就写了个程序啦

unit HotKeyMainF;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
HotKeyID: Integer;
procedure HotKeyPress(var Msg: TMessage);Message WM_HOTKEY;
public
{ Public declarations }
end;

var
Form1: TForm1;
ii: Integer = 1;

implementation

{$R *.DFM}

procedure TForm1.HotKeyPress(var Msg: TMessage);
var
bb: Boolean;
iTemp: Integer;
begin
if (Msg. LParamHi = VK_F12) AND (Msg. LParamLo = 0) then
begin
if FileExists('E:\Sierra\Counter-Strike\cstrike\pldecal.wad') then
if DeleteFile('E:\Sierra\Counter-Strike\cstrike\pldecal.wad') then
Memo1.Lines.Add('Delete CS-Logo');
if FileExists('E:\logo\'+ IntToStr(ii) + '.wad') then
if CopyFile(PChar('E:\Logo\'+ IntToStr(ii) + '.wad'),'E:\Sierra\Counter-Strike\cstrike\pldecal.wad',bb) then
Memo1.Lines.Add('Change CS-Logo' + IntToStr(ii) + '.wad');
Msg.Result := 1;
Inc(ii);
if ii > 3 then ii := 1;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
HotKeyID := GlobalAddAtom('NewHotKeyRegister');
if HotKeyID <> 0 then
RegisterHotKey(Handle,HotKeyID,0,VK_F12)
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
UnregisterHotKey(Handle,HotKeyID);
DeleteAtom(HotKeyID);
end;

end.
skertone 2005-11-15
  • 打赏
  • 举报
回复
private
HotKeyID: Integer;
procedure HotKeyPress(var Msg: TMessage);Message WM_HOTKEY;
public
skertone 2005-11-15
  • 打赏
  • 举报
回复
当程序给Hide没有激活应注册系统热键或Hook下才行的啦


procedure TForm1.FormCreate(Sender: TObject);
begin
HotKeyID := GlobalAddAtom('NewHotKeyRegister');
if HotKeyID <> 0 then
RegisterHotKey(Handle,HotKeyID,0,VK_F12)
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
UnregisterHotKey(Handle,HotKeyID);
DeleteAtom(HotKeyID);
end;

procedure TForm1.HotKeyPress(var Msg: TMessage);
begin
if (Msg. LParamHi = VK_F10) AND (Msg. LParamLo = 0) then
begin
Button1Click(nil);

end;
end;
kongguangming 2005-11-15
  • 打赏
  • 举报
回复
楼上方法可行。
naughtyboy 2005-11-15
  • 打赏
  • 举报
回复
为什么不行呢?
你既然能使窗体显示出来,肯定能对以发送消息啊
自定义消息和系统消息都可以发送
在主程序里面只需要根据接收到的消息做相应的处理就可以了
据个例子来说
WM_MYBUTTONCLK = WM_USER + 1000

SendMessage(h,WM_MYBUTTONCLK,wParam,lParam);

主程序中
procedure HandleMyButtonClick(var Msg: TMessage);message WM_MYBUTTONCLK
begin
//add you code here
Button1.Click;
end;
beyondtkl 2005-11-11
  • 打赏
  • 举报
回复
你是谁发消息给它??

其他进程么?
altans 2005-11-11
  • 打赏
  • 举报
回复
TO :hellolongbin(一个人[终不似 少年游])

你可能未明白我的意思,我已经说了该应用程序只有一个窗体了啊,且已经隐藏
hellolongbin 2005-11-11
  • 打赏
  • 举报
回复
不用发送消息
在你要按F10的窗口写:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key=121 then //F10
form2.button1.click;
end;
naughtyboy 2005-11-11
  • 打赏
  • 举报
回复
程序+键盘Hook
altans 2005-11-11
  • 打赏
  • 举报
回复
to : myy()

GlobalAddAtom(...);
RegisterHotKey(...);
消息处理;
UnRegisterHotKey(...);
上面这种方法是不行的,因为现在窗体已经隐藏掉了,窗口根本激活不了,如何向它发送消息呢?


myy 2005-11-11
  • 打赏
  • 举报
回复
google去搜:RegisterHotKey
altans 2005-11-11
  • 打赏
  • 举报
回复
ding
加载更多回复(2)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧