'Programmings/Windows Programming'에 해당되는 글 35건

  1. 2010.04.27 warning C4995: 'xxx' : name was marked as #pragma deprecated
  2. 2010.04.27 "응용 프로그램 구성이 올바르지 않기 때문에..." 해결 방안
  3. 2010.02.11 DLL에서 WndProc 메시지 처리하는 방법
  4. 2009.10.09 아스키코드(ASCII CODE)와 유티코드(UNICODE)
  5. 2009.07.16 GetLastError()
  6. 2009.06.23 WinIO
  7. 2009.05.29 IME 입력모드 설정 5
  8. 2009.05.29 레지스트리(Registry)
  9. 2009.05.28 다른 윈도우에서의 GetFocus() 사용하기
  10. 2009.05.26 서브클래싱
2010. 4. 27. 14:30

warning C4995: 'xxx' : name was marked as #pragma deprecated



컴파일을 하다보면 "warning C4995: 'xxx': name was marked as #pragma deprecated" 와 같은 warning 메시지를 볼 때가 있다.

MSDN에 이렇게 나와있다.

Error Message

'function': name was marked as #pragma deprecated

The compiler encountered a function that was marked with pragma deprecated. The function may no longer be supported in a future release. You can turn this warning off with the warning pragma (example below).

더 이상  지원되지 않을 수 있는 함수이다.
warning을 보고 싶지 않으면 pargma를 사용해라.

#pragma warning(disable:4995)

위와 같은 처리를 하게 되면, 빌드 시에 warning 메시지는 나오지 않을 것이다.
하지만, 더 이상 지원이 되지 않는 함수라는 것은 뭔가 문제가 있기 때문에 그럴 것이다.

위의 경고를 내는 함수들은 버퍼 오버플로우 혹은 보안적으로 문제를 가질 수 있는 함수들이다. 그렇기 때문에 위의 경고 메시지를 낼 만한 함수의 사용을 자제하고, 개선 된 함수를 사용하는것이 방법이 될 것이다.

아래의 링크가 그 위의 문제를 해결하는데 도움을 줄 것이다.
http://msdn.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx
http://www.chaos3d.net/zboard/view.php?id=cs_public&no=17


2010. 4. 27. 13:39

"응용 프로그램 구성이 올바르지 않기 때문에..." 해결 방안



예전에 http://todayis.tistory.com/148 에 "응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다. 이 문제를 해결하려면 응용 프로그램을 다시 설치하십시오." 라는 주제에 대해서 이야기 한 적이 있었다.

왠만한 경우 'vcredist_x86.exe' 파일을 설치함으로 해결 되었던 것으로 기억이 되는데.. 왠지 이번에 만든 프로그램의 경우 전혀 먹히질 않는다.. -_-;

http://kldp.org/node/95859 의 대글을 보니 이런 부분이 있다.

좀 더 정확히 얘기하면, Side-by-Side Assembly가 없어서 발생하는 문제이죠.

Visual Studio 2005부터는 공용 DLL을 System32라는 곳에 몰아서 보관하지 않고, WinSxS라는 공용 어셈블리 저장공간에 별도로 저장하게 됩니다. 이렇게 저장하는 이유는 버전 충돌을 막기 위해서이고요.

이러한 공용 어셈블리의 위치 정보는 모듈의 Menifest에 저장되어서 참조되게 됩니다.

그래서 사용하는 DLL을 단순히 복사하셔서는 안되고요. cynicjj님 말씀처럼 재배포 패키지를 이용해서 공용 DLL들을 설치하셔야 합니다. (Menifest는 Windows XP이상에서만 사용할 수 있기 때문에, Windows2000에서는 그냥 System32나 어플리케이션이 있는 폴더에 DLL들을 같이 복사해 주셔야 하고요.)

참고로 그런에 에러가 나왔을때, Dependency Walker 프로그램을 이용하면, 무슨 DLL이 없는지 쉽게 확인하실 수 있습니다.


이런 비슷한 내용을 본적이 있는데..
http://www.serious-code.net/moin.cgi/RedistributingVisualCppRunTimeLibrary

위의 사이트를 보니
실행 파일 자체와 실행 파일에서 액세스하는 DLL들에 대한 manifest 파일들을 private assembly로서 같이 배포하면, 에러를 피할 수 있다. 

라고 한다. 

위의 문제를 해결하기 위해서 "C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86" 를 찾아보면 "Microsoft.VC80.CRT" 와 "Microsoft.VC80.MFC" 폴더가 존재한다.
Win32API의 경우 "Microsoft.VC80.CRT", MFC의 경우 "Microsoft.VC80.MFC" 디렉토리 내의 파일들과 함께 실행파일을 제공하면 될 듯 하다.

실행파일에 대한 manifest 파일도 필요하다고 하는데.. 그 파일 없이도 일단 실행이 되는것은 같은데..
참고로 실행파일에 대한 manifest 파일은 프로젝트 관련 디렉토리 내의 Debug 혹은 Release 디렉토리 내에 존재한다.

2010. 2. 11. 18:04

DLL에서 WndProc 메시지 처리하는 방법



응용 프로그램에서 특정 DLL을 사용할 때, 해당하는 DLL에서 윈도우즈 메시지를 처리해야 할 경우가 있다.
한참을 고민했네.. 메시지를 후킹해서 필요한 녀석만 처리를 하게끔 해야하나?? -_-;

의외로 간단한 방법이 있었다.

그것을 '서브클래싱(SubClassing)' 이라고 부르는 것 같다.

DLL의 초기화 하는 적절한 부분에 다음과 같이 서브클래싱을 해준다.
본인의 경우 다음과 같이...

WNDPROC oldProc;
...

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
...
switch(msg)
{
...
}
return CallWindowProc(oldProc, hwnd, msg, wp, lp);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
...
switch(fdwReason)
{
case DLL_PROCESS_ATTACH :
...
oldProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG)WndProc);
}
}

SetWindowLongPtr() 함수를 통해 메시지를 처리할 윈도우 프로시저를 기존의 응용프로그램의 것에서 DLL의
것으로 옮긴다.
DLL 내부에 만들어 놓은 윈도우 프로시저(WndProc)에서 처리하고자 하는 메시지만 처리하도록 하고 그 외의 것은
CallWindowProc()함수를 통해 기존의 응용프로그램의 윈도우 프로시저가 처리하도록 한다.



2009. 10. 9. 11:37

아스키코드(ASCII CODE)와 유티코드(UNICODE)



현재 운영체제가 표현하는 대표적인 문자셋(Character Sets)으로는 아스키코드(ASCII Code)유니코드(UNICode)가 있다.
여기서는 윈도우즈 운영체제를 기준으로 한다.

아스키코드
아스키코드는 미국에서 정의하고 있는 표준이다.
알파벳 26개와 확장 문자를 포함하여 총 256개를 넘지 않는 문자가 존재한다. 이는 1 바이트를 가지고 충분히 표현할 수 있기에 1 바이트의 char형을 사용해서 표현을 할 수 있다.
아스키코드에 해당하는 문자들은 http://todayis.tistory.com/191 에서 확인할 수 있다.

문제는 영어권이 아닌 다른 국가의 언어를 표현하는데 1 바이트로는 무리가 있다는 것이다. 한글의 경우만 보아도 한글의 글자 하나하나에 값을 지정해 주어야 한다. 한글은 그렇다 치더라도 중국어는 어떻할 것인가??
그래서 등장한 것이 유니코드이다.

유니코드
문자를 표현하는데 2 바이트를 사용해 총 65,536개의 문자를 표현할 수 있도록 정의해 놓은 문자셋이다.
전 세계의 모든문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계되었다.


문자를 표현하는데 아스키코드는 1 바이트, 유니코드는 2 바이트를 사용하기 때문에, 동시에 이 둘을 모두 사용하기에는 운영체제가 혼란을 겪을 것이다. 컴퓨터(운영체제)는 단순하기 때문에 하나로 통일을 해 주어야 일을 제대로 할수 있다고 하던데.. ^^;

해결 방법으로 문자셋마다 처리하는 표준을 정의했다.
아스키코드를 처리하기 위한 표준으로 SBCS(Single Byte Character Set)라는 녀석을 정의했고, 유니코드를 처리하기 위해서는 WBCS(Wide Byte Character Set)라는 녀석을 정의해 둔 것이다.
중간에 경우에 따라 1 바이트, 2 바이트를 처리하도록 정의된 MBCS(Multi Byte Character Set)이란 녀석도 있다.

아스키코드 기반으로 문자열을 처리하기 위한 프로그램을 작성할 때에는 이전에 C언어를 배울 때 습관적으로 사용하던 문자 처리방식을 습관적으로 사용하던 방식을 그대로 사용하면 된다.
char, "string", strlen()...

유니코드 기반으로 문자열을 처리하기 위해서는 이와는 약간 다른 부분들이 존재한다.
wchar_t, L"string", wcslen()

위와 같이 자료형, 문자열 표현방법, 함수등이 유니코드 처리에 맞게 재설정 되어있다. 이러한 내용은 윈도우즈에서 제공하는 헤더파일(windows.h, windef.h, winnt.h)을 살펴보면 알 수 있다.

일반적으로 유니코드와 아스키코드를 동시에 지원하기 위해 아래와 같은 방법을 tchar.h 라는 헤더파일에 정의해 두었다. tchar.h 는 windows.h에 포함되지 않기 때문에 명시적으로 추가해 주어야 한다.
자료형의 경우..
#ifdef UNICODE
    typedef  WCHAR     TCHAR;
    typedef  LPWSTR    LPTSTR;
    typedef  LPCWSTR  LPCTSTR;
#else
    typedef  CHAR        TCHAR;
    typedef  LPSTR       LPTSTR;
    typedef  LPCSTR     LPCTSTR;
#endif

함수의 경우..
#ifdef _UNICODE
    #define  _tprintf    wprintf
...
#else
    #define  _tprintf    printf
...
#endif

위와 같이 정의가 되어 있기 때문에 UNICODE(_UNICODE) 의 정의 유무에 따라 아스키코드 또는 유니코드 방식으로 컴파일을 할 수가 있다.
tchar.h 헤더파일을 살펴보는 것도 큰 도움이 될 듯 하다.

참고로 본인이 사용하고 있는 Visual Studio 2005는 유니코드로 미리 정의가 되어 있다.
메뉴에서 [project] -> [CommandPrompt Properties...] 를 선택하면 확인할 수 있다. Alt+P 키를 두 번 눌러도 됨

미리 정의된 유니코드로 작업하기 싫다고 하면, 체크박스로 된 Inherit from parent or project defaults의 체크를 해제하면 된다. 이게 싫다면, 소스코드 내에서 #undef 를 사용해 미리 정의된 UNICODE를 무효화 시키면 된다.
#undef _UNICODE
#undef UNICODE
...

2009. 7. 16. 10:00

GetLastError()



Windows 시스템에서 함수를 사용할 때 이녀석이 제대로 실행되지 않고 에러를 발생시킬 경우가 허다하다.
사실.. 프로그램을 짜면서 에러 하나 없이 순탄하게 짜는 사람이 있을까마는..
적어도 난 한번도 없다면서.. -_-;

그럼 에러가 발생했다 라는것 말고 무슨 이유로 에러가 발생했다는 것을 아는 방법이 없을까?
수정을 하려 해도 어떤 이유에서 에러가 발생하는 지 알아야 수정을 할것인데...
그래서 나온 것이 바로 GetLastError() 라는 함수이다. GetLastError()를 에러가 발생하는 함수 바로 뒤에 호출하게 되면 오류의 원인에 대한 에러코드를 얻을 수가 있다.

DWORD GetLastError(void);

MSDN을 보게 되면 수많은 에러코드의 의미가 나와있다.
오호라.. MSDN을 보니 대충 0 ~ 15999가지의 에러에 대한 내용이 있는 모양이다. 열라 많다 -_-;;

간단하게 사용법을 보면은..
...
HANDLE hFile = CreateFile(...);
if(hFile == INVALID_HANDLE_VALUE)
{
    printf("Error Code : %d \n", GetLastError());
}
...

위와 같이 사용을 하게 될 경우, CreateFile()의 결과가 잘못될 경우, if문의 GetLastError()의 반환값을 보구선 어떤 이유로 원치 않는 결과가 나왔는지를 확인 할 수가 있다.


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

DLL에서 WndProc 메시지 처리하는 방법  (0) 2010.02.11
아스키코드(ASCII CODE)와 유티코드(UNICODE)  (0) 2009.10.09
WinIO  (0) 2009.06.23
IME 입력모드 설정  (5) 2009.05.29
레지스트리(Registry)  (0) 2009.05.29
2009. 6. 23. 09:45

WinIO



WinIO 는 윈도우즈(9x, NT, 2000, XP 등) 보호모드상에서 포트나 메모리의 직접적인 접근을 가능하도록 Yariv Kaplan이라는 사람이 만들어 놓은 라이브러리로 오픈소스이다. WinIO는 드라이버의 소스까지 공개되어 있어 누구나 분석하거나 사용할 수 있고, http://www.internals.com 에 방문하게 되면 얻을 수 있다.
사용법이라든지 도움말, 그리고 간단한 예제 프로그램이 같이 있어 사용하는데 문제는 없을 듯 하다.


원하는 포트를 사용하여 어플리케이션과 디바이스 드라이버간의 통신을 위해 사용할 수 있다. 특시 60, 64 포트를 이용하여 키보드 제어를 위해서도 사용을 하기도 한다.

기타 WinIO 에 대한 자료는 google을 검색하면 수도 없이 나올 것이다.
필요한 부분은 알아서 자알 찾으면 될 듯.. ㅎ


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