我想获取外部程序Label的caption,具体见http://topic.csdn.net/u/20090313/19/ae2b7f38-43de-4b9b-be52-ed28f6ddeba7.html我已经尝试了好几个思路了,现在在这样考虑:用Label显示或者更新数据,就用label2.caption='XXX',那么我要获取该数据(即Label的caption),可以考虑HOOK API,但是在Delphi里面label2.caption='XXX'是通过什么函数来实现的呢?label是个类?caption是Label类的一个成员变量吗?还是怎么回事?不明白这个,即使想HOOK API也不知道该hook哪个API函数啊,哎。
或者各位有什么其它办法或者思路可以获取目标进程界面的Label,也可以拿出来一起探讨,谢谢!!!!!!!
小弟一直没怎么接触过Delphi,请各位指教!!谢谢。

解决方案 »

  1.   

    谢谢QQ286251099。
    请问:目标界面上有很多的Label,我要获取每个的caption。它textout出来的是所有Label的caption总和吗?
    如果是这样,它既然可以分Label1.caption,,Label2.caption等等分别的表示出来,那我能否也一一分别截获下来呢?而不是一股脑的截获所有的caption混在一起。谢谢QQ286251099,也请各位老大都过来指点小弟几招!!
      

  2.   

    假如你能找到这个caption的句柄,并把它转化为控件(FindControl),就可以用TLabel来转化它并访问其属性
      

  3.   


    procedure EnumChildProc(hwnd: HWND; lparam: LPARAM); stdcall;
    var
      wndClassName: array[0..255] of Char;
      WndCaption: array[0..255] of Char;
    begin
      GetClassName(hwnd, wndClassName, 255); 
      GetWindowText(hwnd, WndCaption, 255);
      if GetClassName = 'Tlable' then 
         ....
    end;procedure TForm1.Button3Click(Sender: TObject);
    var
      handle: HWND;
    begin
      handle := FindWindow(nil, PChar(FormCaption));
      if 0 <> handle then
        EnumChildWindows(handle, @EnumChildProc, 0);
    end;
      

  4.   

    你把外部程序的句柄传进去, 也可以用VC里的SP++查看,现在我只发现360用SP++看不到
      

  5.   

    谢谢 只爱三国!!
    你能不能解释下你的代码?
    GetClassName(hwnd, wndClassName, 255);你这个hwnd怎么得到呢?Label是没有句柄的。。而且我要得到外部程序的caption, GetWindowText貌似只能得到自己程序的内容,外部程序是不行的。
      

  6.   

    谢谢!!
    请问你说的caption的句柄是什么意思?我很菜,你能不能多解释一下?
      

  7.   

    TLabel是从TGraphicControl继承下来的,这类控件没有句柄,是依赖所在容器(Parent)的画布绘制。楼主现在也知道了。Controls.pas单元中有一个FindControl函数,通过句柄获得对应的TWinControl对象。
    function FindControl(Handle: HWnd): TWinControl;
    begin
      Result := nil;
      if (Handle <> 0) then
      begin
        if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then
          Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))
        else
          Result := ObjectFromHWnd(Handle);
      end;
    end;由于,进程间内存地址是相对的,所以直接访问这个对象会出现内存异常。procedure InitControls;
    var
      UserHandle: HMODULE;
    begin
      WindowAtomString := Format('Delphi%.8X',[GetCurrentProcessID]);
      WindowAtom := GlobalAddAtom(PChar(WindowAtomString));
      ControlAtomString := Format('ControlOfs%.8X%.8X', [HInstance, GetCurrentThreadID]);
      ControlAtom := GlobalAddAtom(PChar(ControlAtomString));
      RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
    //...
    end;另外FindControl函数用到的变量(如:WindowAtomString)和具体线程ID有关。大概的步骤是:
    1、创建一个hook,以便跨进程访问内存空间;
    2、自定义FindControl方法,按目标窗体所在线程组装参数;
    3、获得TWinControl对象;
    4、通过WM_COPYDATA消息返回查询内容。关键代码:
    (*//
    标题:窗体嗅探器
    作者:王集鹄(Zswang)
    博客:http://blog.csdn.net/zswang
    日期:2009年3月14日
    .//*)unit Sniffer;interfaceuses Windows;function ExeSniffer( // 执行嗅探
      AHandle: THandle; // 窗体句柄
      AParam: Integer // 附加参数
    ): BOOL; stdcall;implementation// 尊重作者,转贴请注明出处 王集鹄(Zswang) 2009年3月14日uses SysUtils, Classes, Controls, StdCtrls, Messages;var
      WM_SNIFFWINDOW: Longword;type
      TSnifferInfo = packed record
        rHOOK: HHOOK;
        rHandle: HWND;
        rParam: Integer;
      end;
      PSnifferInfo = ^TSnifferInfo;var
      vMapFile: THandle;
      vSnifferInfo: PSnifferInfo;var
      ControlAtom: TAtom;
      ControlAtomString: string = '';
      RM_GetObjectInstance: DWORD;  // registered window messagefunction FindControl(Handle: HWnd): TWinControl;
    var
      OwningProcess: DWORD;
    begin
      Result := nil;
      if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and
         (OwningProcess = GetCurrentProcessId) then
      begin
        if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then
          Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))
        else
          Result := Pointer(SendMessage(Handle, RM_GetObjectInstance, 0, 0));
      end;
    end; { FindControl }function SnifferProc(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
    var
      vWinControl: TWinControl;
      vCopyDataStruct: TCopyDataStruct;
      I: Integer;
      S: string;
    begin
      case code of
        HC_ACTION:
          begin
            if PCWPStruct(lParam)^.message = WM_SNIFFWINDOW then
            begin
              if ControlAtomString = '' then
              begin
                ControlAtomString := Format('ControlOfs%.8X%.8X', [
                  GetWindowLong(vSnifferInfo^.rHandle, GWL_HINSTANCE),
                  GetWindowThreadProcessId(vSnifferInfo^.rHandle)]);
                ControlAtom := GlobalAddAtom(PChar(ControlAtomString));
                RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));
              end;
              vWinControl := FindControl(vSnifferInfo^.rHandle);
              if Assigned(vWinControl) then
              begin
                for I := 0 to vWinControl.ComponentCount - 1 do
                begin
                  S := '';
                  if SameText(vWinControl.Components[I].ClassName, 'TLabel') then
                  begin
                    S := Format('%s: %s', [vWinControl.Components[I].Name,
                      QuotedStr(TLabel(vWinControl.Components[I]).Caption)]);
                  end else if SameText(vWinControl.Components[I].ClassName, 'TMemo')
                    or SameText(vWinControl.Components[I].ClassName, 'TEdit') then
                  begin
                    S := Format('%s: %s', [vWinControl.Components[I].Name,
                      QuotedStr(TLabel(vWinControl.Components[I]).Caption)]);
                  end;
                  vCopyDataStruct.cbData := Length(S);
                  vCopyDataStruct.dwData := 0;
                  vCopyDataStruct.lpData := @S[1];
                  SendMessage(vSnifferInfo^.rParam, WM_COPYDATA,
                    vSnifferInfo^.rHandle, Integer(@vCopyDataStruct));
                end;
              end;
            end;
          end;
      end;
      Result := CallNextHookEx(vSnifferInfo^.rHOOK, code, wParam, lParam);
    end;function ExeSniffer( // 执行嗅探
      AHandle: THandle; // 窗体句柄
      AParam: Integer // 附加参数
    ): BOOL; stdcall;
    begin
      vSnifferInfo^.rHandle := AHandle;
      vSnifferInfo^.rParam := AParam;
      vSnifferInfo^.rHOOK := SetWindowsHookEx(
        WH_CALLWNDPROC, SnifferProc, HInstance, GetWindowThreadProcessId(AHandle));
      Result := SendMessageTimeout(AHandle, WM_SNIFFWINDOW, 0, 0,
        SMTO_NORMAL, 3000, THandle(Result)) = 0;
      UnhookWindowsHookEx(vSnifferInfo^.rHOOK);
    end;initialization
      WM_SNIFFWINDOW := RegisterWindowMessage('SnifferLib.SniffWindow');
      vMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, '~Sniffer');
      if vMapFile = 0 then
        vMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
          SizeOf(TSnifferInfo), '~Sniffer');
      vSnifferInfo := MapViewOfFile(vMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);finalization
      UnmapViewOfFile(vSnifferInfo);
      CloseHandle(vMapFile);end.
      

  8.   

    用例已经放到下载频道:跨进程访问VCL的一个用例(Delphi6、TurboDelphi测试通过)
    不过要花10个资源分(50个可用分)
    如果资源分不足可以用:可用分兑换资源分(5:1)
      

  9.   

    非常感谢zswang大哥!!!!
    我先把你的代码理一下,你知道对于我这样的菜鸟没个半天时间消化不了,分一定给,这个绝对不是问题,要是这30分不够我都可以另外开个帖子给你分,,
      

  10.   

    分不多,但人人有份,谢谢各位的帮助!!
    先把zswang的代码消化下,结贴去也。。
      

  11.   

    回复myjian:
    谢谢指教!!