Option Explicit Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wparam As Long, lparam As Any) As Long Private Const WM_COMMAND = &H111 Private Const CBN_SELCHANGE = 1 Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function GetDlgCtrlID Lib "user32" (ByVal hwnd As Long) As Long
Private Sub Combo1_Click() '测试,针对vb,CBN_SELCHANGE这条消息会生成combobox的click事件 MsgBox "aaa" End Sub
Private Sub Command1_Click() Dim mhwnd As Long Dim ctrlid As Long mhwnd = Me.Combo1.hwnd ctrlid = GetDlgCtrlID(mhwnd) Dim wparam As Long, lparam As Long wparam = CBN_SELCHANGE * 2 ^ 16 + ctrlid lparam = mhwnd Dim phwnd As Long phwnd = GetParent(mhwnd) SendMessage phwnd, WM_COMMAND, wparam, ByVal lparam End Sub
Private Sub Form_Load() Dim i As Long For i = 1 To 20 Combo1.AddItem "line " + CStr(i) Next End Sub
//选中第一个
SendMessage(hwndList,CB_SETCURSEL,0,0);
//将hwndList句柄的CBN_SELCHANGE消息送到hwnd中处理
SendMessage(hwnd,WM_COMMAND,MAKEWPARAM(IDC_PROCESSMODULELIST,CBN_SELCHANGE),(LPARAM)hwndList);
SendMessage(hwndList,WM_SETREDRAW,TRUE,0);
//重绘hwndList
InvalidateRect(hwndList,NULL,FALSE);
这是针对本窗口中的combobox的,如果想用于其它窗口,请自行修改mhwnd = Me.Combo1.hwnd这一句为合适的语句(提示,可利用findwindow结合findwindowex获得combobox句柄):
Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wparam As Long, lparam As Any) As Long
Private Const WM_COMMAND = &H111
Private Const CBN_SELCHANGE = 1
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetDlgCtrlID Lib "user32" (ByVal hwnd As Long) As Long
Private Sub Combo1_Click() '测试,针对vb,CBN_SELCHANGE这条消息会生成combobox的click事件
MsgBox "aaa"
End Sub
Private Sub Command1_Click()
Dim mhwnd As Long
Dim ctrlid As Long
mhwnd = Me.Combo1.hwnd
ctrlid = GetDlgCtrlID(mhwnd)
Dim wparam As Long, lparam As Long
wparam = CBN_SELCHANGE * 2 ^ 16 + ctrlid
lparam = mhwnd
Dim phwnd As Long
phwnd = GetParent(mhwnd)
SendMessage phwnd, WM_COMMAND, wparam, ByVal lparam
End Sub
Private Sub Form_Load()
Dim i As Long
For i = 1 To 20
Combo1.AddItem "line " + CStr(i)
Next
End Sub
var
pst : TSystemTime;
tm : TDateTime;
begin
tm := Date-100; //将datetimepicker1的日期更改为当前日期-100
DateTimeToSystemTime(tm,pst); //将tm转换为Tsystemtime
SendMessage(DateTimePicker1.Handle, $1000+2, 0, Longint(@pst));//发送消息end;
var
st: TSystemTime;
begin
DateTimeToSystemTime(Date() - 2, st);
SendMessage(DateTimePicker1.Handle, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@st));
end;
var
st: TSystemTime;
begin
st.wYear := 2000;
st.wMonth := 1;
st.wDay := 1;
st.wHour := 12;
st.wMinute := 0;
st.wSecond := 0;
SendMessage(DateTimePicker1.Handle, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@st));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Mwd,Cwd :LongInt ;
st : TSystemTime;
begin
Mwd :=FindWindow('TForm1','Form1');
//if FindWindowEx(Mwd,0,'TDateTimePicker',nil)<>0 then ShowMessage('sd');//这里已经找到了TDateTimePicker的Handle
Cwd :=FindWindowEx(Mwd,0,'TDateTimePicker',nil);
DateTimeToSystemTime(Date-2, st);
SendMessage(Cwd, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@st));//但是这里没办法修改另一程序的DateTimePicker.date,如果是本窗体的DateTimePicker1.Handle却是可以修改的~~
end;
这里@st必须是本进程的地址,所以必须将st写入对方的内存中:
以下程序测试通过(目标from为TEST3)
procedure TForm1.Button1Click(Sender: TObject);
var
Mwd,Cwd :LongInt ;
st : TSystemTime;
pid,phd:thandle;
p:pointer;
l:dword;
b:boolean;
begin
Mwd :=FindWindow(nil,'TEST3'); GetWindowThreadProcessId(mwd,pid);
phd:=openprocess(PROCESS_ALL_ACCESS,true,pid);
VirtualAllocEx(phd,p,sizeof(st), MEM_COMMIT,PAGE_READWRITE );
if (p=nil) then
begin
ShowMessage('error1');
exit;
end;
l:=0; Cwd :=FindWindowEx(Mwd,0,'TDateTimePicker',nil); DateTimeToSystemTime(Date-2, st);
b:=WriteProcessMemory(phd,p,@st,sizeof(st),l);
if ((not b )and (l<>sizeof(st)) )then
begin
ShowMessage('error2');
exit;
end;
PostMessage(cwd, DTM_SETSYSTEMTIME, GDT_VALID, longint(p));end;
VirtualFreeEx(phd,p,sizeof(st), MEM_DECOMMIT );
CloseHandle(phd);
否则目标程序关闭时要出错
1.用 ShowMessage(datetostr( DateTimePicker1.DateTime));
2.用
var
st: TSystemTime;
d:tdatetime;
begin
SendMessage(DateTimePicker1.Handle, DTM_GETSYSTEMTIME, GDT_VALID, Longint(@st));
d:= SystemTimeToDateTime(st);
ShowMessage(datetostr( d));
在PostMessage(cwd, DTM_SETSYSTEMTIME, GDT_VALID, longint(p));后,它们的结果是不是样的,而OnChange是delphi在焦点离开TDateTimePicker时,用新的DateTime与老的比较,所以我们的方法是无法触发OnChange的
能想到的解决方法:
1.不用DTM_SETSYSTEMTIME,而用模拟鼠标点击的方法,对目标TDateTimePicker操作
2.研究TDateTimePicker源码,看它的DateTime怎样赋值的
procedure TForm1.Button1Click(Sender: TObject);
var
Mwd,Cwd :LongInt ;
st : TSystemTime;
pid,phd:thandle;
p:pointer;
l:dword;
b:boolean;
nm:NMHDR;
tg:tagNMDATETIMECHANGE;
begin
Mwd :=FindWindow(nil,'TEST3');
if (mwd=0) then
begin
ShowMessage('error1');
exit;
end;
Cwd :=FindWindowEx(Mwd,0,'TDateTimePicker',nil);
if(cwd=0) then
begin
ShowMessage('error2');
exit;
end;
GetWindowThreadProcessId(mwd,pid);
phd:=openprocess(PROCESS_ALL_ACCESS,false,pid);
p:=VirtualAllocEx(phd,nil,sizeof(tg), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (p=nil) then
begin
ShowMessage('error3');
CloseHandle(phd);
exit;
end;
l:=0;
DateTimeToSystemTime(Date-2, st);
nm.hwndFrom:=cwd;
nm.idFrom:=0;
nm.code:=DTN_DATETIMECHANGE;
tg.nmhdr:=nm;
tg.dwFlags:=GDT_VALID;
tg.st:=st;
b:=WriteProcessMemory(phd,p,@tg,sizeof(tg),l);
if ((not b )or (l<>sizeof(tg)) )then
begin
ShowMessage('error4');
CloseHandle(phd);
exit;
end;
Postmessage(cwd, WM_NOTIFY,0, Longint(p)); //cwd也可为mwd
Sleep(100); //不能马上释放内存,因为目标还未收到
if ( VirtualFreeEx(phd,p,0, MEM_RELEASE))=nil then
begin
Showmessage('error5');
end;
CloseHandle(phd);
end;要注意的是
1.上次的VirtualAllocEx是有个大错,能运行是运气(因为p是个随机值),为这个,我废了半天
2.正如程序中所注释,内存不能马上释放
3.如果你要多次发送,最好先打开进程及申请内存,在程序退出时再释放,不要反复打开,这样Sleep也可不用了