我用Hook监视一个目标窗口的出现,并在窗口出现后,获取到几个相关的窗体句柄
其中一个产品名称列表下拉框,一个产品编号文本框
在程序中直接操作的时候,应该是先选择下拉框中产品,此时会触发下拉框的Onclick事件,进行一些数据读取的处理,然后输入产品编号,在输入产品编号的过程中,每输入一个数字,都会触发一个事件,对产品名称和编号进行比较,如果比较通过,则该窗口直接进入下一个填写界面。我现在通过WM_WINDOWPOSCHANGING消息Hook监视该目标窗口,并且模拟下拉框选择和产品编号的填写,但是总是导致目标程序出错,一直找不到原因。我单独模拟输入产品名称下拉框,程序不出错,
单独模拟输入产品标号,程序也不出错。
但是只要两者一起输入,目标程序就出错了。模拟输入下拉框代码:
var listOrder:Integer;
listOrder:= findComboItemIndex(nameHwnd, productName);//找到要输入的产品名称在下拉列表中的顺序
SendMessage(nameHwnd, CB_SETCURSEL, listOrder, 0);
模拟输入产品编号代码:
SendMessage(codeHwnd, WM_SETTEXT, 0, LongInt(Pchar(productCode)));麻烦大家帮忙分析一下原因,谢谢。
不懂的,不能回答的,就别顶了,我会自己关注帖子,自己提前的,谢谢合作

解决方案 »

  1.   

    无法设定间隔时间啊,我试过。
    其实就是在你上次帮我改的那个Hook代码里,继续写的。
    因为窗口消息处理事件进入我的Dll里了,我的Dll如果Sleep的话,那个程序也停了,我的Sleep结束,那个程序才继续运行。就跟没Sleep一样
      

  2.   

    有源代码,是VB的,但是获取不到通过Vb调试运行出来的窗口。
    就能识别EXE运行出来的
      

  3.   

    你不要用CB_SETCURSEL,换用CB_SELECTSTRING试试:SendMessage(nameHwnd, CB_SELECTSTRING, 0,LPARAM(pchar('下拉列表选项名)));
      

  4.   

    想办法跟踪到VB代码里了,发现是我用程序模拟选择完产品名称,输入完产品编号后,后续VB代码让那个界面上一个下拉框Focus,但是因为那个窗口还没显示出来呢,所以调用.focus就出错了。VB里有那样一个限制,对于尚未显示出来的控件,调用Focus就会出错。原因是发现了,但还没想到解决办法,求救了
      

  5.   

      if (nCode < 0) then //or (nCode = HC_NOREMOVE)
      begin
        Result := CallNextHookEx(0, nCode, WParam, LParam);
        exit;
      end;  winStruct := PCWPSTRUCT(LParam)^;  if winStruct.message <> WM_WINDOWPOSCHANGING then
      begin
        Result := CallNextHookEx(0, nCode, WParam, LParam);
        exit;
      end
      else
      begin
        winPos := PWindowPos(winStruct.lParam)^;
        if (winPos.flags and SWP_SHOWWINDOW) = 0 then
        begin
          Result := CallNextHookEx(0, nCode, wParam, lParam);
          exit;
        end;
        if (winPos.hwnd = 0) or (not IsWindow(winPos.hwnd)) then
        begin
          Result := CallNextHookEx(0, nCode, wParam, lParam);
          exit;
        end;
      end;
      //开始模拟录入
    上面代码是Hook函数里监视目标窗口的代码,原来意图是那个窗口还没等显示出来,就让其隐藏并且任务栏上看不到相应图标。
    我现在隐藏部分都先注释掉了,就没贴上来。
    但执行模拟录入的时候,目标窗口还是没显示出来呢,所以就像我上面说的那样,导致错误了。
    我是不是应该等目标窗口已经显示出来,再模拟输入啊?
    但如果又想隐藏窗口,又不希望程序图标在任务栏显示,又想保证目标窗体完全加载完毕,应该怎么办呢?
    我以前发过帖子,直接用一个可执行程序隐藏目标窗口并且不显示任务栏是可行的。
    但相同的代码放在Dll里,就达不到效果了。
      

  6.   

    因为时间太紧,我想先退一步,等目标窗口已经显示出来再对其进行操作。
    那这个时候,我应该Hook哪个消息?
    谢谢
      

  7.   

    但好像WM_WINDOWPOSCHANGED 消息在窗体显示,最大化,最小化,关闭过程中都会产生,不知道会不会有问题。
    我先试试去
      

  8.   

    WM_WINDOWPOSCHANGED = $0047;
    发送此消息给那个窗口的大小和位置已经被改变时,来调用setwindowpos函数或其它窗口管理函数
      

  9.   

    WM_WINDOWPOSCHANGING = $0046;
    发送此消息给那个窗口的大小和位置将要被改变时,来调用setwindowpos函数或其它窗口管理函数
      

  10.   

    改成WM_WINDOWPOSCHANGED消息后,还是有点问题
    正常来说VB窗体加载的时候,会触发一个Form_Activate事件,并且是在窗体显示出来之前执行的,
    但我发现我Hook了WM_WINDOWPOSCHANGED消息的时候,那个窗口的Form_Activate竟然执行了两次。
    当我用程序模拟选择了产品名称和编号后,那个VB程序自动将产品名称下拉框和编号文本框隐藏了。
    而第二次执行Form_Activate的时候,因为那个窗体上有的文本框已经隐藏了,那在Form_Activate中再次对那个文本框.focus的时候,就出错了。
      

  11.   

    你在 WM_WINDOWPOSCHANGED 的处理里一定做了什么事情,否则不会激活两次的。
      

  12.   

    看来你需要在 Form_Activate 之后再做你的工作?如果是那样的话,我想这个事件可能和 WM_ACTIVATE 消息是相关的,你钩这个消息试试?
      

  13.   

    窗体生命周期消息:
    创建窗体  ...
    1. WM_GETMINMAXINFO        
    2. WM_NCCREATE             
    3. WM_NCCALCSIZE             
    4. WM_CREATE               
    创建完毕.显示窗体  ...
    1. WM_SHOWWINDOW            
    2. WM_WINDOWPOSCHANGING      
    3. WM_WINDOWPOSCHANGING      
    4. WM_ACTIVATEAPP           
    5. WM_NCACTIVATE             
    6. WM_GETTEXT                
    7. WM_ACTIVATE              
    8. WM_SETFOCUS              
    9. WM_NCPAINT                
    10. WM_GETTEXT                
    11. WM_ERASEBKGND            
    12. WM_WINDOWPOSCHANGED       
    13. WM_SIZE                  
    14. WM_MOVE                   
    显示完毕.
    其他的先不列出来了。
    Hook  WM_WINDOWPOSCHANGED消息的情况下,其实我之前选择输入产品名称和产品编号的目的确定达到了,比我之前Hook WM_WINDOWPOSCHANGING消息前进了一步。
    但是是不理解那个Form_Activate 应该是在我的代码执行之前执行的,怎么之后又执行了一次,并导致错误。
    实在想不出来,怎么能绕过去我又不能改动那个VB程序。不允许改。
      

  14.   

    我理解错了,在那个VB源码里又跟踪了一次,发现是我的Hook代码执行之后,那个窗体才触发Form_Activate事件。
    Hook WM_WINDOWPOSCHANGED 消息和Hook WM_ACTIVATE消息都是这样。
    为什么呢?
    到底应该Hook哪个消息,保证窗体显示完毕,才执行我的代码呢?
      

  15.   

    也就是说Form_Activate并没有执行两次,而是比我的HOOK代码执行的晚。如果能让我的Hook代码在Form_Activate事件之后执行,应该就没问题了。VB窗体显示的时候触发的事件是有顺序的,先Form_Load,然后Form_Activate,然后才显示出来。
      

  16.   

    这个已经不是简单的 Windows 的机制问题了,和 VB 的 Form 的实现机制也密切相关。关键点现在看来集中到了如何准确判断 Form_Activate 的出发时机上。没有经历帮你测试,只好关注了,呵呵。
      

  17.   

    其实应该也可以不考虑VB 的 Form 的实现机制,只要能够判断窗口是否显示完毕,就可以了。
    但我现在想不到办法判断窗口显示完毕。
      

  18.   

    窗口显示完毕就是 WM_WINDOWPOSCHANGED,基本没有别的什么好办法了。
      

  19.   

    lz可以这么干,先把hook插入目标进程,然后用SetWindowLong修改目标窗口的处理函数,当消息出现时,先调用原先的处理函数,再判断消息类型,如果是WM_SHOWWINDOW则自动填表,这样可以保证窗口先显示出来
      

  20.   

    自己写一个MySleep过程,代替Sleep
    procedure MySleep(Sec: Integer);
    var
      i: Integer;
    begin
      i:=0;
      while i<100*Sec do
      begin
        i:=i+1;
        Application.ProcessMessages;
        Sleep(10);
      end;
    end;
      

  21.   

    这样不行,因为是在Dll里,不能Application.ProcessMessages;
    而直接Sleep会导致目标程序也暂停。