::: 델파이 Tip&Trick :::

델파이 Tip&Trick 성격에 맞지 않는 광고,비방,질문의 글은 즉시 삭제하며
내용을 복사하여 사용할 경우 반드시 이곳(http://www.howto.pe.kr)을 출처로 명시하여 주세요


Category

  김영대(2003-03-07 09:21:09, Hit : 4045, Vote : 852
 Keyboard Hook

Product: Delphi32;

Q) How can I create a system wide keyboard hook under Win32?

A) The following example demonstrates creating a system wide windows
hook under Win32. The example provides both the code for the system
hook dll and an example application. The hook function that we will
create will also demonstrate advanced coding techniques such as
sharing global memory across process boundaries using memory mapped
files, sending messages from the key hook function back to the
originating application, and dynamic loading of a dll at runtime.

The example keyboard hook that we create will keep a count of the
number of keystrokes a user enters on the keyboard. Further, we will
demonstrate trapping the enter key, and passing a message back to the
application that initiated the keyboard hook each time the enter key
is pressed. Finally, we will demonstrate trapping the left arrow key
and instead of letting it through to the current application, we will
instead replace it with a right arrow keystroke. (Note: that this can
cause much confusion to a unsuspecting user).

Adding a hook to the windows system involves calling the Windows API
function SetWindowsHookEx() and passing it the type of hook you wish
to install, and address of the hook function you are installing.
System wide hook functions are required to reside in a dynamic link
library, since they must be mapped into each process on the system.
The SetWindowsHookEx() function adds your hook function into the
Windows "hook chain", returning a handle (or id) of the hook you are
installing. You will use this handle to identify your hook to windows,
and to remove your hook when you are done trapping the keyboard.

The Windows "hook chain" is a linked list of functions that Windows
uses to keep track of all the installed hooks, allowing multiple
hooks to be installed at any given time. Occasionally, Windows will
ask your hook function to call the next hook in the chain, allowing
all the hooks an opportunity to function. When we do call the next
hook in the chain, we will need to identify ourselves by passing the
handle of our hook function to the next hook.

Creating a Windows hook requires special handling under Win32, since
the dll must be mapped (on the fly) into the process space of every
application that receives keystrokes. Normally, this is not an issue,
however, when operating inside a keyhook procedure, global variables
(such as your hook handle) must be preserved while the dll is mapped
into other process spaces. Under Win16, this would not be a program,
since dlls had a single data segment that was shared across all
process mappings. Under Win32, each mapping of the dll receives its
own data segment. This means that as the dll that contains the
keyboard hook is mapped into each process that receives keystrokes,
it receives a new data segment, and new unitialized variables with it.
This is a problem, since global variables (such as your hook handle)
must be preserved across process mappings. To solve this problem, we
will take advantage of Win32's ability to memory map variables from
the system paging file.

Each time our dll is mapped into a process, the DllMain() function
in our dll will be called by windows, with a parameter flag indicating
the reason for the call. When we receive the DLL_PROCESS_ATTACH flag
(indicating our dll is getting mapped into a different process), we
will create a file mapping to the system paging file and get a pointer
to our memory mapped variables. When we receive the DLL_PROCESS_DETACH
flag (indicating our dll is getting un-mapped from a process), we will
free our file mapping of the system paging file. The variables we will
need to keep track of (and have access to from both the dll and the
application that originally loaded the keyboard hook) are placed in a
record structure called THookRec. The THookRec structure has the
following fields:

TheHookHandle : The handle (id) of the Keyboard hook that we set. We
will need access to this variable during the execution of the keyhook
function, to identify ourselves to windows when we are asked to call
the next hook in the hook chain. We will also need access to this
variable when we remove our hook. Finally, the originating application
that will receive the messages from our hook function can access this
variable to see if and when the hook is active.

TheAppWinHandle : While this variable is not used in our example dll
or application, it is a starting place for adding additional messaging
capabilities between the hook function and your application that
initiates the hook. It can also be useful for determining if the hook
is functioning while mapped into the context of the initiating
application.

TheCtrlWinHandle : This variable will hold the handle to a button
control in our initiating application. We will use this handle to send
messages from the keyboard hook function to the button control. Every
time the enter key is pressed, we will send a WM_KEYDOWN and a
WM_KEYUP message to the button and a key value of 0 (zero). We will
trap the OnKeyDown event in the button control, and keep count of the
number of times the user presses the enter key.

TheKeyCount : This variable will keep track of the total number of key
presses made by the user. Obviously our keyhook will need access to
this variable to increment its value, and the originating application
that will receive the messages from our hook function will want to
access this variable to display real time results.

The DLL contains the following functions:

MapFileMemory : Creates a system paging file mapping object and
initializes a pointer to our mapping variable of type THookRec.

UnMapFileMemory : Frees the system paging file mapping object and
mapping variable created by the MapFileMemory() function.

GetHookRecPointer : An exported function that returns a pointer to the
mapping variable created by the MapFileMemory() function. The
initiating application can both set and examine this memory block, and
effectively share memory that is used by our hook function during the
time the hook function is operating in the context of another process
space.

KeyBoardProc : The actual hook function. This function receives both
keydown, and keyup messages as well as a message from windows
indicating we should call the next hook in the windows "hook chain".
This function increments TheKeyCount field of the memory mapped
THookRec structure if the keystroke we are processing is a keyup
message. If the key being processed is the enter key, we will fire the
OnKeyDown event of the window provided in "TheCtrlWinHandle" field of
the memory mapped THookRec structure. Finally, if the left arrow key
is pressed, we will swallow the keystroke, and instead send a right
arrow key stroke to the application. Note that the following variables
and initializing code has been included in this function for your
convience. The variables have been commented out in the code (as not
to compile). To use them, simply remove the comments in the code:

  IsAltPressed {Determines if the Alt key is currently down}
  IsCtrlPressed {Determines if the Control key is currently down}
  IsShiftPressed {Determines if the Shift key is currently down}


StartKeyBoardHook : An exported function that allows the application
to initiate installing the keyboard hook;

StopKeyBoardHook : An exported function that allows the application
to initiate removing the keyboard hook;

DllEntryPoint : The main entry point into our dll, allowing us to know
when our dll is being mapped in, and out of, different application's
address space.


Delphi Hook DLL Example:


library TheHook;

uses
  Windows,
  Messages,
  SysUtils;

{Define a record for recording and passing information process wide}
type
  PHookRec = ^THookRec;
  THookRec = packed record
    TheHookHandle : HHOOK;
    TheAppWinHandle : HWND;
    TheCtrlWinHandle : HWND;
    TheKeyCount : DWORD;
  end;

var
  hObjHandle : THandle; {Variable for the file mapping object}
  lpHookRec : PHookRec; {Pointer to our hook record}

procedure MapFileMemory(dwAllocSize : DWORD);
begin
{Create a process wide memory mapped variable}
  hObjHandle := CreateFileMapping($FFFFFFFF,
                                  NIL,
                                  PAGE_READWRITE,
                                  0,
                                  dwAllocSize,
                                  'HookRecMemBlock');
   if (hObjHandle = 0) then begin
     MessageBox(0,
                'Hook DLL',
                'Could not create file map object',
                MB_OK);
     exit;
   end;
{Get a pointer to our process wide memory mapped variable}
  lpHookRec := MapViewOfFile(hObjHandle,
                             FILE_MAP_WRITE,
                             0,
                             0,
                             dwAllocSize);
  if (lpHookRec = NIL) then begin
    CloseHandle(hObjHandle);
    MessageBox(0,
               'Hook DLL',
               'Could not map file',
               MB_OK);
    exit;
  end;
end;

procedure UnMapFileMemory;
begin
{Delete our process wide memory mapped variable}
  if (lpHookRec <> NIL) then begin
    UnMapViewOfFile(lpHookRec);
    lpHookRec := NIL;
  end;
  if (hObjHandle > 0) then begin
    CloseHandle(hObjHandle);
    hObjHandle := 0;
  end;
end;

function GetHookRecPointer : pointer stdcall;
begin
{Return a pointer to our process wide memory mapped variable}
  result := lpHookRec;
end;


{The function that actually processes the keystrokes for our hook}
function KeyBoardProc(Code : integer;
                      wParam : integer;
                      lParam : integer): integer; stdcall;
var
  KeyUp : bool;
{Remove comments for additional functionability
  IsAltPressed : bool;
  IsCtrlPressed : bool;
  IsShiftPressed : bool;
}
begin
  result := 0;

  case Code of
    HC_ACTION : begin
     {We trap the keystrokes here}

     {Is this a key up message?}
      KeyUp := ((lParam AND (1 shl 31)) <> 0);

    (*Remove comments for additional functionability
     {Is the Alt key pressed}
      if ((lParam AND (1 shl 29)) <> 0) then begin
        IsAltPressed := TRUE;
      end else begin
        IsAltPressed := FALSE;
      end;

     {Is the Control key pressed}
      if ((GetKeyState(VK_CONTROL) AND (1 shl 15)) <> 0) then begin
        IsCtrlPressed := TRUE;
      end else begin
        IsCtrlPressed := FALSE;
      end;

     {if the Shift key pressed}
      if ((GetKeyState(VK_SHIFT) AND (1 shl 15)) <> 0) then begin
        IsShiftPressed := TRUE;
      end else begin
        IsShiftPressed := FALSE;
      end;
     *)

     {If KeyUp then increment the key count}
      if (KeyUp <> FALSE) then begin
        Inc(lpHookRec^.TheKeyCount);
      end;

      case wParam of

       {Was the enter key pressed?}
        VK_RETURN : begin
          {if KeyUp}
           if (KeyUp <> FALSE) then begin
            {Post a bogus message to the window control in our app}
             PostMessage(lpHookRec^.TheCtrlWinHandle,
                         WM_KEYDOWN,
                         0,
                         0);
             PostMessage(lpHookRec^.TheCtrlWinHandle,
                         WM_KEYUP,
                         0,
                         0);
           end;
          {If you wanted to swallow the keystroke then return -1}
          {else if you want to allow the keystroke then return 0}
           result := 0;
           exit;
         end; {VK_RETURN}

       {If the left arrow key is pressed then lets play a joke!}
        VK_LEFT : begin
          {if KeyUp}
           if (KeyUp <> FALSE) then begin
            {Create a UpArrow keyboard event}
             keybd_event(VK_RIGHT, 0, 0, 0);
             keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
           end;
          {Swallow the keystroke}
           result := -1;
           exit;
         end; {VK_LEFT}

      end; {case wParam}
     {Allow the keystroke}
      result := 0;
    end; {HC_ACTION}
    HC_NOREMOVE : begin
      {This is a keystroke message, but the keystroke message}
      {has not been removed from the message queue, since an}
      {application has called PeekMessage() specifying PM_NOREMOVE}
      result := 0;
      exit;
    end;
  end; {case code}
  if (Code < 0) then
   {Call the next hook in the hook chain}
    result :=
      CallNextHookEx(lpHookRec^.TheHookHandle,
                     Code,
                     wParam,
                     lParam);
end;

procedure StartKeyBoardHook stdcall;
begin
{If we have a process wide memory variable}
{and the hook has not already been set...}
  if ((lpHookRec <> NIL) AND
      (lpHookRec^.TheHookHandle = 0)) then begin
   {Set the hook and remember our hook handle}
    lpHookRec^.TheHookHandle := SetWindowsHookEx(WH_KEYBOARD,
                                                 @KeyBoardProc,
                                                 hInstance,
                                                 0);
  end;
end;

procedure StopKeyBoardHook stdcall;
begin
{If we have a process wide memory variable}
{and the hook has already been set...}
  if ((lpHookRec <> NIL) AND
      (lpHookRec^.TheHookHandle <> 0)) then begin
   {Remove our hook and clear our hook handle}
    if (UnHookWindowsHookEx(lpHookRec^.TheHookHandle) <> FALSE) then
begin
      lpHookRec^.TheHookHandle := 0;
    end;
  end;
end;

procedure DllEntryPoint(dwReason : DWORD);
begin
  case dwReason of
    Dll_Process_Attach : begin
     {If we are getting mapped into a process, then get}
     {a pointer to our process wide memory mapped variable}
      hObjHandle := 0;
      lpHookRec := NIL;
      MapFileMemory(sizeof(lpHookRec^));
    end;
    Dll_Process_Detach : begin
     {If we are getting unmapped from a process then, remove}
     {the pointer to our process wide memory mapped variable}
      UnMapFileMemory;
    end;
  end;
end;

exports
  KeyBoardProc name 'KEYBOARDPROC',
  GetHookRecPointer name 'GETHOOKRECPOINTER',
  StartKeyBoardHook name 'STARTKEYBOARDHOOK',
  StopKeyBoardHook name 'STOPKEYBOARDHOOK';

begin
{Set our Dll's main entry point}
  DLLProc := @DllEntryPoint;
{Call our Dll's main entry point}
  DllEntryPoint(Dll_Process_Attach);
end.



Application notes:

The test application we have created demonstrates loading the dll that
contains the keyboard hook, installing the key board hook, displaying
the total keystroke count and the number of times the enter key has
been pressed (in real time), uninstalling the keyboard hook and
unloading the dll.


The application code starts out by defining a form containing two
labels, a button, and timer component. Once we install our hook
function, we will start the timer, and upon every timer event, we will
display in label1 the total number of keystrokes that have been
entered by the user since the hook was set. The hook will also fire
the button's OnKeyDown event each time the enter key is pressed,
giving us the opportunity to display the total number of times the
enter key has been pressed in the caption of label2.

After the form is defined, we then define the THookRec structure in
the same manner as it is defined in the hook dll. Other variables
we will use include: a handle variable used for loading the hook dll,
and three function pointer variables used to call the
GetHookRecPointer(), StartKeyBoardHook(), and StopKeyBoardHook()
functions. Finally we define a pointer to a THookRec structure used to
access the memory mapped variables used by the hook function, a
variable to keep track of the number of times the enter key is
pressed, and a variable used to indicate the success of loading the
dll, getting its functions, and setting the hook.

The application logic goes something like this:

On form create, we will initialize our form's components, attempt to
dynamically load the hook dll, and get the address of the
GetHookRecPointer(), StartKeyBoardHook(), and StopKeyBoardHook()
functions located in the hook dll. If we are successful, we will
retrieve a pointer to THookRec structure used by the hook dll, we will
then initialize structure, adding the handle of the button control so
the keyboard hook will know which window control to call when the
enter key is pressed. We will then attempt to start the keyboard hook.
If we are successful, at setting the hook, we can then start the
timer.

On form destroy, if we where previously successful in installing the
windows hook and loading the hook dll, we will now uninstall the
windows hook, and unload the KeyHook dll.

On the timer's timer event, we will simply display the total number of
key presses in the form's label1 caption by accessing the KeyHook
dll's THookRec structure.

On the Buttons KeyDown event, if the key value passed is zero we
increment our EnterKeyCount variable and display the total number of
times the enter key has been pressed by accessing the KeyHook dll's
THookRec structure.

Delphi TestApp Example:

unit TestHk1;

interface

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

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Timer1: TTimer;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{Functions prototypes for the hook dll}
type TGetHookRecPointer = function : pointer stdcall;

type TStartKeyBoardHook = procedure stdcall;

type TStopKeyBoardHook = procedure stdcall;

{The record type filled in by the hook dll}
type THookRec = packed record
  TheHookHandle : HHOOK;
  TheAppWinHandle : HWND;
  TheCtrlWinHandle : HWND;
  TheKeyCount : DWORD;
end;

{A pointer type to the hook record}
type PHookRec = ^THookRec;

var
  hHookLib : THANDLE; {A handle to the hook dll}
  GetHookRecPointer : TGetHookRecPointer; {Function pointer}
  StartKeyBoardHook : TStartKeyBoardHook; {Function pointer}
  StopKeyBoardHook : TStopKeyBoardHook; {Function pointer}
  LibLoadSuccess : bool; {If the hook lib was successfully loaded}
  lpHookRec : PHookRec; {A pointer to the hook record}
  EnterKeyCount : DWORD; {An internal count of the Enter Key}

procedure TForm1.FormCreate(Sender: TObject);
begin
{Set our initial variables}
  Timer1.Enabled := FALSE;
  Timer1.Interval := 1000;
  Label1.Caption := '0 Keys Logged';
  Label2.Caption := '0 Enter Keys Logged';
  EnterKeyCount := 0;
  lpHookRec := NIL;
  LibLoadSuccess := FALSE;
  @GetHookRecPointer := NIL;
  @StartKeyBoardHook := NIL;
  @StopKeyBoardHook := NIL;
{Try to load the hook dll}
  hHookLib := LoadLibrary('THEHOOK.DLL');
{If the hook dll was loaded successfully}
  if hHookLib <> 0 then begin
   {Get the function addresses}
    @GetHookRecPointer :=
      GetProcAddress(hHookLib, 'GETHOOKRECPOINTER');
    @StartKeyBoardHook :=
      GetProcAddress(hHookLib, 'STARTKEYBOARDHOOK');
    @StopKeyBoardHook :=
      GetProcAddress(hHookLib, 'STOPKEYBOARDHOOK');
   {Did we find all the functions we need?}
    if ((@GetHookRecPointer <> NIL) AND
        (@StartKeyBoardHook <> NIL) AND
        (@StopKeyBoardHook <> NIL)) then begin
       LibLoadSuccess := TRUE;
      {Get a pointer to the hook record}
       lpHookRec := GetHookRecPointer;
      {Were we successfull in getting a ponter to the hook record}
       if (lpHookRec <> nil) then begin
        {Fill in our portion of the hook record}
         lpHookRec^.TheHookHandle := 0;
         lpHookRec^.TheCtrlWinHandle := Button1.Handle;
         lpHookRec^.TheKeyCount := 0;
        {Start the keyboard hook}
         StartKeyBoardHook;
        {Start the timer if the hook was successfully set}
         if (lpHookRec^.TheHookHandle <> 0) then begin
           Timer1.Enabled := TRUE;
         end;
       end;
    end else begin
     {We failed to find all the functions we need}
      FreeLibrary(hHookLib);
      hHookLib := 0;
      @GetHookRecPointer := NIL;
      @StartKeyBoardHook := NIL;
      @StopKeyBoardHook := NIL;
    end;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
{Did we load the dll successfully?}
  if (LibLoadSuccess = TRUE) then begin
   {Did we sucessfully get a pointer to the hook record?}
    if (lpHookRec <> nil) then begin
     {Did the hook get set?}
      if (lpHookRec^.TheHookHandle <> 0) then begin
        Timer1.Enabled := FALSE;
        StopKeyBoardHook;
      end;
    end;
   {Free the hook dll}
    FreeLibrary(hHookLib);
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
{Display the number of keystrokes logged}
  Label1.Caption := IntToStr(lpHookRec^.TheKeyCount) + ' Keys Logged';
end;

procedure TForm1.Button1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
{Process message sent from hook dll and display}
{number of time the enter key was pressed}
  if (Key = 0) then begin
    Inc(EnterKeyCount);
    Label2.Caption := IntToStr(EnterKeyCount) + ' Enter Keys Logged';
  end;
end;

end.


[431] 레지스트리의 특정키 검색하기
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  reg: TRegistry;
  rInfo: TRegKeyInfo;
  aList: TStringList;
  i: Integer;
begin
  reg := TRegistry.Create;
  aList := TStringList.Create;
  try
    reg.RootKey := HKEY_LOCAL_MACHINE;
    if reg.OpenKey('Software', False) then // open할 키 지정
      if reg.GetKeyInfo(rInfo) then
      begin
        if rInfo.NumSubKeys > 0 then // 요건 이상하게 도움말에 없어요
        begin
          reg.GetKeyNames(aList); // open한 키에 속한 subkey의 이름을 불러온다
          for i := 0 to rInfo.NumSubKeys -1 do
          begin
            ListBox1.Items.Add(aList.Strings[i])
          end;
        end;
      end;
  finally
    reg.CloseKey;
    reg.Free;
    aList.Free;
  end;

  // HKEY_LOCAL_MACHINE의 Software에 Borland가 있는지 ?
  i := ListBox1.items.IndexOf('Borland');
  if i > -1 then
    ListBox1.ItemIndex := i;
end;

end.





571   [윈도우즈 API] 윈도우즈 '시작' 메뉴 Refresh 시키기  김영대 2003/03/07 4596 1419
570   [윈도우즈 API] 다른 Application의 화면에 글자,그림을 출력하기  김영대 2003/03/07 3374 866
569   [일반/컴포넌트] WideString 을 String 으로 바꾸기  김영대 2003/03/07 4470 1110
568   [윈도우즈 API] 윈도우즈 탐색기의 파일, 컴퓨터 찾기 화면 띄우기  김영대 2003/03/07 6159 1628
567   [일반/컴포넌트] MessageDlg()의 폰트를 바꾸어서 띄우기  김영대 2003/03/07 3860 1066
566   [일반/컴포넌트] ListView 의 item 을 강제로 편집상태로 만들기  김영대 2003/03/07 4636 1213
565   [데이터베이스] 동적으로 SELECT의 GROUP BY 문 만들기  김영대 2003/03/07 4180 945
564   [윈도우즈 API] ALT_F4 hot key 가로채기  김영대 2003/03/07 5625 1610
563   [윈도우즈 API] 레지스트리 전체 검색하기  김영대 2003/03/07 4179 1135
562   [일반/컴포넌트] TOpenDialog 의 '선택','취소' 버튼 이름 바꾸기  김영대 2003/03/07 4351 1333
561   [윈도우즈 API] 모서리가 둥근(rounded ends) TEdit 만들기  김영대 2003/03/07 4845 1285
560   [시스템] 프로그램이 동적으로 할당받은 메모리 크기 ?  김영대 2003/03/07 4533 1294
559   [일반/컴포넌트] OnActivate 이벤트 내에서 폼 확실히 닫기  김영대 2003/03/07 4208 1088
558   [데이터베이스] Query한 결과를 수정하기...  김영대 2003/03/07 4907 1195
557   [일반/컴포넌트] StringGrid의 Cell을 강제로 다중 선택/해제 시키기  김영대 2003/03/07 3989 1006
556   [일반/컴포넌트] TRichEdit의 행간격 띄우기(line spacing)  김영대 2003/03/07 5457 1492
555   [일반/컴포넌트] 프린터로 escape 문자 출력하기(raw print)  김영대 2003/03/07 5014 1247
554   [윈도우즈 API] keyboard, mouse 메시지 무시(skip) 하기  김영대 2003/03/07 4385 1201
553   [윈도우즈 API] 윈도우즈 커서(global cursor) 바꾸기  김영대 2003/03/07 6951 2100
552   [시스템] 현재 프린터의 출력가능한 용지종류 구하기  김영대 2003/03/07 6239 1679
551   [시스템] 프린터에 작업중인 job의 리스트 구하기  김영대 2003/03/07 4828 1240
550   [시스템] Clipboard 훔쳐보기(Clipboard hooking)  김영대 2003/03/07 6902 1583
549   [윈도우즈 API] Control의 repainting 금지하여 깜박임 줄이기  김영대 2003/03/07 5549 1248
548   [일반/컴포넌트] 문자열의 끝에서부터 검색하는 Pos() 함수  김영대 2003/03/07 5120 1176
547   [일반/컴포넌트] 디렉토리명 바꾸기/이동 하기  김영대 2003/03/07 5237 1572
546   [일반/컴포넌트] 디렉토리 변동사항을 탐색기에 알리기  김영대 2003/03/07 5398 1612
545   [일반/컴포넌트] 폼 인쇄하기 2  김영대 2003/03/07 3764 1021
544   [일반/컴포넌트] 연속된 키보드의 키 발생시키기  김영대 2003/03/07 4132 1114
  [시스템] Keyboard Hook  김영대 2003/03/07 4045 852
542   [윈도우즈 API] 레지스트리의 특정키를 파일로 저장/복원하기  김영대 2003/03/07 6526 1485
541   [시스템] PC에 설치된 DirectX 버전 읽기  김영대 2003/03/07 3928 1215
540   [데이터베이스] CD 에 있는 DB 접근하기  김영대 2003/03/07 3882 1117
539   [일반/컴포넌트] 제어판의 applet 리스트 (17개)  김영대 2003/03/07 3412 984
538   [일반/컴포넌트] 투명한 Bitmaps 인쇄  김영대 2003/03/07 7579 1393
537   [일반/컴포넌트] QReport 를 bmp 로 변환하기  김영대 2003/03/07 3231 853
536   [일반/컴포넌트] WMF 를 BMP 로 변환하기  김영대 2003/03/07 4467 1369
535   [일반/컴포넌트] Memo의 입력행수 제한하기  김영대 2003/03/07 4145 1172
534   [시스템] PC의 전원상태 알아보기  김영대 2003/03/07 5872 1709
533   [윈도우즈 API] 파일에서 아이콘 빼내기(32 * 32)  김영대 2003/03/07 6352 1616
532   [윈도우즈 API] 파일에서 아이콘 빼내기(16 * 16)  김영대 2003/03/07 4713 1255

[이전 10개] [1].. 11 [12][13][14][15][16][17][18][19][20]..[25] [다음 10개]
 

Copyright 1999-2022 Zeroboard / skin by zero