'Programmings'에 해당되는 글 51건

  1. 2009.05.29 IME 입력모드 설정 5
  2. 2009.05.29 레지스트리(Registry)
  3. 2009.05.28 다른 윈도우에서의 GetFocus() 사용하기
  4. 2009.05.26 서브클래싱
  5. 2009.05.18 GetWindowThreadProcessId()
  6. 2009.05.15 GetModuleFileNameEx()
  7. 2009.04.27 DllMain
  8. 2009.04.24 DLL 제작 (Explicit)
  9. 2009.04.23 DLL 제작 (Implicit 연결)
  10. 2009.04.23 DLL 이란...
2009. 5. 29. 17:47

IME 입력모드 설정



화상 키보드를 만들다가 한글 IME관련 처리를 하기위해 자료를 찾다가 다시 찾을까 겁이나서 포스팅!!
아래의 함수들을 사용해서 생각보다 쉽게 IME의 상태를 알아 올수 있다. 단점은 현재 자신의 프로그램 내의 IME만 알아오거나 바꾸는 것이 가능하고, 다른 프로그램것은 되질 않는다.

IME해당 함수를 사용하기 위해서는 Imm.h와 Imm32.lib를 포함해주어야 한다. Imm.h 는 windows.h에 포함되어 있으므로 생략해도 된다.

해당 윈도우의 Input Context를 가져오는 함수이다. 리턴값으로 Input Context의 핸들을 반환한다.
HIMC ImmGetContext ( HWND hWnd );
hWnd - input context를 받을 윈도우의 핸들

Input Context를 릴리즈 하고, Context에 할당된 메모리를 unlock 한다.
ImmGetContext()를 사용했다면, 반드시 ImmReleaseContext()를 사용해주어야 한다.
BOOL ImmReleaseContext ( HWND hWnd,
                                             HIMC hIMC
                                            );
hWnd - input context를 릴리즈할 윈도우의 핸들
hIMC - input context의 핸들

Conversion Status를 가져온다.
BOOL ImmGetConversionStatus ( HIMC hIMC,
                                                      LPDWORD lpfdwConversion,
                                                      LPDWORD lpfdwSentence
                                                    );
hIMC - 정보를 알고 싶은 input context의 핸들
lpfwdConversion - IME Conversion mode 값
lpfwdSentence - Sentence mode 값

현재 윈도우의 Conversion Status를 원하는 값으로 설정한다.
BOOL ImmSetConversionStatus ( HIMC hIMC,
                                                     DWORD fdwConversion,
                                                     DWORD fdwSentence
                                                    );
hIMC - input context 핸들, NULL이면 현재 active 상태인 context를 설정
lpfwdConversion - IME Conversion mode 값
lpfwdSentence - Sentence mode 값


IME Conversion Mode
              Value                                    Description
IME_CMODE_CHARCODE             Set to 1 if character code input mode; 0 if not.
IME_CMODE_EUDC                        Set to 1 if EUDC conversion mode; 0 if not.
IME_CMODE_FULLSHAPE               Set to 1 if full shape mode; 0 if half shape mode.
IME_CMODE_HANJACONVERT        Set to 1 if HANJA convert mode; 0 if not.
IME_CMODE_KATAKANA                 Set to 1 if KATAKANA mode; 0 if HIRAGANA mode.
IME_CMODE_NATIVE                   Set to 1 if NATIVE mode; 0 if ALPHANUMERIC mode.
IME_CMODE_NOCONVERSION       Set to 1 to prevent processing of conversions by IME;
                                                       0 if not.
IME_CMODE_ROMAN                      Set to 1 if ROMAN input mode; 0 if not.
IME_CMODE_SOFTKBD                   Set to 1 if Soft Keyboard mode; 0 if not.


아래는 현재 윈도우의 한영 모드를 알아와서, 한글모드이면 영문으로, 영문모드이면 한글모드로 세팅을 바꾸는 간단한 예제의 함수이다.
void Imm()
{
    HIMC h_imc;
    DWORD conv, sentence;

    h_imc = ImmGetContext(hWnd);
    BOOL ime_flag = ImmGetConversionStatus(h_imc, &conv, &sentence);

    if(ime_flag)
    {
        if(conv & IME_CMODE_NATIVE){                    // 한글
            ...
            conv = IME_CMODE_CHARCODE;
            ImmSetConversionStatus(h_imc, conv, sentence);
            ...           
        }
        else{                                                                // 영어
            ...
conv = IME_CMODE_NATIVE;
            ImmSetConversionStatus(h_imc, conv, sentence);
            ...
        }
        ime_flag = ImmReleaseContext(focus, h_imc);
    }
    else
        ...
}

추가로 참고는 MSDN을 활용하면 될 듯 하다.


'Programmings > Windows Programming' 카테고리의 다른 글

GetLastError()  (0) 2009.07.16
WinIO  (0) 2009.06.23
레지스트리(Registry)  (0) 2009.05.29
다른 윈도우에서의 GetFocus() 사용하기  (0) 2009.05.28
서브클래싱  (0) 2009.05.26
2009. 5. 29. 15:43

레지스트리(Registry)


프로그램은 실행중에 사용자가 입력한 옵션 설정이나 프로그램 스스로 만들어낸 정보들을 다음 실행을 위해서 저장을 해두어야 할 필요가 있다. 레지스트리(Registry)는 프로그램 실행중에 일어나는 상황이라든지 프로그램의 설정 정보를 저장하기 위해 사용된다. 저장의 대상은 사용자의 신상, 프로그램의 위치, 크기, 옵션, 설정 등의 프로그램 동작에 필요한 모든 정보가 될 수 있다.
이러한 레지스트리 설정을 통해 프로그램이 다음 실행시에도 이전의 상태 그대로를 유지 할 수 있는 것을 볼 수 있다.

등록된 레지스트리를 보거나 수정을 하려면 시작->실행에서 regedit를 입력후 엔터키를 치면 확인할 수 있다.

레지스트리를 다루는 데 주로 사용되는 함수들은 아래와 같다.

레지스트리 키를 생성하는 함수이다. 이미 키가 생성되어 있는 상태라면 해당 키를 열기만 한다. 이 함수의 인수는 9개로 많기는 하지만, 대부분의 인수는 디폴트로 적용된다.
LONG RegCreateKeyEx(
                                    HKEY hKey,
                                    LPCTSTR LpSubKey,
                                    DWORD Reserved,
                                    LPTSTR lpClass,
                                    DWORD dwOptions,
                                    REGSAM samDesired,
                                    LPSECURITU_ATTRIBUTES  lpSecurityAttributes,
                                    PHKEY phkResult,
                                    LPDWORD lpdwDisposition
                                   );
hKey - 새로 만들어지는 키의 부모키를 지정한다.
            응용 프로그램들이 주로 사용하는 키는  HKEY_CURRENT_USER 키이고, 이 키 아래 Software 서브
            키에 자신의 서브키를 생성하여 사용한다.
            운영체제에 의해 사용할 수 있는 키는 아래와 같다.
              HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, ....

lpSubKey - 만들고자(혹은 열고자) 하는 서브키를 지정하는 널을 포함하는 문자열로 반드시 지정해 주어야
                   한다.

Reserved - 예약..

lpClass - 생성되는 키의 클래스를 지정하는 문자열이다.
                이미 존재하는 키를 오픈할 때 이 인수는 무시되고, 클래스를 지정하지 않을 때에는 NULL로 설정
                한다.

dwOptions - 생성하는 키의 옵션을 지정한다.(키를 생성할 때만 적용된다.)
                     REG_OPTION_NON_VOLATILE
                     REG_OPTION_VOLATILE
                     REG_OPTION_BACKUP_RESTORE

samDesired - 새로 만들어지는 키의 보안 속성을 설정한다.

lpSecurityAttributes - 키값이 차일드 프로세스로도 상속 될 것인가를 지정하는 SECURITY_ATTRIBUTE
                                   구조체의 포인터이다. NULL이면 상속되지 않는다.

phkResult - 만들어지거나 열려진 키값이 대입되는 변수의 포인터이다.
                   이 인수가 지정한 변수에 생성된(열린) 키값을 리턴한다. 리턴값은 HKEY형의 현수이다.

lpdwDisposition - 키가 새로 생성되었는지 기존의 키가 오픈 된것인지를 리턴받기 위한 출력용 변수이다.
                             REG_CREATED_NEW_KEY : 생성된 키,
                             REG_OPENED_EXISTING_KEY : 기존의 키가 오픈된 것
예)
RegCreateKeyEx ( HKEY_CURRENT_USER, "Software\\Wizntec\\RegiTest\\Position", 0, NULL,
                           REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &dwDisp );

RegCreateKeyEx()에 의해 열려진 레지스트리 키는 아래의 RegSetValueEx()함수를 통해서 조작할 수 있다.
LONG RegSetValueEx( HKEY hKey,
                                      LPCTSTR lpValueName,
                                      DWORD Reserved,
                                      DWORD dwType,
                                      CONST BYTE *lpData,
                                      DWORD cbData
                                     );
hKey - 값을 저장하고자 하는 키 핸들
lpValueName - 값의 이름을 지정하는 문자열, 해당 키에 값이 없으면 새로 생성해서 데이터를 저장한다.
dwType - 값의 형(type), 대부분 정수형(REG_DWORD)과 문자열(REG_SZ)를 사용한다.
lpData - 저장하고자 하는 데이터의 포인터이다.
cbData - 데이터의 크기 값


RegCreateKeyEx()에 의해 오픈된 레지스트리로부터 RegQueryValueEx()를 사용해서 값을 읽어올 수 있다.
LONG RegQueryValueEx( HKEY hKey,
                                           LPTSTR lpValueName,
                                           LPDWORD lpReserved,
                                           LPDWORD lpType,
                                           LPBYTE lpData,
                                           LPDWORD lpcbData
                                         );
첫 번째 ~ 세 번째 인수는 이전과 동일.
lpType - 읽은 값의 타입을 대입받을 변수의 포인터
lpData - 읽혀진 값을 대입받을 변수의 번지
lpcbData - 이 변수의 크기값을 가지는 변수의 번지


RegOpenKeyEx() 함수는 레지스트리를 열기만 하는 함수이다. 보통 RegCreateKeyEx()를 주로 이용하여 잘 사용되지 않는 함수이다.
LONG RegOpenKeyEx( HKEY hKey,
                                      LPCTSTR lpSubKey,
                                      DWORD ulOptions,
                                      PHKEY phkResult
                                    );


마지막으로 열려진 레지스트리 키를 닫는 함수이다.
LONG RegCloseKey( HKEY hKey );

레지스트리의 예제는 윈도우즈 API 정복을 참조했으며 아래 파일을 통해 테스트 하면 된다.


'Programmings > Windows Programming' 카테고리의 다른 글

WinIO  (0) 2009.06.23
IME 입력모드 설정  (5) 2009.05.29
다른 윈도우에서의 GetFocus() 사용하기  (0) 2009.05.28
서브클래싱  (0) 2009.05.26
GetWindowThreadProcessId()  (0) 2009.05.18
2009. 5. 28. 16:02

다른 윈도우에서의 GetFocus() 사용하기



일반적으로 포커스를 가진 윈도우의 핸들을 가져오거나 지정하는데 사용되는 함수는 GetFocus(), SetFocus()이다. 하지만, 이들 함수들은 모든 윈도우의 포커스를 가져오는 것이 아니고, 현재 윈도우 내의 포커스를 가진 핸들을 가져오는 함수이다.

쉽게 말하자면, 자신의 윈도우에서 포커스를 가진 특정 윈도우(버튼, 에디트 박스 등)의 핸들을 가져올 때 사용하는 것은 문제가 없을 것이지만, 다른 윈도우를 대상으로 이 함수를 쓰게 된다면, 우리가 원하는 핸들 대신 NULL 값을 가져오게 될 것이다.
NULL 값을 가져온 경우 포커스를 가진 윈도우가 다른 스레드 메시지 큐에 있기 때문이다.

하지만, 이에 대한 해결 방법이 있다.
먼저 GetForegroundWindow() 를 사용하여 실제 포커스를 가진 윈도우의 최상위 부모 핸들을 얻는다. 그리고  이 윈도우의 스레드를 구해(GetWindowThreadProcessId()) 현재 스레드에 연결(AttachThreadInput())하면 된다. 이 후에 GetFocus()를 호출하게 되면, NULL 값이 아닌 포커스를 가진 다른 윈도우의 핸들을 가져오는 것을 확인 할 수 있다.

MDDN에서는 GetFocus에 대해 이렇게 설명하고 있다.

The GetFocus function retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.

Syntax

 HWND GetFocus(VOID);

Return Value

 The return value is the handle to the window with the keyboard focus. If the calling thread's message queue does not have an associated window with the keyboard focus, the return value is NULL.


Remarks

 GetFocus returns the window with the keyboard focus for the current thread's message queue. If GetFocus returns NULL, another thread's queue may be attached to a window that has the keyboard focus.

 Use the GetForegroundWindow function to retrieve the handle to the window with which the user is currently working. You can associate your thread's message queue with the windows owned by another thread by using the AttachThreadInput function.

 Windows 98/Me and Windows NT 4.0 SP3 and later:To get the window with the keyboard focus on the foreground queue or the queue of another thread, use the GetGUIThreadInfo function.


간단하게 예를 들어보면, 아래와 같은 방법으로 다른 윈도우의 포커스를 가져올 수 있다.
HWND hWnd = GetForegroundWindow();
DWORD fromId = GetCurrentThreadId();
DWORD toId = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(fromId, toId, TRUE);
HWND focus = GetFocus();

참고 웹사이트 ( http://ditongs.egloos.com/1353649 )

'Programmings > Windows Programming' 카테고리의 다른 글

IME 입력모드 설정  (5) 2009.05.29
레지스트리(Registry)  (0) 2009.05.29
서브클래싱  (0) 2009.05.26
GetWindowThreadProcessId()  (0) 2009.05.18
GetModuleFileNameEx()  (0) 2009.05.15
2009. 5. 26. 10:51

서브클래싱



서브클래싱(SubClassing)이란 윈도우 프로시저로 전달되는 메시지를 중간에 가로채는 방법이다. 중간에서 메시지를 조작하게 됨으로써 윈도우의 모양을 변경하거나 동작을 감시하거나 하는 작업을 할 수 있게 되는 것이다.

윈도우는 CreateWindow()를 통해 만들어진다. 이 때 CreateWindow()의 첫번 째 인수인 윈도우 클래스에서 윈도우 생성에 필요한 정보를 구하게 되는데, 그 중 가장 중요한 것이 메시지를 처리하는 윈도우 프로시저의 번지(lpfnWndProc)이다. 이는 윈도우 클래스에 보관되는 것이 아니고 윈도우별로 별도로 보관된다.

윈도우는 메시지를 받게 되면 해당 윈도우의 윈도우 프로시저 번지를 조사한 후 조사된 번지로 메시지를 보내고 메시지를 받은 윈도우 프로시저는 이 메시지를 받아 해당 윈도우에서 작성한 코드대로 처리를 하게 된다.
이 때 윈도우 프로시저를 다른 윈도우 프로시저로 변경을 한다면, 모든 메시지는 새로 만든 윈도우 프로시저로 전달이 될 것이다.
이렇게 새로 만들어진 윈도우 프로시저를 서브클래스 프로시저(SubClass Procedure)라고 한다.
윈도우 프로시저의 번지를 변경하기 전에 원래의 윈도우 프로시저 번지를 보관해 두고 서브클래스 프로시저에서 처리하지 않은 메시지는 반드시 원래 윈도우 프로시저로 전달하도록 해야한다.

서브클래스 프로시저를 등록하기 위해서는 아래와 같은 함수를 사용한다.
LONG_PTR SetWindowLongPtr( HWND          hWnd,
                                              int               nIndex, 
                                              LONG_PTR  dwNewLong )

hWnd - 프로시저를 바꾸려는 윈도우에 속한 클래스의 핸들
nIndex - MSDN 참고
             GWL_EXSTYLE : Sets a new extended window style
             GWL_STYLE : Sets a new Window style
             GWLP_WNDPROC : Sets a new address for the window procedure.
             GWLP_HINSTANCE : Sets a application instance handle.
             ...
dwNewLong - 대체할 값(프로시져)을 지정.

예)
원래번지 = SetWindowLongPtr(변경 윈도우, GWLP_WNDPROC, 서브클래스 프로시져);
위와 같이 하면, 변경 윈도우로 보내지는 모든 메시지는 일단 서브클래스 프로시져로 전달 될 것이다.
변경 윈도우는 일반적인 윈도우가 될 수도 있고, 버튼, 에디트박스와 같은 윈도우도 될 수 있다. 버튼이나 에디트박스가 변경 윈도우가 될 경우 그 윈도우에서 처리하고 싶은 이벤트, 메시지에 관련된 부분을 서브클래스 프로시져에 넣어주면 된다.

추가로 서브클래스 프로시져를 작성한다.
LRESULT CALLBACK 프로시져(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    switch(iMessage){
    case XXX:
        ...
        break;
    }
    return CallWindowProc(원래번지, hWnd, iMessage, wParam, lParam);
}

CallWindowProc() 는 위 예제의 서브클래스의 case 에 속하지 않은 메시지를 처리하는 부분이다. 이 메시지들은 lpPrevWndFunc에 정의된 윈도우 프로시져로 보내저 처리가 될 것이다.
LRESULT CallWindowProc (WNDPROC  lpPrevWndFunc,
                                        HWND        hWnd,
                                        UINT          Msg,
                                        WPARAM    wParam,
                                        LPARAM     lParam )
lpPrevWndFunc - 서브클래스 등록(SetWindowLongPtr)시 리턴된 값으로 원래의 윈도우 프로시저(번지)
hWnd - 메시지를 받을 윈도우 프로시저의 핸들
Msg - 메시지 내용
wParam - 메시지의 추가적인 정보
lParam - 메시지의 추가적인 정보

예)
return CallWindowProc(원래번지, hWnd, iMessage, wParam, lParam);

윈도우즈 API 정복을 참고한 간단하게 본 서브클래스의 개념과 주요 함수들이다.

'Programmings > Windows Programming' 카테고리의 다른 글

레지스트리(Registry)  (0) 2009.05.29
다른 윈도우에서의 GetFocus() 사용하기  (0) 2009.05.28
GetWindowThreadProcessId()  (0) 2009.05.18
GetModuleFileNameEx()  (0) 2009.05.15
DllMain  (0) 2009.04.27
2009. 5. 18. 11:38

GetWindowThreadProcessId()



GetWindowThreadProcessId() 함수는 HWND 값을 이용하여 프로세스 ID를 알려주는 함수이다.

DWORD GetWindowThreadProcessId (
                                                      HWND       hWnd;
                                                      LPDWORD lpdwProcessId
                                                      );
hWnd              - PID를 얻고자 하는 윈도우의 핸들
lpdwProcessId - 반환받을 PID의 포인터, NULL로 설정할 경우 PID는 리턴값으로 반환된다.

이 함수를 사용하기 위해서는 user32.dll과 user32.lib 를 필요로 한다. 하지만 이들은 기본적으로 VS2005로 작업할 때 포함되어 있으므로 구지 신경을 쓸 필요는 없다.

예)
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
// 또는
pid = GetWindowThreadProcessId(hWnd, NULL);




'Programmings > Windows Programming' 카테고리의 다른 글

다른 윈도우에서의 GetFocus() 사용하기  (0) 2009.05.28
서브클래싱  (0) 2009.05.26
GetModuleFileNameEx()  (0) 2009.05.15
DllMain  (0) 2009.04.27
DLL 제작 (Explicit)  (0) 2009.04.24
2009. 5. 15. 18:14

GetModuleFileNameEx()



GetModuleFileNameEx() 함수는 현재 실행된 다른 프로그램의 실팽파일의 경로를 얻을 수 있는 함수이다.

DWORD WINAPI GetModuleFileNameEx( __in HANDLE hProcess,
                                                          __in_opt  HMODULE hModule,
                                                          __out LPTSTR lpFilename,
                                                          __in DWORD nSize
                                                         );
hProcess - 원하는 모듈을 가지고 있는 프로세스의 핸들.
hModule - NULL로 설정을 하여 실행중인 파일의 경로를 받아올수 있게 한다.
lpFilename - 실행되는 모듈의 경로를 받아올 버퍼.
nSize - 실행되는 파일의 경로를 가져올 버퍼의 크기.

ex) GetModuleFileNameEx(hProc, NULL, str, lstrlen(str));
이 함수를 사용하기 위해서는 'Psapi.h'라는 헤더파일을 포함해 주어야 한고, psapi.lib 파일을 추가해주어야 한다.
아래는 '팁소프트'의 게시판에서 가져온 자료이다.
// GetModuleFileNameEx 함수를 이용하여 경로를 얻기위한 함수
// 프로세스의 경로를 얻기 위해서는 프로세스 정보에 접근해야 하는데, 프로세스의 정보에 접근하기 위해선 해당
// 프로세스의 아이디가 필요하다.
// 프로세스 아이디는 해당 프로세스와 연결된 윈도우 핸들을 통해 알 수 있으며 원하는 프로그램의 윈도우핸들은
// FindWindow 또는 FindWindowEx 함수를 이용해서
찾을 수 있다.
//
// [ 프로세스 정보에 접근하는 순서 ]
// 1. FindWindow 함수로 원하는 프로세스의 윈도우 핸들을 찾는다.
// 2. 윈도우 핸들을 이용하여 프로세스 아이디를 구한다.
// 3. 프로세스 아이디를 이요아여 프로세스 정보를 오픈한다.
void 클래스명::GetExecuteFileName()
{
    // "Test"라는 이름을 가진 윈도우를 찾는다.
    HWND h_wnd = ::FindWindow(NULL, "Test");
    unsigned long process_id = 0;
    // 윈도우 핸들을 이용하여 프로세스 아이디를 구한다.
    GetWindowThreadProcessId(h_wnd, &process_id);
    char temp[256] = {0,};

    // 프로세스 아이디를 이용하여 해당 프로세스 핸들 값을 얻는다.
    HANDLE hwnd = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);
    if(hwnd != NULL){
        // 정상적으로 프로세스를 열었다면 프로세스의 경로명을 얻는다.       
        // 정상적으로 경로명을 얻었다면 해당 경로명을 그렇지 못했다면 파일명만을 출력한다.
        if(GetModuleFileNameEx(hwnd, NULL, temp, 256)) MessageBox(temp);
    }
}

더 많은 내용은 '팁소프트'에 방문하면 찾을 수 있을 듯 한데.. ^^; 광고 아님.. ㅎ

'Programmings > Windows Programming' 카테고리의 다른 글

서브클래싱  (0) 2009.05.26
GetWindowThreadProcessId()  (0) 2009.05.18
DllMain  (0) 2009.04.27
DLL 제작 (Explicit)  (0) 2009.04.24
DLL 제작 (Implicit 연결)  (0) 2009.04.23
2009. 4. 27. 11:43

DllMain



DLL은 함수들의 집합이므로 함수에 대한 정의만 있으면 되고 일반적인 실행파일의 WinMain과 같은 메인함수가 꼭 있어야 하는것은 아니다. 엄밀히 말하자면 DLL도 반드시 Main이라는 엔트리포인트가 필요하지만, VC++를 사용할 경우 C런타임이 엔트리 포인트를 대신 제공하기 때문에 없어도 상관이 없다는 것이다.

DLL이 단순한 함수의 집합이 아니라면 DLL의 엔트리 포인트 DllMain이 필요하다. 전역변수가 있다거나 동적으로 메모리를 할당해 사용한다거나 할 때 초기화와 종료 처리를 위해 필요하다.

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpRes);

hInst는 DLL의 인스턴스 핸들이다.
fdwReason은 이 함수가 호출된 이유를 지정한다.(일종의 통지 메시지)
  DLL_PROCESS_ATTACH
  - DLL이 프로세스의 주소공간에 맵핑될 때 호출된다.
    주로 메모리를 할당하거나 시스템 전역 핸들을 초기화하는 용도로 사용된다.
  DLL_PROCESS_DETACH
  - DLL이 프로세스의 주소 공간에서 분리될 때 호출된다.
    할당한 메모리를 해제하거나 시스템 전역 핸들을 파괴하는 용도로 사용된다.
  DLL_THREAD_ATTACH
  - DLL을 사용하는 프로세스에서 스레드를 생성할 때마다 이 값과 함께 DllMain함수가 호출된다.
    DLL에서는 이 값을 받았을 때 스레드별 초기화를 수행한다.
  DLL_THREAD_DETACH
  - DLL을 사용하는 프로세스에서 스레드가 종료될 때마다 이 값과 함께 DllMain 함수가 호출된다.
    DLL에서는 이 값을 받았을 때 스레드별 종료 처리를 한다.
lpRes는 DLL의 연결 방식을 지정한다.
  TRUE - 암시적 연결
  FALSE - 명시적 연결

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpRes)
{
    switch(fdwReason) {
        case DLL_PROCESS_ATTACH:
            ...
            break;

        case DLL_PROCESS_DETACH:
            ...
            break;

        case DLL_THREAD_ATTACH:           
            ...
            break;

        case DLL_THREAD_DETACH:
            ...
            break;
    }
    return TRUE;
}

이런 식으로 구현을 해주면 된다.
해당하는 통지 메시지가 전달 될 때 필요한 작업을 넣어준다. 가만히 보고 있자면 하는 일이 WndProc와 비슷한것 같다면서.. ^^;


'Programmings > Windows Programming' 카테고리의 다른 글

GetWindowThreadProcessId()  (0) 2009.05.18
GetModuleFileNameEx()  (0) 2009.05.15
DLL 제작 (Explicit)  (0) 2009.04.24
DLL 제작 (Implicit 연결)  (0) 2009.04.23
DLL 이란...  (0) 2009.04.23
2009. 4. 24. 15:02

DLL 제작 (Explicit)



DLL을 명시적(Explicit)으로 연결하기 위한 방법이다.
명시적(Explicit) 연결이라는 부분에 대해서는 프로그램이 실행되고 있는 도중에 필요한 함수가 포함된 DLL을 로드하는 방식이라고 보면 될 듯하다.

명시적인 연결을 위한 DLL을 제작할 때 중요한 함수들이 있다.
HINSTANCE LoadLibrary(LPCTSTR lpLibFileName);
지정한 DLL을 메모리로 읽어와 현재 프로세스의 주소공간에 맵핑시켜 사용할 수 있도록 한다. 하지만, 이미 다른 프로세스에서 해당 DLL을 사용하고 있다면, DLL을 메모리로 또다시 올리는 것이 아니고 DLL 의 사용 카운트만 1 증가시킨다.
인수는 읽고자 하는 DLL 의 파일 이름이다. 파일의 경로를 지정할 수도 있고, 지정하지 않을 수도 있다. 파일의 경로를 지정하지 않으면 DLL을 찾는 순서에 따라 경로를 뒤져가며 해당 DLL을 찾게 된다.

FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
DLL에서 엑스포트한 함수의 번지를 찾아 그 함수의 함수 포인터를 리턴한다.
첫 번째 인수는 함수가 포함된 DLL의 모듈 핸들이며 LoadLibrary() 가 리턴한 값이다.
두 번째 인수는 찾고자 하는 함수 이름이다.
이 함수가 리턴한 함수포인터를 사용하여 DLL에 있는 함수를 호출한다.

BOOL FreeLibrary(HMODULE hLibModule);
DLL의 사용 카운트를 1 감소시키며 사용 카운트가 0이 되었을 경우 메모리에서 DLL을 삭제한다.
첫 번째 인수는 LoadLibrary()가 리턴한 DLL의 모듈 핸들이다. LoadLibrary()로 DLL을 읽어왔다면 반드시 프로세스를 종료하기 전에 FreeLibrary()를 호출하여 DLL을 해제해야 한다.


DLL 제작
DLL 제작 방법은 아래를 참조하면 될듯.. -_-;;
http://todayis.tistory.com/206

DLL Test 프로그램(명시적 연결) 제작
새로운 Win32 프로젝트를 생성하고, WndProc 소스 부분을 아래와 같이 굵은 글자로 된 부분을 추가한다.
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HINSTANCE hInst;
    int(*pFunc)(int, int);
    TCHAR str[128];

    switch (iMessage) {
    case WM_CREATE:
        hWndMain=hWnd;
        return 0;
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        hInst = LoadLibrary(L"DLL_test.dll");
        pFunc = (int(*)(int, int))GetProcAddress(hInst, "AddInteger");
        wsprintf(str, L"1+2 = %d", (*pFunc)(1, 2));
        TextOut(hdc, 10, 10, str, lstrlen(str));
        FreeLibrary(hInst);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

컴파일.. 하고 실행을 하면.. 전에 설명했던 암시적(Implicit) 연결과 동일한 결과임을 알 수 있다.

단지 명시적 연결의 경우 원하는 위치에서 DLL을 직접 호출하는 구문이 있다는 것이다. 위의 경우에는 WM_PAINT
DLL을 사용하는 프로그램이 실행될 때 DLL이 같이 로드되는 것이 아니기 때문에 Settings에 따로 XXX.lib를 지정할 필요가 없다. 또 함수포인터로 함수가 있는 번지를 직접 조사한 후 그 주소를 이용하기 때문에 함수의 원형같은 것도 필요가 없다.
어떻게 보면, 명시적인 연결을 사용하는 DLL 이 더 쉬운듯 하다.

추가로 에러를 위한 처리구문을 추가하자.
LoadLibrary() 그리고 GetProcAddress() 등의 함수를 사용하는 부분을 아래와 같이 처리해 주면 된다.
if((hInst = LoadLibrary(L"DLL_test.dll")) == NULL) {
    MessageBox("There are no DLLs!!!");
    // 추가적인 에러 처리
    return 0;
}
if((pFunc = (int(*)(int, int))GetProcAddress(hInst, "AddInteger")) == NULL) {
    MessageBox("Where is The Function what I want to?? ");
    // 추가적인 에러처리
    return 0;
}


명시적(Explicit) 연결의 장점
1. 필요할 때만 DLL을 읽어와 사용하므로 메모리와 리소스가 절약된다.
2. 상황에 따라 사용할 DLL을 교체할 수 있다.
3. 필요한 DLL이 없는 경우라도 프로그램을 실행할 수는 있다. DLL을 사용하는 부분에서는 정상적인 동작을 안하더라도...
4. DLL을 호출하는 프로그램의 시작 실행속도가 빠르다.

명시적(Explicit) 연결의 단점
1. 사용하기 전에 DLL을 메모리로 읽어오므로 함수 호출 속도가 느리다.

  • 윈도우즈 API 완전정복 참고...


'Programmings > Windows Programming' 카테고리의 다른 글

GetModuleFileNameEx()  (0) 2009.05.15
DllMain  (0) 2009.04.27
DLL 제작 (Implicit 연결)  (0) 2009.04.23
DLL 이란...  (0) 2009.04.23
아스키 코드표  (0) 2009.03.03
2009. 4. 23. 22:17

DLL 제작 (Implicit 연결)



DLL 제작
단순히 DLL 파일을 생성하는 방법이다. DLL은 단독으로 실행될 수 없으므로 이 파일을 가지고 테스트를 할 수는 없다.(테스트 프로그램을 따로 제작할 것이다.)

1. Visual Studio를 실행한다.(본인의 경우 Visual Studio 2005 임)
2. File -> New -> Project..
3. New Project 위자드
   - Visual C++ 탭에서 Win32를 선택하고, 템플릿으론 Win32 Project를 선택한다.
   - Name, Location, Solution Name는 알아서 대충 넣어준다..
4. 대충 Next 버튼을 클릭하며, Application Settings에서는  DLL을 선택한다.
5. Finish 버튼 클릭!!
6. 새프로젝트가 만들어지면, .cpp파일을 하나 생성하고, 테스트용으로 간단한 내용을 입력한다.
// 윈도우즈 API 완전정복의 코드임..
// a, b를 입력받아 a, b의 합을 리턴하는 코드임
// 다른 프로그램에서 이 함수를 사용할 수 있도록 extern "C"__declspec를 사용..
extern "C"__declspec(dllexport) int AddInteger(int a, int b)
{
    return a+b;
}

7. 이 프로젝트를 컴파일하면 해당하는 .dll과 .lib 파일이 생성된다.


DLL 테스트 프로그램 제작
Implicit(암시적), Explicit(묵시적) 연결을 사용할 수 있다.

Implicit(암시적) 연결
MyDllTest라는 API 프로젝트를 만들고 다래 코드를 추가한다.

// DLL  함수를 위해 추가해야 하는 부분..
extern "C"__declspec(dllimport) int AddInteger(int, int);
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR str[128];

    switch (iMessage) {
    case WM_CREATE:
        hWndMain=hWnd;
        return 0;
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        wsprintf(str, "1+2 = %d", AddInteger(1, 2));
        TextOut(hdc, 10, 10, str, lstrlen(str));
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
       return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}


다음은 사용하고자 하는 DLL의 임포트 라이브러리를 프로젝트에 포함시키는 작업을 해주어야 한다.
메뉴 탭의 Project -> XXXProperties.. (이미지 클릭 하셈!!! ㅋ)


마지막으로 .DLL 파일과 .lib 파일을 MyDllTest 프로젝트 디렉토리로 복사한다.
참고로 .DLL과 .lib 파일은 위에서 DLL 제작의 컴파일 결과물로 생성된 녀석들이다.


이 방법 말고도, DLL을 사용하려는 소스의 윗부분에 #pragma 문을 사용할 수도 있다.
#pragma comment(lib,"XXXDLL.lib") 를 추가하면 된다.
#pragma 지시자를 사용하면 컴파일러의 라이브러리 관리 모듈에게 XXXDLL.lib를 검색하도록 하게 하므로 위의 과정에서 보인것과 같은 설정 대화상자나 파일(.dll, .lib) 추가 없이 소스에서 곧바로 임포트 라이브러리를 지정할 수 있다.


그리고 컴파일... 후 실행하면..



추가로  DLL의 헤더파일을 정의해서 깔끔하게 DLL을 작성하는 방법이다.

위와 같이 함수의 내용이 얼마 되지 않는다면 그냥 사용할 수 있겠지만, DLL에 추가되는 함수의 수가 많아지게 되면, 선언의 꺼리(extern "C"__declspec..와 같은)가 그만큼 많아질 것이다.
헤더파일을 하나 만들어 선언을 모두 옮겨 놓는 방법도 하나의 해결 방안이 될 듯..

DLL의 프로젝트에 헤더파일 하나를 만든다.
그리고 아래와 같은 내용을 추가한다.

//XXX.h

#ifdef DLLEXPORT
#define MYDLLTYPE __declspec(dllexport)
#else
#define MYDLLTYPE __declspec(dllimport)
#endif

extern "C" MYDLLTYPE int AddInteger(int a, int b);

추가로 DLL에 함수를 추가하고자 한다면, 함수의 선언 부분을 extern "C" .. 의 아래에 추가시켜주면 될 것이다.

DLL의 .cpp 파일을 열어서 다음의 두줄을 추가한다.

#define DLLEXPORT             // DLL Export임을 선언(??)
#include "XXX.h"

이 두줄을 추가시키므로 인해서, DLL은 export 하는 용도임을 정의한다.

테스트 프로그램은 단지 XXX.h파일을 추가시켜준다.
어떠한 정의가 따로 되어있지 않으므로, __declspec(dllimport)로 인식할 것이다.


여기까지!!

이게 DLL을 사용하는 가장 간편한 방법이라고 하는데..
다른 방법들은.. 다음 이시간에.. !!!


'Programmings > Windows Programming' 카테고리의 다른 글

DllMain  (0) 2009.04.27
DLL 제작 (Explicit)  (0) 2009.04.24
DLL 이란...  (0) 2009.04.23
아스키 코드표  (0) 2009.03.03
프로그램 실행 에러 - MFC71D.DLL을(를) 찾을 수 없으므로...  (5) 2009.02.05
2009. 4. 23. 18:30

DLL 이란...



DLL(Dynamic Link)라는 것.. 동적 링크라고도 하는 이넘은... 컴파일시 함수의 코드가 실행 파일에 그대로 복사되는 것이아니고, 실행되는 파일이 실행 될 때 필요로 하는 함수가 실행 파일에 연결되는 형식이다. 실행파일은 단지 호출할 함수의 정보만 포함되고 실제 함수코드는 복사되지 않기 때문에 실행 파일의 크기가 작아진다. 하지만 실행시킬 루틴이 필요하기 때문에 실행파일은 실행시킬 함수에 대한 정보를 가지고 있어야하고, 실행시킬 함수는 DLL 파일의 형태로 존재하게 된다.

장점
1. 한 코드를 여러 프로그램이 같이 사용하기 때문에 메모리가 절약된다.
2. DLL을 사용하는 프로그램은 실행파일 자체에 해당 함수가 포함되지 않기에 크기가 작다.
3. 함수의 루틴을 바꾸고자(업그레이드) 할 경우 해당하는 DLL만 수정하면 된다.
...
이외에도 많은 장점들이 있는듯함..

단점
1. DLL 없이 실행프로그램 자체만으론 동작을 안한다. -_-;
2. DLL 이 교체되거나 하면, 프로그램이 정상동작을 안할 수도 있다.
... 등등..

DLL 연결 방법
1. 암시적(Implicit) 연결

함수가 어느  DLL에 있는지 밝히지 않고 그냥 사용을 하는 방법이다. DLL을 사용하려는 프로젝트는 해당 dll과 lib를 포함하고 있어야 하고, 윈도우즈는 임포트 라이브러리의 정보를 참조해서 해당 DLL을 로드하고 함수를 찾게 된다.
프로그램이 실행될 때 DLL이 로드되므로 실행시 연결(Load time Linking)이라고 한다.
2. 명시적(Explicit) 연결
어느 DLL에 있는 함수인지를 밝히고 사용하는 방법이다. 프로그램이 실행될 때 DLL이 로드되는 것이 아니라 로드하라는 명령이 있을 때만 해당 DLL이 로드된다. 함수가 속해있는 DLL의 이름을 명시적으로 지정하여 호출하므로 임포트 라이브러리는 필요하지 않다.
프로그램이 실행 중에 DLL이 메모리로 읽혀지기 때문에 실행중 연결(Run Time Linking)이라고 한다.