Q&A

  • SetWindowsHookEx를 실행 에러, 살려주세요!!!
'ㄱㅣㅁㅇㅠㅅㅣㄴ'처럼 낱개의 한글을 조합하려고 하는데 키보드 후킹을 사용하려는데 SetWindowsHookEx의 KeybdHookProc, 에서 커서가 멈추며 에러가 납니다. 살려주세요.
[Error] Main_U.pas(77): Incompatible types: 'regular procedure and method pointer'

<!--CodeS-->
unit Main_U;

interface

uses
  Windows, SysUtils, StdCtrls, Messages, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, Menus, ExtCtrls, Buttons, MemDS, DB, DBAccess, MSAccess,
  ComCtrls, ShellAPI, jpeg, inifiles, ImgList, ShlObj, ActiveX, ComObj, Registry,
  ADODB, Mask, ToolEdit, CurrEdit, BaseGrid, AdvGrid, RXCtrls, Qt;

type
  TMain_F = class(TForm)
    qryadoTemp: TADOQuery;
    ADOConnection1: TADOConnection;
    gr1: TAdvStringGrid;
    OpenDialog1: TOpenDialog;
    btnExlRead: TRxSpeedButton;
    edtPreHan: TEdit;
    edtChgHan: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnReadClick(Sender: TObject);

  private
    { Private declarations }

  public
    { Public declarations }

    procedure SimulateKeyDown(VirtualKey : Byte);
    procedure SimulateKeyUp(VirtualKey : Byte);
    function KeybdHookProc(Code: Integer; wParam:WPARAM; lParam: LPARAM): LongInt; stdcall;

  end;

var
  Main_F: TMain_F;
  KeybdHook : HHook;

implementation

procedure TMain_F.FormCreate(Sender: TObject);
begin
   KeybdHook := SetWindowsHookEx(WH_KEYBOARD,KeybdHookProc,
                        HInstance,GetCurrentThreadID);
end;

procedure TMain_F.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TMain_F.FormDestroy(Sender: TObject);
begin
  UnHookWindowsHookEx(KeybdHook);
end;

procedure TMain_F.btnReadClick(Sender: TObject);
  tmp_str : string;
begin
      edtChgHan.Setfocus;
       tmp_str := 'ㄱㅏㄴㅏㄷㅏ';

       i := 1;
       while i < length(tmp_str) do
        begin
             if copy(tmp_str,i,2) = 'ㄱ' then
             begin
                 SimulateKeyDown(Ord('r'));
                 SimulateKeyUp(Ord('r'));
             end
              else if copy(tmp_str,i,2) = 'ㅣ' then
              begin
                 SimulateKeyDown(Ord('l'));
                 SimulateKeyUp(Ord('l'));
              end
              else if copy(tmp_str,i,2) = 'ㅁ' then
              begin
                 SimulateKeyDown(Ord('a'));
                 SimulateKeyUp(Ord('a'));
              end;

              i := i + 2;
           end;
        end;
end;

procedure TMain_F.SimulateKeyDown(VirtualKey : Byte); // 키의 down
begin
  keybd_event(VirtualKey,MapVirtualkey(VirtualKey, 0),0,0);
end;

procedure TMain_F.SimulateKeyUp(VirtualKey : Byte); // 키의 up
begin
  keybd_event(VirtualKey,MapVirtualkey(VirtualKey, 0),KEYEVENTF_KEYUP,0);
end;

function TMain_F.KeybdHookProc(Code : Integer; wParam: WPARAM; lParam: LPARAM): LongInt; stdcall;
begin
  if Code >= 0 then
     if ((wParam = 229) and (lParam = -2147483647)) then
     begin
        Result := Integer(True);
        Exit;
     end;
  Result := CallNexthookEx(KeybdHook, Code, wParam, lParam);
end;

end.
<!--CodeE-->
3  COMMENTS
  • Profile
    신철우 2007.01.23 19:28

    관련 함수(1개)와 프로시저(2개)를 선언을 하면 안됩니다.
    그리고 시작전 Application.Processmessage 추가
    한글완성 후 엔터키와 Application.Processmessage 추가
    한글변환입력은 edtChgHan.ImeMode :=imSHanguel
    한글변환은 영어 대문자만 됨.
    아래 소스는 완전한 것임-컴파일 해보심이.

    <!--CodeS-->
    unit Main_U;

    interface

    uses
      Windows, SysUtils, StdCtrls, Messages, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Grids, Menus, ExtCtrls, Buttons, MemDS, DB, DBAccess, MSAccess,
      ComCtrls, ShellAPI, jpeg, inifiles, ImgList, ShlObj, ActiveX, ComObj, Registry,
      ADODB, Mask, ToolEdit, CurrEdit, BaseGrid, AdvGrid, RXCtrls;

    type
      TMain_F = class(TForm)
        edtChgHan: TEdit;
        btnRead: TRxSpeedButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure btnReadClick(Sender: TObject);

      private
        { Private declarations }

      public
        { Public declarations }

    //키포인트 - 선언하면 안됨
    {    procedure SimulateKeyDown(VirtualKey : Byte);
        procedure SimulateKeyUp(VirtualKey : Byte);
        function KeybdHookProc(Code: Integer; wParam:WPARAM; lParam: LPARAM): LongInt;
    stdcall;
    }

      end;

    var
      Main_F: TMain_F;
      KeybdHook : HHook;

    implementation

    //폼에 예속되면 안됨
    function KeybdHookProc(Code : Integer; wParam: WPARAM; lParam: LPARAM): LongInt; stdcall;
    begin
      if Code >= 0 then
         if ((wParam = 229) and (lParam = -2147483647)) then
         begin
            Result := Integer(True);
            Exit;
         end;
      Result := CallNexthookEx(KeybdHook, Code, wParam, lParam);
    end;

    //폼에 예속되면 안됨
    procedure SimulateKeyDown(VirtualKey : Byte); // 키의 down
    begin
      keybd_event(VirtualKey,MapVirtualkey(VirtualKey, 0),0,0);
    end;

    //폼에 예속되면 안됨
    procedure SimulateKeyUp(VirtualKey : Byte); // 키의 up
    begin
      keybd_event(VirtualKey,MapVirtualkey(VirtualKey, 0),KEYEVENTF_KEYUP,0);
    end;

    procedure TMain_F.FormCreate(Sender: TObject);
    begin
       KeybdHook := SetWindowsHookEx(WH_KEYBOARD,KeybdHookProc,
                            HInstance,GetCurrentThreadID);
    end;

    procedure TMain_F.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
    end;

    procedure TMain_F.FormDestroy(Sender: TObject);
    begin
      UnHookWindowsHookEx(KeybdHook);
    end;

    procedure TMain_F.btnReadClick(Sender: TObject);
      tmp_str : string;
    begin
           tmp_str := 'ㄱㅏㄴㅏㄷㅏ';
          edtChgHan.Setfocus;

           Application.Processmessage;  //아주 중요

           i := 1;
           while i < length(tmp_str) do
            begin
                 if copy(tmp_str,i,2) = 'ㄱ' then
                 begin
                     SimulateKeyDown(Ord('R'));
                     SimulateKeyUp(Ord('R'));
                 end
                  else if copy(tmp_str,i,2) = 'ㅣ' then
                  begin
                     SimulateKeyDown(Ord('L'));
                     SimulateKeyUp(Ord('L'));
                  end
                  else if copy(tmp_str,i,2) = 'ㅁ' then
                  begin
                     SimulateKeyDown(Ord('A'));
                     SimulateKeyUp(Ord('A'));
                  end
                  else
                  begin
                     SimulateKeyDown(VK_SPACE);
                     SimulateKeyUp(VK_SPACE);
                  end;

                  i := i + 2;
               end;

               //엔터키로 한글완성
               SimulateKeyDown(VK_RETURN);
               SimulateKeyUp(VK_SPACE);

               Application.Processmessage;  //아주 중요

            end;
    end;

    end.
    <!--CodeE-->
  • Profile
    최용일 2007.01.23 21:22
    SimulateKeyDown, SimulateKeyUp은 메소드로 하든 그냥 일반함수로 하든 별 상관없습니다. 후킹에 사용되는 콜백함수인 KeybdHookProc만 일반함수로 하시면 됩니다. 뭐 메소드로 선언해도 방법이 없는것은 아니구요...

    ^^
  • Profile
    최용일 2007.01.22 23:04
    안녕하세요. 최용일입니다.

    에러 내용 그대로 파라매터에 함수포인터를 넣어야 하는데 메소드포인터를 넣으셔서 그런겁니다.

    KeybdHookProc를 함수포인터로 만드세요...

    <!--CodeS-->
    interface

    ......

    function KeybdHookProc(Code: Integer; wParam:WPARAM; lParam: LPARAM): LongInt; stdcall;

    implementation

    function KeybdHookProc(Code : Integer; wParam: WPARAM; lParam: LPARAM): LongInt; stdcall;
    begin
      if Code >= 0 then
         if ((wParam = 229) and (lParam = -2147483647)) then
         begin
            Result := Integer(True);
            Exit;
         end;
      Result := CallNexthookEx(KeybdHook, Code, wParam, lParam);
    end;
    <!--CodeE-->

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