Q&A

  • 핸들값을 찾아내는 spy에 관한 질문입니다.
안녕하세요.
제가 오늘 비가 와서 그런지 잘 풀려간다고 생각했던 문제들에서 자꾸 막히네요.
다름이 아니라 제가 드라이버 설치를 진행하는데요.
버튼을 찾아서 그 버튼에 클릭효과를 줌으로써 단계를 진행합니다.
근데 좀 이상한 상황이 나타나서 질문을 올리게 되었습니다.
질문을 위해서 파일 두개를 첨부하겠습니다.
'의문 화면.Bmp'라는 파일은 제가 이상하다고 생각한 부분의 화면의 캡쳐 부분이고 'project1.exe'라는 프로그램은 마우스 위치의 핸들과 클래스 이름, 그리고 그것의 텍스트를 가져오는 실행파일(델아맏의 김도완님이 올려주신 파일-죄송합니다. 유용한것 같아서 쓰고 있었습니다.이해해주세요.)입니다.

좀 수고우시더라도 봐주셨으면 합니다. 죄송합니다.

첨부된 그림을 보면 spy의 화면의 빨간색 선에는 분명이 클래스가 'button'으로 되어 있고 텍스트가 '아니오, 컴퓨터를 나중에 다시 시작하겠습니다.'라고 되어 있습니다.
하지만 실행파일 화면의 'ClassName'을 보면 'static'으로 되어 있고, text는 아무런 내용이 없습니다.

어떤 것이 정확한 값일까요?

제가 만든 소스를 보여드리면 아래와 같습니다.

unit uInstallLevel;

interface

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

type
  TfrmInstallOrder = class(TForm)
    btnNextEnter: TButton;
    edtDeviceName: TEdit;
    edtMClassName: TEdit;
    edtMText: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    edtCClassName: TEdit;
    edtCText: TEdit;
    Label5: TLabel;
    Label6: TLabel;
    btnClose: TButton;
    btnNewDevice: TButton;
    Label7: TLabel;
    btnClickTest: TButton;
    btnClear: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnNextEnterClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnNewDeviceClick(Sender: TObject);
    procedure Update_File;
    procedure btnClickTestClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    InstallOrder : TIniFile;
    i : integer;
  end;

var
  frmInstallOrder: TfrmInstallOrder;

implementation

{$R *.dfm}

procedure TfrmInstallOrder.FormCreate(Sender: TObject);
begin
  i := 0;
  Label7.Caption := 'Level = ' + IntToStr(i+1);
end;

procedure TfrmInstallOrder.btnNextEnterClick(Sender: TObject);
//var
//  DeviceName, MClassName, MText, CClassName, CText : String;

begin
  Label7.Visible := false;
  Update_file;
{  InstallOrder := TIniFile.Create('C:\Result\InstallOrder.ini');
  DeviceName := edtDeviceName.Text;
  MClassName := edtMClassName.Text;
  MText := edtMText.Text;
  CClassName := edtCClassName.Text;
  CText := edtCText.Text;
  inc(i);
  InstallOrder.WriteString(DeviceName, 'Level', IntToStr(i));
  InstallOrder.WriteString(DeviceName, 'MClassName' + IntToStr(i), MClassName);
  InstallOrder.WriteString(DeviceName, 'MText' + IntToStr(i), MText);
  InstallOrder.WriteString(DeviceName, 'CClassName' + IntToStr(i), CClassName);
  InstallOrder.WriteString(DeviceName, 'CText' + IntToStr(i), CText);
  Label4.Caption := 'Level = ' + IntToStr(i);
  InstallOrder.Free;
  edtMClassName.Clear;
  edtMText.Clear;
  edtCClassName.Clear;
  edtCText.Clear;
  edtMClassName.SetFocus;}
end;


procedure TfrmInstallOrder.btnCloseClick(Sender: TObject);
begin
  frmInstallOrder.Close;
end;

procedure TfrmInstallOrder.btnNewDeviceClick(Sender: TObject);
var
  NewDeviceName : String;

begin
  i := 0;
  NewDeviceName := InputBox('New DeviceName', '새로입력할 장치의 이름을 입력하세요!','');
  edtDeviceName.clear;
  edtDeviceName.Text := NewDeviceName;
  Label7.Caption := 'Level =' + IntToStr(i+1);
  Label4.Visible := false;
  Update_File;
  Label4.Visible := true;
end;

procedure TfrmInstallOrder.Update_File;
var
  DeviceName, MClassName, MText, CClassName, CText : String;

begin
  InstallOrder := TIniFile.Create('C:\Result\InstallOrder.ini');
  DeviceName := edtDeviceName.Text;
  MClassName := edtMClassName.Text;
  MText := edtMText.Text;
  CClassName := edtCClassName.Text;
  CText := edtCText.Text;
  inc(i);
  Label4.Caption := 'Level = ' + IntToStr(i);
  InstallOrder.WriteString(DeviceName, 'Level', IntToStr(i));
  InstallOrder.WriteString(DeviceName, 'MClassName' + IntToStr(i), MClassName);
  InstallOrder.WriteString(DeviceName, 'MText' + IntToStr(i), MText);
  InstallOrder.WriteString(DeviceName, 'CClassName' + IntToStr(i), CClassName);
  InstallOrder.WriteString(DeviceName, 'CText' + IntToStr(i), CText);
  InstallOrder.Free;
  edtMClassName.Clear;
  edtMText.Clear;
  edtCClassName.Clear;
  edtCText.Clear;
  edtMClassName.SetFocus;
end;

procedure TfrmInstallOrder.btnClickTestClick(Sender: TObject);
var
  s1, s2, s3, s4 : String;
  AlHandle1, AlHandle2 : THandle;
  Temp : Integer;

begin
  Temp := 0;
  s1 := edtMClassName.Text;
  s2 := edtMText.Text;
  s3 := edtCClassName.Text;
  s4 := edtCText.Text;
  ALHandle1:=FindWindow(PChar(s1),PChar(s2));
  if ALHandle1 <> 0 then
    ShowMessage('프로그램을 찾았어요.  핸들:'+IntToStr(ALHandle1))
  // ** 찾지 못 했다면 나갑니다. ** //
  else Exit;
  ALHandle2:=FindWindowEx(ALHandle1,0,PChar(s3),PChar(s4));
  if ALHandle2 <> 0 then
    ShowMessage('버튼을 찾았어요.  핸들:'+IntToStr(ALHandle2))
  // ** 찾지 못 했다면 나갑니다. ** //
  else Exit;

// ** 다음 버튼을 클릭합니다. ** //
  Repeat
    begin
      SendMessage(ALHandle2,WM_LBUTTONDOWN,0,$10001);
      sleep(1);
      SendMessage(ALHandle2,WM_LBUTTONUP,0,$10001);
      inc(Temp);
      if Temp = 10 then exit;
      sleep(100);
    end;
  Until AlHandle2 <> (FindWindowEx(ALHandle1,0,PChar(s3),PChar(s4)));
end;

procedure TfrmInstallOrder.btnClearClick(Sender: TObject);
begin
  edtMClassName.Clear;
  edtMText.Clear;
  edtCClassName.Clear;
  edtCText.Clear;
end;

end.

에디트 박스에 각 클래스 이름과 텍스트를 넣고 버튼을 누르면 '프로그램을 찾았어요', '버튼을 찾았어요'라는 팝업창을 띄워줍니다.
그리고 그 버튼에 마우스 클릭효과를 주어서 단계를 넘깁니다.
하지만 spy에 나온 것처럼 'button'과 '아니오, 컴퓨터를 나중에 다시 시작하겠습니다.'라고 넣으면 '버튼을 찾았어요'라는 메세지가 뜨지 않습니다.

이런 현상이 일어날 수도 있는 건가요?
제가 경험과 지식이 부족해서 해결할 방법을 찾아내지 못하겠네요.
부디 버튼을 찾아 단계를 넘길 수 있는 방법을 아시는 분은 꼭 좀 알려주세요.
질문이 너무 장황해서 죄송합니다.
나름대로 요약해서 올린건데.. 소스를 짜르면 님들께서 혹시 보시기 불편해 하실까봐..
그럼 꼭 부탁 좀 드리겠습니다.
비오는데 정말 소주한잔 생각나네요.. ㅠ.ㅠ
3  COMMENTS
  • Profile
    최용일 2004.05.13 18:50
    안녕하세요. 최용일입니다.

    핸들을 잘못찾으신거 같습니다.

    님이 찾으신 static이란 클래스의 핸들은 918728인데 아래 스파이에서 보이는 핸들은 $11056E이네요. 두 개의 값이 틀린걸 보면 님께서 버튼의 핸들을 제대로 못 찾았다고 생각되네요...

    ^^ 항상 즐코하세요...

  • Profile
    술한잔기울이며 2004.05.13 19:31
    버튼의 핸들을 잘못 찾는다는 말씀을 듣고 간단히 다음과 같이 만들어보았습니다.

    procedure TForm1.Button1Click(Sender: TObject);
    var
      s1, s2, s3, s4 : string;
      AlHandle1, AlHandle2 : THandle;

    begin
      s1 := Edit1.Text;
      s2 := Edit2.Text;
      s3 := Edit3.Text;
      s4 := Edit4.Text;
      AlHandle1 := FindWindow(PChar(s1), PChar(s2));
      if AlHandle1 <> 0 then
        ShowMessage('창을 찾았습니다.');
      AlHandle2 := FindWindowEx(AlHandle1,0,PChar(s3), PChar(s4));
      if AlHandle2 <> 0 then
        ShowMessage('버튼을 찾았습니다.');

    end;

    위의 소스에서 보면 AlHandle1이 질문의 창을 찾는 것이고, AlHandle2가 버튼을 핸들을 저장하는 것이라 생각합니다.

    AlHandle2 := FindWindowEx(AlHandle1,0,PChar(s3), PChar(s4)); 부분이 잘못 되었다는 것인가요?
    하지만 다른 드라이버 설치파일에서는 무리 없이 진행되었는데.
    으앙 도데체 무엇이 문제인지를 모르겠네요.
    제 의견 중 잘못된 부분이 있으면 거침없이 질타하여 주십시요.

  • Profile
    최용일 2004.05.13 20:00
    안녕하세요. 최용일입니다.

    소스가 잘 못되었다는 말은 못하겠네요... 제가 그 윈도우들의 Parent-Child관계를 알 수가 없으니까요... 보여주신 화면에는 이런 관계가 안 나타나거든요...

    제 생각엔 님께서 찾으실려고 하는 컨트롤이 메인윈도우 바로 밑의 Child가 아니라 그 중간에 몇개의 컨트롤들이 더 있으리라 생각합니다.

    윈도우들의 Parent-Child관계를 보여주시면 확실히 답변을 드릴수가 있을거 같네요...

    ^^ 항상 즐코하세요...

    • 최용일
      2004.05.13 19:32
      안녕하세요. 최용일입니다. 델파이소스에 있는 InputBox함수에 한줄만 추가시켰습니다. function I...
    • 유정헌
    • 2004.05.13 08:50
    • 4 COMMENTS
    • /
    • 0 LIKES
    • 유정헌
      2004.05.14 00:22
      정말 도움이많이되었습니다. 감사합니다.
    • 이진기
      2004.05.13 19:38
      procedure TForm1.Timer1Timer(Sender: TObject); var     NewTime: TTime; begi...
    • 석주현
      2004.05.13 19:03
      이런 방법도 있습니다.. 아래를 보면 아시겠지만 TTIme이 double 형이니깐 아래처럼 해서 그 시간들의 ...
    • 바보래요
      2004.05.13 17:41
      우선 타이머의 인터벌을 1000으로 하시구요  1000이 1초거든요... 그리고 버튼을 Enabled...
    • FREEFLY
    • 2004.05.13 07:39
    • 1 COMMENTS
    • /
    • 0 LIKES
    • cell
      2004.05.13 17:34
      원하는 답변은 아니겠지만... Tprinter을 이용해서 출력하세요. 아주 정확하게 위치가 맞출수 있습니다. ...
    • 박미영
    • 2004.05.13 06:29
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 김철홍
      2004.05.13 17:48
      하나의 폼에 다른 폼의 유닛을 추가하세요. 두개의 폼 A, B가 있다고 할때 unitA의 implementation아래에...
    • 미러
    • 2004.05.13 05:54
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 너구리
      2004.05.13 18:53
      한번 델파이에서 Import ActiveX로 등록 해보세요.. 제가 쓰는 컴터도 win2k server인데 다른언어에서 ...
    • 김민우
    • 2004.05.13 04:31
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2004.05.13 19:06
      안녕하세요. 최용일입니다. 자료실에 관련 컴포넌트를 올렸습니다. 참고하세요... DSP에 보시면 이것...
    • 김민우
      2004.05.13 19:09
      정말 정말 감사합니다 시삽님!!!  ^^ 많은 도움이 됐습니다. 시삽님도 즐코하세요~~~
    • 유호성
    • 2004.05.13 03:35
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 바보래요
      2004.05.13 18:25
      Enter = #13 BackSpace = #8  (백스페이스는 정확히 잘 모르것네요...찾아보세요...아스...
    • 최용일
      2004.05.13 18:50
      안녕하세요. 최용일입니다. 핸들을 잘못찾으신거 같습니다. 님이 찾으신 static이란 클래스의 핸들은...
    • 술한잔기울이며
      2004.05.13 19:31
      버튼의 핸들을 잘못 찾는다는 말씀을 듣고 간단히 다음과 같이 만들어보았습니다. procedure TForm1.But...
    • 최용일
      2004.05.13 20:00
      안녕하세요. 최용일입니다. 소스가 잘 못되었다는 말은 못하겠네요... 제가 그 윈도우들의 Parent-Child...
    • 박준철
    • 2004.05.13 02:38
    • 0 COMMENTS
    • /
    • 0 LIKES
    • LuckyBoy
    • 2004.05.13 00:13
    • 5 COMMENTS
    • /
    • 0 LIKES
    • 김요한
      2004.05.13 19:28
      LuckyBoy님께서 원하시는 일을 잘 이해를 못해서 축구경기로 예를 들어 보겠습니다. 경기는 전후반 45...
    • 너구리
      2004.05.13 00:42
      delay 함수가 뭔가요?? 결과를 보기엔 어플리케이션 전체가 3초동안 멈추는게 아닌가 싶은데요.. 그...
    • LuckyBoy
      2004.05.13 01:29
      procedure TIoOperate.Delay(DelayTime: Integer); var   sPast,sNow: Integer; begin  ...
    • 너구리
      2004.05.13 02:27
      무지하게 슬립하는거군요... 분리하고 싶은게 delay가 아니라 timer 아닌가요?? 자료실에 보면 이름...
    • LuckyBoy
      2004.05.13 04:44
      제 질문에 관심 및 답변에 감사드립니다. 말씀하신대로 Sleep을 사용하면 Sleep동안은 멈추지요. 하지...
    • 라용수
    • 2004.05.12 22:46
    • 2 COMMENTS
    • /
    • 0 LIKES
    • nilriri™
      2004.05.26 11:09
    • 채창훈
      2004.05.13 01:36
      안녕하세요.. 정확한 답변이 될 수 있을런지 모르겠네요.. 저는 델파이 5 버젼을 쓰는데 위와 같은 ...
    • 최석기
    • 2004.05.12 20:21
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 박진규
    • 2004.05.12 19:42
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 김지훈
    • 2004.05.12 13:44
    • 4 COMMENTS
    • /
    • 0 LIKES
    • cell
      2004.05.13 00:47
      INSERT INTO test values ('DD', '06/05/2004') 와 같이 날짜형태를 바꿔주면 텍스트 형태의 SQL을 ...
    • cell
      2004.05.13 00:34
      파라메터로 넘기면 되지 않을까요.... sql:=insert  ........... into   value...
    • 바보래요
      2004.05.12 17:48
      sql문장은 string입니다.  그러니 날자는 string로 형태를 바꾸어야 합니다... 물론 다른...
    • 김지훈
      2004.05.12 20:57
      답변감사합니다.. 제가 질문 쿼리를 조금 잘 못쓴거 같습니다.. 예.. datetostr함수를 사용해서 작성 하...
    • 박기선
    • 2004.05.12 10:16
    • 0 COMMENTS
    • /
    • 0 LIKES
    • ㅣㅣ
    • 2004.05.12 09:17
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 바보래요
      2004.05.12 17:50
      계산된 값을 그리드에 넣을때는... StringGrid.Cells[i, j] := IntToStr( i * j ); 이런식이구요...
    • 유정헌
    • 2004.05.12 07:29
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 바보래요
      2004.05.12 17:51
      타이머를 쓰지 않아도 될듯... 시작시 시간을 저장해 두었다가  프로그램을 종료할때 ...
    • 전덕성
    • 2004.05.12 03:12
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 너구리
      2004.05.12 03:36
      말씀하신대로 해상도의 차이인거 같은데요.. 프로퍼티에 있는 height, width 의 단위가 pixel 인거 같은...