我要用一程序控制另一程序的DateTimePicker,如何用SendMessage更改DateTimePicker控件的时间?另外, SendMessage (ComboBox, CB_SETCURSEL,1,0) ;//选择ComboBox的下拉值时怎么没有触发OnChange事件呀?ComboBox的下拉值却是对的~`

解决方案 »

  1.   

    DateTimePicker...这个组件啊..你可以看看这个组件的源代码它的值是通过什么消息来设置的..
      

  2.   

    我找到一个应该是VC的代码,但是我不是很明白MAKEWPARAM(IDC_PROCESSMODULELIST,CBN_SELCHANGE)之中的意思`~~`
    //选中第一个
    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);
      

  3.   

    //再找一段VB的代码`~`哪位高手给看看吧`~`
    这是针对本窗口中的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   
      
      

  4.   

    procedure TForm1.Button2Click(Sender: TObject);
    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;
      

  5.   

    wudi_1982~~`不行呀`~不知咋回事`~
      

  6.   

    uses CommCtrl;procedure TForm1.Button1Click(Sender: TObject);
    var
        st: TSystemTime;
    begin
        DateTimeToSystemTime(Date() - 2, st);
        SendMessage(DateTimePicker1.Handle, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@st));
    end;
      

  7.   

    以下代码将DateTimePicker的时间指定为2000年1月1日12:0:0uses CommCtrl;procedure TForm1.Button1Click(Sender: TObject);
    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;
      

  8.   

    to:ccrun(老妖)(www.ccrun.com)
    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;
      

  9.   

    SendMessage(Cwd, DTM_SETSYSTEMTIME, GDT_VALID, Longint(@st));
    这里@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;
      

  10.   

    另外,注意最后要释放内存
      VirtualFreeEx(phd,p,sizeof(st), MEM_DECOMMIT );
      CloseHandle(phd);
    否则目标程序关闭时要出错
      

  11.   

    非常感谢keiy() ~~~但是虽然成功`~`但这并不能触发TDateTimePicker的OnChange事件,为何呀?
      

  12.   

    我细细地研究了一下,有相当的难度,由于Delphi的TDateTimePicker在系统的date and time picker (DTP) 上做了封装,所以即便用PostMessage(cwd, DTM_SETSYSTEMTIME, GDT_VALID, longint(p));改变了DTP内的DateTime,但没有改变TDateTimePicker的DateTime,可以这样试试
    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怎样赋值的
      

  13.   

    通过研究TDateTimePicker的源码,终于发现可以通过WM_NOTIFY的DTN_DATETIMECHANGE来改变目标程序的TDateTimePicker的DataTime且能触发OnChange事件,以下是测试程序(在D6上测试通过):
    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也可不用了