CoInzBlog

2003-11-03 오전 1:42:10   /  번호: 6687  / 평점:  (8.2) category: VC++ 일반  /  조회: 12,479
 첨부파일 있음윈도우 메시지 후킹 강좌 (첨 해보는 사람들을 위해서) 이은규 / unkyulee  
이은규님께 메시지 보내기  이은규님을 내 주소록에 추가합니다.  이은규님의 블로그 가기   

원래는 워드로 작성했는데 옮기니까 좀 이상허네요

이미지도 안뜨고~

첨부파일에 워드문서로 작성한 강좌랑 샘플 코드 올렸습니다.

^0^)~ 그럼 모두 즐프!

 

 

 

따라해보는 후킹

작성자 : 이은규

작성일 : 2003.11.02

홈페이지 : http://unkyulee.net

 

목차

1. 들어가는 글

2. 후킹이란?

3. 후킹 프로시져를 만들어 보자.

4. 후킹 프로시져를 시작, 종료하는 함수

5. 프로시져 내에서 다른 윈도우로 데이터 전송하기

6. 간단한 샘플 프로그램

 


1. 들어가는 글

 

 "그냥 실행되는 걸 보고 싶었다."

 

 예전에 했던 프로젝트의 내용 중에 사용자가 키보드로 입력하는 내용을 얻어와서 처리해야 되는 부분이 있었다. 이러한 기능을 구현하기 위해서는 후킹 이라는 기술을 사용해야 한다. 그래서 관련된 내용을 인터넷에서 찾아봤는데, 왜 이렇게 알아야 되는 내용이 많은지… 또 내용들은 어찌나 어렵던지… 후킹 구현한답시고 한달 내내 문서 읽고 인터넷 뒤지고 엄청 고생 했었다. 결국 간단한 샘플 코드를 구해서 원하는 기능을 구현 했던 기억이 있다.

 

 프로젝트 내에서 그리 중요한 부분도 아니였고, 그냥 호기심에 후킹이라는 걸 실제로 구현해보고 싶었던 것 뿐이였는데, 정말 어렵게 공부했던 것 같다.

 

 이 강좌는 순전히 호기심으로 혹은 그냥(?) 한번 후킹을 실제로 구현해 보고자 하는 사람들을 대상으로 한다. 후킹에 대한 자세한 이론은 대부분 생략할 예정이다. 대신에 이 강좌를 다 읽고 나면 후킹을 사용한, 일단 돌아가는 코드를 작성 할 수 있을 것이다.

 

 일단 돌아가는 코드를 작성하고 나면, 그 외의 내용을 익히는 것은 시간 문제일 뿐이지 않을까 생각한다. ^0^)

 


2. 후킹이란?

 

 "후킹은 도청하는 걸 예로 들면 쉽게 이해할 수 있다."

 

 후킹이란 다른 프로세스에 걸려서(Hooked) 해당 프로세스의 정보를 얻어 오거나, 변경하는 것이 가능한 기술이다. 여기서 프로세스란 좁게 봐서 "윈도우 프로시져" 혹은 "윈도우 메시지" 라고 생각하면 되겠다.

 

 예를 들어 보자. 한 아파트 건물이 있다고 하자. 그리고 이 건물을 도청하고 싶다. 그럼 전화선들이 지나가는 곳(Window Process) 에 도청 장치(후킹 프로시져)를 설치한다. 그럼 도청장치 사이로 전화 내용들이(Window Message) 지나간다. 도청 장치는 그 중 필요한 메시지를 저장하고 있거나, 필요한 곳으로 전송한다.

 

 위의 과정들에 의해서 빌딩은 도청을 당한다. 그럼 실제 후킹의 경우를 살펴보자. 일단 윈도우 메시지(전화 내용)를 후킹 한다고 하면 윈도우 메시지를 발생시키는 곳(전화선들이 지나가는 곳)에 후킹 프로시져(도청 장치)를 설치한다. 그럼 해당 윈도우에서 발생하는 메시지가 후킹 프로시져를 거쳐가게 된다. 그럼 후킹 프로시져는 메시지들을 보고 필요한 내용을 저장하던지 필요한 곳에 전달을 하면 되는 것이다.

 

 그림 한번 보자. 위 그림은 Ivo Ivanov 라는 사람이 쓴 API Hooking Reveal 라는 문서에서 퍼 가지고 왔다. 그림을 보면 Hook Driver 라는 것들이 3개가 보인다. 그림에서 현재 윈도우가 3 개가 떠있는데 각각의 윈도우에 하나씩 Hook Driver 가 붙어 있는 모양이다. 따라서 이 드라이버(후킹 프로시져) 들이 각각의 윈도우에서 오는 메시지들을 받을 수가 있는 것이다.

 

 뭔가 굉장히 많아 보인다. 하지만 결국 개발자가 만들어 주는 것은 후킹 프로시져 하나이다.

 

 여기서 키포인트는 특정 위도우가 받는 메시지를 후킹 프로시져도 받을 수 있다는 것이다. 이런 기술을 바로 후킹이라고 한다.

 

 


3. 후킹 프로시져를 만들어 보자.

 

 "이론은 끝났다. 이제 만들어 보자."

 

 후킹 프로시져… 아까부터 프로시져라는 단어가 계속 나오는데 결국 프로시져는 함수와 그 의미가 비슷하다. 따라서 후킹 프로시져라고 함은 후킹을 하는 함수라고 생각하자. 따라서 후킹 프로시져를 만든다는 것은 함수를 하나 만든다고 생각하면 된다.

 

 후킹 함수를 만들기 위해서는 지켜야 하는 규칙들이 있다.

1. Call Back 함수이여야 한다.

2. 함수의 마지막 부분에서는 CallNextHookEx() 함수를 호출한다.

3. 함수가 받는 인자는 정해져 있다.

4. 후킹 프로시져는 DLL 안에 있어야 한다.

 

Ex)

//--------------------------------------------------------------

// Hook Procedure - Keyboard

//--------------------------------------------------------------

LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)

{

             if( nCode >= 0 )

             {

            

             }

             // We must pass the all messages on to CallNextHookEx.

           return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );

}

 

 위의 규칙들을 지켜서 만든 후킹 프로시져 함수이다.

 

 4번째 규칙에 의하면 후킹 함수는 DLL 내부에 있어야 한다. Visual C++ 6.0 에서 DLL 프로젝트를 하나 만들어 보자.

 

Step 1. Win32 Dynamic-Link Library 프로젝트 생성

Step 2. Simple 프로젝트 선택 후 Finish

Step 3. cpp 파일에 위의 후킹 함수를 만들어 준다.

 

위의 프로젝트를 컴파일 하면 HookDll.dll 파일이 생성된다.

 

전체 프로젝트 파일 내용

// HookDll.cpp : Defines the entry point for the DLL application.

//

 

#include "stdafx.h"

 

BOOL APIENTRY DllMain( HANDLE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                                                                   )

{

    return TRUE;

}

 

//--------------------------------------------------------------

// Hook Procedure - Keyboard

//--------------------------------------------------------------

LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)

{

             if( nCode >= 0 )

             {

                          

             }

             // We must pass the all messages on to CallNextHookEx.

             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );

}

 

 

 


4. 후킹 프로시져를 시작, 종료하는 함수

 

 이번 단계에서는 앞서 만든 후킹 프로시져를 설치하고, 제거하는 함수를 만들어 보겠다. 후킹 프로시져는 특정 윈도우에 설치가 되어야 제 역할을 할 수 있게 된다. 이때 후킹 프로시져를 설치해주는 함수가 바로 SetWindowsHookEx() 이다. 그 다음에 설치된 후킹 프로시져를 제거하기 위해서는 UnhookWindowsHookEx() 가 쓰이게 된다. 각각의 사용법을 알아보고 앞에서 만든 프로젝트에 이어서 적용시켜 보자.

 

SetWindowsHookEx()의 사용법

HHOOK SetWindowsHookEx(

    int idHook,

    HOOKPROC lpfn,

    HINSTANCE hMod,

    DWORD dwThreadId

);

 

 첫번째 패러메터는 후킹 필터를 설정한다. 후킹 프로시져가 받은 메시지의 종류를 설정하는 항목이다. 예를 들어 WH_GETMESSAGE로 설정하면 모든 메시지를 받게 되고, WH_KEYBOARD로 설정하게 되면 키보드 관련 메시지만 전달 받게 된다. 더 자세한 내용은 MSDN 을 참고하기 바란다.

 

 두번재 패러메터는 후킹 프로시져의 포인터를 지정해야 한다. 간단하게 후킹 프로시져 함수 이름 써주면 된다.

 

 세번째 패러메터는 DLL 의 핸들을 넘겨줘야 된다. 이 값은 앞에서 만든 프로젝트에서 DLlMain() 함수를 보면 HANDLE hModule 값이 넘어오는데 이걸 저장 해놨다가 넘겨주면 된다.

 

 네번째 패러메터는 후킹 프로시져를 설치할 윈도우 값을 넘겨준다. 이번 예에서는 0 을 넘겨준다. 0 을 넘겨주면 후킹 프로시져가 모든 윈도우에 설치가 된다.

 

 이 함수가 리턴하는 값을 잘 저장 해 놓자. 나중에 후킹을 해제할 때 필요하게 된다.

 

Ex) g_HookKeyboard = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;

 

UnhookWindowsHookEx() 의 사용법

 

BOOL UnhookWindowsHookEx(         

             HHOOK hhk

);

 

 이 함수는 후킹 핸들을 받아서 해당 후킹 프로시져를 해제한다. 이때 받는 핸들은 SetWindowsHookEx() 함수가 리턴한 값을 넣어주면 된다.

 

 

프로젝트를 계속 진행 해보자.

 

1. 필요한 전역 변수를 만들어 준다.

//---------------------------------------------------

// Global Variables

// 공용 메모리

//---------------------------------------------------

#pragma data_seg(".HKT")

HINSTANCE g_Module = NULL ;     // DLL Handle

HHOOK g_Hook = NULL ;  // Hook Handle

HWND g_HwndServer = NULL ;      // Hook Server Window Handle

#pragma data_seg()

 

 

2. SetHook, Remove 이라는 함수를 만든다.

//------------------------------------------------------------------// Set Hook

//------------------------------------------------------------------BOOL     SetHook( HWND hWnd )

{

             g_HwndServer = hWnd ;                // Set Hook Server

             g_Hook = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;

             return false ;

}

 

//------------------------------------------------------------------// Remove Hook

//------------------------------------------------------------------BOOL     RemoveHook()

{

             UnhookWindowsHookEx( g_Hook ) ;

             return false;

}

 

 

// HookDll.def 파일 부분

LIBRARY   HookDll

 

SECTIONS

             .HKT   Read Write Shared

 

EXPORTS

             SetImeWindow                 @1

             SetHook                                        @2

             RemoveHook                                 @3

 

 

 

3.. 위의 함수와 전역 변수의 세팅을 위한 [프로젝트명].def 파일을 만들어 준다.

LIBRARY   [프로젝트명]

 

SECTIONS

             .HKT   Read Write Shared

 

EXPORTS

             SetHook                                        @2

             RemoveHook                                 @3

 

 

4. DllMail 함수에서 핸들을 저장한다.

//------------------------------------------------------------------// DllMain : Entry point

//------------------------------------------------------------------BOOL APIENTRY DllMain( HANDLE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                                                                   )

{

             switch (ul_reason_for_call)

             {

             case DLL_PROCESS_ATTACH:

                           g_Module = (HINSTANCE)hModule; // Save Dll Handle

                           break;

 

             case DLL_PROCESS_DETACH:

                           RemoveHook();

                           break;

    }

 

    return TRUE;

}

 

 

전체 프로젝트 파일

 

1. HookDll.cpp

// HookDll.cpp : Defines the entry point for the DLL application.

//

 

#include "stdafx.h"

 

//---------------------------------------------------

// Global Variables

// 공용 메모리

//---------------------------------------------------

#pragma data_seg(".HKT")

HINSTANCE g_Module = NULL ;     // DLL Handle

HHOOK g_Hook = NULL ;  // Hook Handle

HWND g_HwndServer = NULL ;      // Hook Server Window Handle

#pragma data_seg()

 

BOOL    RemoveHook() ;

BOOL    SetHook( HWND hWnd ) ;

 

//------------------------------------------------------------------

// DllMain : Entry point

//------------------------------------------------------------------

BOOL APIENTRY DllMain(

                                                                                HANDLE hModule,

                                                                                DWORD  ul_reason_for_call,

                                                                                LPVOID lpReserved

                                                                  )

{

             switch (ul_reason_for_call)

             {

             case DLL_PROCESS_ATTACH:

                           g_Module = (HINSTANCE)hModule; // Save Dll Handle

                           break;

                          

             case DLL_PROCESS_DETACH:

                           RemoveHook();

                           break;

    }

            

    return TRUE;

}

 

//--------------------------------------------------------------

// Hook Procedure - Keyboard

//--------------------------------------------------------------

LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)

{

             if( nCode >= 0 )

             {

                          

             }

             // We must pass the all messages on to CallNextHookEx.

             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );

}

 

//------------------------------------------------------------------

// Set Hook

//------------------------------------------------------------------

BOOL    SetHook( HWND hWnd )

{

             g_HwndServer = hWnd ;                // Set Hook Server

             g_Hook = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;

            

             return false ;

}

 

//------------------------------------------------------------------

// Remove Hook

//------------------------------------------------------------------

BOOL    RemoveHook()

{

             UnhookWindowsHookEx( g_Hook ) ;

             return true ;

}

 

 

2. HookDll.def 파일

LIBRARY   HookDll

 

SECTIONS

.HKT   Read Write Shared

 

EXPORTS

SetHook                                        @2

RemoveHook                                 @3

 

 

프로젝트를 컴파일 하면 HookDll.lib 와 HookDll.dll 파일이 생성이 된다.


5. 프로시져 내에서 다른 윈도우로 데이터 전송하기

 

 이번에는 앞서 만든 후킹 프로시져를 좀더 강화해보기로 하자. 후킹 프로시져 내에서 메시지를 받고 받은 메시지를 복사하여 특정 윈도우에게 보낼 것이다.

 

 이때 WM_COPYDATA 메시지를 생성 할 것이다.

 

1. WM_COPYDATA 로 보낼 데이터의 구조를 정의한다.

// 메시지를 저장하는 구조체

typedef struct

{

             int                       Type ;

             WPARAM            Data ;

             LPARAM              lParam ;

} HEVENT;

 윈도우 메시지의 내용을 저장할 구조체

 

 

2. 현재의 메시지를 복사한다.

COPYDATASTRUCT  CDS;

HEVENT          Event;

 

// Set CDS

CDS.dwData = 0 ;

CDS.cbData = sizeof(Event);

CDS.lpData = &Event;

 

// 메시지의 내용을 저장한다.

Event.Type = 1 ;               // It's WM_KEY..

Event.Data = wParam ;     // Send CharCode

Event.lParam = lParam ;

 

 

3. g_HwndServer 에게로 메시지를 전달한다.

// g_HwndServer  에게로 메시지를 날린다.

// g_HwndServer 는 SetHook 함수 호출시 저장한 윈도우 핸들이다.

::SendMessage( g_HwndServer , WM_COPYDATA , 0 , (LPARAM)(VOID*)&CDS ) ;

 

 

 

프로젝트를 계속 진행 해보자.

 

1. 앞선 프로젝트의 내용 중 KeyboardProcedure() 함수의 내용을 수정한다.

 

//------------------------------------------------------------------

// Hook Procedure - Keyboard

//------------------------------------------------------------------

LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)

{

             if( nCode >= 0 )

             {

                           // Send To HookServer

                           COPYDATASTRUCT  CDS;

                           HEVENT          Event;

                           // Set CDS

                           CDS.dwData = 0 ;

                           CDS.cbData = sizeof(Event);

                           CDS.lpData = &Event;

                           // Set Variables

                           Event.Type = 1 ;               // It's WM_KEY..

                           Event.Data = wParam ;     // Send CharCode

                           Event.lParam = lParam ;

                          

                            ::SendMessage( g_HwndServer , WM_COPYDATA , 0 , (LPARAM)(VOID*)&CDS ) ;    

             }

 

             // We must pass the all messages on to CallNextHookEx.

             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );

}

 

 

2. Event 구조체를 정의 해준다.

typedef struct

{

             int                       Type ;

             WPARAM            Data ;

             LPARAM              lParam ;

} HEVENT;


6. 간단한 샘플 프로그램

 

 지금까지 만들어 본 후킹 프로시져를 가지고 실제로 샘플 프로그램을 작성해보자.

 

 

1. 프로젝트를 생성한다.

             - MFC 다이얼로그

 

2. 위의 프로젝트를 컴파일 하면 HookDll.lib 와 HookDll.dll 파일이 생성이 된다. 이 파일을 새롭게 생성할 프로젝트 폴더에 복사한다.

 

3. 프로젝트를 세팅한다.

             - 메뉴에서 Project -> Setting -> Link 탭에서 Object/Modules Library 칸에 HookDll.lib 를 지정한다.

 

 

 

4 . 다이얼로그를 위의 모양같이 만들어 주고

에디트 컨트롤을 생성하고 다음과 같이 변수를 연결해준다..

 

ID : IDC_EDIT_CNT

Value : m_Cnt

Type : int


5. 클래스 위저드로 WM_COPYDATA 메시지 핸들러를 생성한다.

BOOL CHookTestDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)

{

             // TODO: Add your message handler code here and/or call default

            

             // WM_COPYDATA 메시지가 올때마다 카운트를 증가한다.

             m_Cnt++ ;

             UpdateData( false ) ;

 

             return CDialog::OnCopyData(pWnd, pCopyDataStruct);

}

 

위와 같이 수정해준다.

 

6. DLL 에 있는 함수를 사용하기 위해 헤더 파일에 다음을 추가한다.

BOOL    RemoveHook() ;

BOOL    SetHook( HWND hWnd ) ;

 

 

7. InitDialog() 함수에서 SetHook() 함수를 호출한다.

BOOL CHookTestDlg::OnInitDialog()

{

             CDialog::OnInitDialog();

 

             // Add "About..." menu item to system menu.

 

             // IDM_ABOUTBOX must be in the system command range.

             ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

             ASSERT(IDM_ABOUTBOX < 0xF000);

 

             CMenu* pSysMenu = GetSystemMenu(FALSE);

             if (pSysMenu != NULL)

             {

                           CString strAboutMenu;

                           strAboutMenu.LoadString(IDS_ABOUTBOX);

                           if (!strAboutMenu.IsEmpty())

                           {

                                        pSysMenu->AppendMenu(MF_SEPARATOR);

                                        pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

                           }

             }

 

             // Set the icon for this dialog.  The framework does this automatically

             //  when the application's main window is not a dialog

             SetIcon(m_hIcon, TRUE);                           // Set big icon

             SetIcon(m_hIcon, FALSE);                          // Set small icon

            

             // TODO: Add extra initialization here

             SetHook( this->GetSafeHwnd() ) ; // 후킹 프로시져 설치

            

             return TRUE;  // return TRUE  unless you set the focus to a control

}

 

자 이제 실행하면 키보드를 칠 때마다 카운트가 증가하는 프로그램이 완성이 되었다.

 

이 글에 평점 주기:  
 
  2003-11-04 09:55:00
 Re:  까막 / crowback  
까막님께 메시지 보내기  까막님을 내 주소록에 추가합니다.  까막님의 블로그 가기   
아.. 이거 읽구 첨으로 후킹이란걸 해봤는데.. 정말 쉽게 이해가 가는군요.. ^^;
지금 래핑해가지구.. 제 개인 자료실에 꼭 꼭 담아 놨습니다.
앞으로도 좋은 강좌 많이 올려주세요.. ^^;
  2003-11-07 16:32:00
 Re:  홍길동 / myunghoon  
홍길동님께 메시지 보내기  홍길동님을 내 주소록에 추가합니다.  홍길동님의 블로그 가기   
저 근데..COPYDATASTRUCT CDS; 에 HEVENT Event;를 설정해야만 숫자가 올라가는데..이건 왜 그런거지요?? Event를 설정 안하면 다른 프로세스에서 키보드를 눌렀을때 WM_COPYDATA가 안오던데...이유를 모르겠네요..
  2003-11-24 15:47:00
 Re:   박희웅 / ultracom  
박희웅님께 메시지 보내기  박희웅님을 내 주소록에 추가합니다.  박희웅님의 블로그 가기   
최고입니다.!
  2004-01-18 13:04:00
 Re:  핸드브이 / kimjua  
핸드브이님께 메시지 보내기  핸드브이님을 내 주소록에 추가합니다.  핸드브이님의 블로그 가기   
근데 카운트가 한번에 두개씩 올라가던데요..(누르고있음 막 올라감;;)
1개씩 올라가게 할수는 없나요?
  2004-08-09 00:22:00
 Re: 슬픔  꺼비 / ggubby  
꺼비님께 메시지 보내기  꺼비님을 내 주소록에 추가합니다.  꺼비님의 블로그 가기   
다른님들은 모두 lib파일이 빌드시 생성되나 봐요? 전 아무리 따라해도 빌드하면 lib파일이 생성되질 않아서 지금 죽을 맛입니다. .... 왜 이런건지 제발좀 알려주세요
  2004-09-16 18:45:00
 Re: 좋음  김진혁 / jinh  
김진혁님께 메시지 보내기  김진혁님을 내 주소록에 추가합니다.  김진혁님의 블로그 가기   
좋은 팁이였습니다. 저에게 도움이 많이된 자료였네요 ^ ^
  2004-12-01 16:05:00
 Re: 좋음  똥꼬녕 / kor3084  
똥꼬녕님께 메시지 보내기  똥꼬녕님을 내 주소록에 추가합니다.  똥꼬녕님의 블로그 가기   
어려워서 이해하긴 쉽지않지만 따라하기식으로 쉽게 알려주기위해 노력하신게 눈에 보이네요
초보자로서 너무 감사드리며 앞으로도 많은 가르침 올려주세요
다시한번 감사드립니다.
  2004-12-04 11:12:00
 Re: 좋음  주먹발사 / jumukbalsa  
주먹발사님께 메시지 보내기  주먹발사님을 내 주소록에 추가합니다.  주먹발사님의 블로그 가기   
강좌 감사말씀먼저 드립니다... 헌데 질문이 있습니다.
님의 강좌를 적용해본결과 dll을 로드시켜 후킹 중 다른 윈도우를 클릭하고 다시 후킹을 중지시킨 후 다시 후킹을 설치하려고 하면 실패해버립니다.
이것저것 다 해봐도 도무지 안되는군요..
  2005-05-31 00:54:00
 Re: 좋음  emanwon / emanwon  
emanwon님께 메시지 보내기  emanwon님을 내 주소록에 추가합니다.  emanwon님의 블로그 가기   
최고~ㅆㅆ
  2005-09-07 11:15:00
 Re: 좋음  정영철 / aslongas3  
정영철님께 메시지 보내기  정영철님을 내 주소록에 추가합니다.  정영철님의 블로그 가기   
정말 좋은 강좌 였습니다.

완벽하게는 아니지만... 대충 이해도 되었구요...

그런데... HookTest.exe를 실행하고 다른 windows의 메시지를 후킹하다가

그중에서 하나의 window를 죽이면 모든 window 에서 후킹이 중지되는 현상이 있습니다.

이건 원래 그런가요..?? 아님 코드가 잘 못된 것인가요..? 아님.. 제가 테스트를 잘 못한건가요..???
  2005-09-07 11:26:00
 Re: 좋음  정영철 / aslongas3  
정영철님께 메시지 보내기  정영철님을 내 주소록에 추가합니다.  정영철님의 블로그 가기   
아~~ 그리고 마우스를 클릭 했을때 카우트가 하나 올라가던데..

이건 왜 그런가요..??

마우스 이벤트가 WH_KEYBOARD 에 포함이 되는건가요..??
  2005-11-24 15:48:00
 Re: 슬픔  신새롬 / choco082  
신새롬님께 메시지 보내기  신새롬님을 내 주소록에 추가합니다.  신새롬님의 블로그 가기   
.그림은..사라졌네요..흑..

 

Comment +0