출처 : http://fallingstar.tistory.com/99


사용하다가 주로 격는 에러만 몇 가지 정리해 봅니다.

1. error C2065 : 'i' : undeclared identifier 
 변수를 잘못 선언하거나 선언하지 않은 경우 발생

2. error C2509 : 'OnLButtonDown' : member function not declared in 'XXXDlg'
 함수를 잘못 선언하거나, 선언하지 않은 경우 발생

3. error LNK2001 : unresolved external symbol "protected: void_thiscall XXXDlg::OnLButton(....)"
함수를 선언만 해 놓고 소스 코드에 구현하지 않은 경우에 발생합니다.

4. MDI(다중도큐먼트)기반 프로그램에서 헤더파일을 인클루드 할 때에는 다음과 같이 도큐먼트 헤더가 뷰 헤더 위에 위치하도록 합니다.
#include "XXXDoc.h"
#include "XXXView.h"
(그렇지 않을 경우 오류 발생)

5. error C2601 : local function definitions are illegal 
   fatal error C1004 : unexpected end of file found
괄호가 제대로 닫히지 않은 경우 발생합니다.

6. error C2248 : cannot access protected member declared in class 'XXXDoc' 
   : see declaration of 'm_nXXX'
 접근할 권한이 없는 함수나 변수에 접근하려 한경우(private ,protect 변수나 함수) 발생합니다.

대략적으로 이런 경우더군요.

AfxGetMainWnd() MFC 전역 함수는 현재 스레드의 메인 윈도우 핸들을 리턴한다.

AfxGetMainWnd() 의 원형은 다음과 같다.

_AFXWIN_INLINE CWnd *AFXAPI AfxGetMainWnd()
{
    CWinThread *pThread = AfxGetThread();
    return pThread != NULL ? pThread->GetMainWnd() : NULL;
}
 


리턴값을 보면 현재 스레드의 메인 윈도우를 리턴한다.
따라서 다른 쓰레드에서 AfxGetMainWnd() 함수를 사용하면 다른 윈도우 핸들을 리턴할 가능성이 있다.

다른 스레드에서 메인 윈도우 핸들을 얻기 위해선
::AfxGetApp()->GetMainWnd();
함수를 사용하면 된다.

 출처 : www.soen.kr

#include <windows.h>

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="First";

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
  ,LPSTR lpszCmdParam,int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst=hInstance;

WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=(WNDPROC)WndProc;
WndClass.lpszClassName=lpszClass;
WndClass.lpszMenuName=NULL;
WndClass.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  NULL,(HMENU)NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);

while(GetMessage(&Message,0,0,0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
switch(iMessage) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
 

 

4헤더 파일

우선 제일 첫행을 보면 windows.h 하나만 인클루드되어 있다. 도스에서는 사용하는 함수에 따라 여러 개의 헤더 파일을 포함하지만 윈도우즈에서는 하나의 헤더 파일에 모든 API 함수들의 원형과 사용하는 상수들을 죄다 정의하고 있기 때문에 windows.h만 포함해 주면 된다. stdio.h나 conio.h, graphics.h 등을 포함해 줄 필요가 없다. 물론 특별한 경우에는 해당하는 헤더 파일을 포함해야 하지만 예제 수준에서는 windows.h만 포함시키면 거의 문제가 없다. windows.h 헤더 파일은 기본적인 데이터 타입, 함수 원형 등을 정의하며 그 외 필요한 헤더 파일을 포함하고 있다. 그래서 윈도우즈 프로그램의 첫 줄은 거의 항상 #include <windows.h> 로 시작된다.

4 시작점

다음으로 차이나는 점은 프로그램의 시작점인 엔트리 포인트(Entry Point)가 main 함수가 아니라 WinMain이라는 점이다. 윈도우즈 프로그램의 시작점은 main이 아닌 WinMain이다. 원형은 다음과 같다.

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance ,LPSTR lpszCmdParam,int nCmdShow)

도스에서의 main 함수는 인수 사용여부에 따라 여러 가지 원형이 있지만 WinMain의 원형은 위와 같이 고정되어 있다. APIENTRY 지정자는 __stdcall형 호출 규약을 사용한다는 뜻인데 일단은 없다고 생각해도 무방하다. 4개의 인수를 취하는데 각 인수의 의미는 다음과 같다.

인수 의미
hInstance 프로그램의 인스턴스 핸들
hPrevInstance 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들. 없을 경우는 NULL이 되며 WIN32에서는 항상 NULL이다. 호환성을 위해서만 존재하는 인수이므로 신경쓰지 않아도 된다.
lpCmdLine 명령행으로 입력된 프로그램 인수이다. 도스의 argv인수에 해당한다.
nCmdShow 프로그램이 실행될 형태이며 최소화, 보통모양 등이 전달된다.

이 중 hInstance 이외에는 잘 사용되지 않는다. 인스턴스(Instance)라는 말은 클래스가 메모리에 실제로 구현된 실체를 의미한다. 윈도우즈용 프로그램은 여러개의 프로그램이 동시에 실행되는 멀티태스킹 시스템일 뿐만 아니라 하나의 프로그램이 여러 번 실행될 수도 있다. 이때 실행되고 있는 각각의 프로그램을 프로그램 인스턴스라고 하며 간단히 줄여서 인스턴스라고 한다. 예를 들어 다음과 같이 메모장이 두번 실행되어 있다고 해 보자.

이 때 두 프로그램은 모두 메모장(Notepad.exe)이지만 운영체제는 각각 다른 메모리를 사용하는 다른 프로그램으로 인식한다. 이때 각 메모장은 서로 다른 인스턴스 핸들을 가지며 운영체제는 이 인스턴스 핸들값으로 두 개의 메모장을 서로 구별한다.

hInstance란 프로그램 자체를 일컫는 정수값이며 API 함수에서 수시로 사용된다. 그래서 이 예제에서는 WinMain의 인수로 전달된 hInstance값을 전역 변수 g_hInst에 대입해 두었다. hInstance 인수는 기억부류가 지역 변수이기 때문에 WinMain의 밖에서는 사용할 수 없기 때문이다. 이 예제에서는 g_hInst 값을 당장 사용하지 않고 있지만 앞으로의 예제에서는 이 값을 사용하게 될 것이다.

그리고 lpszClass라는 전역 문자열이 정의되어 있는데 이 문자열은 윈도우 클래스를 정의하는데 사용된다. 잠시 후에 이 문자열이 사용되는 곳에서 설명을 하도록 한다.

HINSTANCE g_hInst;
LPSTR lpszClass="First";

4 메시지 처리 함수

이 프로그램을 자세히 보면 두개의 함수만 있다. 하나는 프로그램의 시작점인 WinMain이며 나머지 하나는 WndProc이다. 도스에서는 main 함수만으로도 프로그램을 작성할 수 있지만 윈도우즈에서는 아주 특별한 경우를 제외하고는 이 두개의 함수가 모두 있어야 한다.

WinMain에서는 윈도우를 만들고 화면에 출력하기만 할 뿐이며 대부분의 일은 WndProc에서 이루어진다. WinMain은 프로그램을 시작시키기만 하며 실질적인 처리는 대부분 WndProc에서 이루어진다. WinMain의 모양은 대체로 일정하며 특별한 일을 하지 않지만 WndProc는 프로그램에 따라 천차만별로 달라진다. 그래서 소스를 분석할 때 주의깊게 봐야 할 부분은 WinMain이 아니라 WndProc이다. WinMain 바로 윗부분에 WndProc 함수의 원형이 선언되어 있다.

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

 


 

그리고 소스의 뒷부분에는 이 함수의 본체가 정의되어 있다.

코드를 분석할때 도저히 알 수 없는 코드에 printf 를 넣는다.

빌드 과정에서 printf에 찍힌 값 하나 하나를 따라가다보면 코드를 분석하는데 도움이 된다.

출처 : http://www.soen.kr/

 

핸들이란, 구체적인 어떤 대상에 붙여진 번호이며 분법적으로는 32비트의 정수값이다.

도스 프로그래밍에서는 거의 유일하게 파일 핸들만이 사용되었으며 그래서 도스에서 핸들은 곧 파일 핸들을 의미하는 경우가 많았다. 그러나 윈도우즈에서는 여러 가지 종류의 핸들이 사용되고 있다. 만들어진 윈도우에는 윈도우 핸들(hWnd)을 붙여 윈도우를 번호로 관리하며 아직은 잘 모르겠지만 DC에 대해서도 핸들을 사용하고 논리적 펜, 브러시에도 핸들을 붙여 관리한다. 심지어 메모리를 할당할 때도 할당한 메모리의 번지를 취급하기보다는 메모리에 번호를 붙인 메모리 핸들을 사용한다. 왜 이렇게 핸들을 자주 사용하는가 하면 대상끼리의 구분을 위해서는 문자열보다 정수를 사용하는 것이 훨씬 더 속도가 빠르기 때문이다.

윈도우즈에서 핸들을 이렇게 많이 사용하므로 우리는 핸들의 일반적인 특성에 관해서 미리 숙지하는 것이 좋다. 핸들은 일반적으로 다음과 같은 특징이 있다.

① 일단 핸들은 정수값이며 대부분의 경우 32비트값이다. 핸들을 사용하는 목적은 오로지 구분을 위한 것이므로 핸들끼리 중복되지 않아야하며 이런 목적으로는 정수형이 가장 적합하다.

② 핸들은 운영체제가 발급해 주며 사용자는 쓰기만 하면 된다. 예를 들어 윈도우를 만들거나 파일을 열면 운영체제는 만들어진 윈도우나 열려진 파일에 핸들을 붙여준다. 사용자는 이 핸들을 잘 보관해 두었다가 해당 윈도우나 파일을 다시 참조할 때 핸들을 사용하면 된다. 사용자가 직접 핸들을 만들 경우란 없다.

③ 같은 종류의 핸들끼리는 절대로 중복된 값을 가지지 않는다. 만약 이렇게 된다면 핸들은 구분을 위해 사용할 수 없을 것이다. 물론 다른 종류의 핸들끼리는 중복된 값을 가질 수도 있다.

④ 핸들은 정수형이므로 값을 가지겠지만 그 실제값이 무엇인지는 몰라도 상관없다. 핸들은 크고 작음의 성질을 가지는 숫자가 아니라 단순한 표식일 뿐이다. 핸들형 변수를 만들어 핸들을 대입받아 쓰고 난 후에는 버리면 된다.

윈도우즈에서 핸들은 예외없이 접두어 h로 시작되며 핸들값을 저장하기 위해 별도의 데이터형까지 정의해 두고 있다. HWND, HPEN, HBRUSH, HDC 등이 핸들을 담기 위한 데이터형들이며 모두 부호없는 정수형이다.

+ Recent posts