정리

[MFC] DestroyWindow

저장소/VC++

DestroyWindow에 대한 MSDN 발췌 내용은 다음과 같다.

The DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).

If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.

다음은 CWnd의 DestroyWindow에 대한 내용이다.

The DestroyWindow member function sends appropriate messages to the window to deactivate it and remove the input focus. It also destroys the window's menu, flushes the application queue, destroys outstanding timers, removes Clipboard ownership, and breaks the Clipboard-viewer chain if CWnd is at the top of the viewer chain. It sends WM_DESTROY and WM_NCDESTROY messages to the window. It does not destroy the CWnd object.

DestroyWindow is a place holder for performing cleanup. Because DestroyWindow is a virtual function, it is shown in any CWnd-derived class in Class View. But even if you override this function in your CWnd-derived class, DestroyWindow is not necessarily called. If DestroyWindow is not called in the MFC code, then you have to explicitly call it in your own code if you want it to be called.

Assume, for example, you have overridden DestroyWindow in a CView-derived class. Since MFC source code does not call DestroyWindow in any of its CFrameWnd-derived classes, your overridden DestroyWindow will not be called unless you call it explicitly.

If the window is the parent of any windows, these child windows are automatically destroyed when the parent window is destroyed. The DestroyWindow member function destroys child windows first and then the window itself.

이러저러한 얘기는 많지만 내가 알고싶었던 것은 Child Window를 Destroy 하느냐 마느냐였는데 잘 나와있다.

알고 쓰고 정리하자. ㅠㅠ

'저장소 > VC++' 카테고리의 다른 글

[Debugging] First-chance Exception과 Second-chance Exception  (0) 2012.01.12
[Win32 API] GetAsyncKeyState  (0) 2011.11.25
[MFC] MainFrame 크기 고정  (0) 2011.10.21
[Win32 API] Window Styles  (0) 2011.10.10
[MFC] CFileDialog 사용 주의점  (0) 2011.09.23

[MFC] MainFrame 크기 고정

저장소/VC++
최초 실행시 MainFrame의 크기를 정하기 위해서는 PreCreateWindow를 재정의하여 다음과 같이 해주면 된다.

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWndEx::PreCreateWindow(cs) )
		return FALSE;
	cs.cx = 1024;
	cs.cy = 768;

	...

}


MainFrame의 크기를 고정하기 위해서는 WM_GETMINMAXINFO 메시지를 다음과 같이 처리해주면 된다.

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
	lpMMI->ptMinTrackSize.x = 1024;
	lpMMI->ptMinTrackSize.y = 768;
	lpMMI->ptMaxTrackSize.x = 1024;
	lpMMI->ptMaxTrackSize.Y = 768;

	CFrameWndEx::OnGetMinMaxInfo(lpMMI);
}


이와 같이 처리하면 MainFrame의 크기를 변경할 수 없게 된다.
크기 변경 불가, 최대화 버튼 비활성화를 처리하기 위해서는 PreCreateWindow에서 style을 다음과 같이 변경해주면 된다.

cs.style &= ~FWS_MAXMIZEBOX; cs.style &= ~FWS_THICKFRAME;

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] GetAsyncKeyState  (0) 2011.11.25
[MFC] DestroyWindow  (0) 2011.11.24
[Win32 API] Window Styles  (0) 2011.10.10
[MFC] CFileDialog 사용 주의점  (0) 2011.09.23
[Error/Warnning] error LNK2005  (0) 2011.08.16

[Win32 API] Window Styles

저장소/VC++
글 싸기가 귀찮아서 걍 검색한 내용.
원문 작성자님 감사합니다. ㅎㅎ;;

출처 : http://blog.naver.com/kimgudtjr/140095980103


[윈도우 스타일]

 

CreateWindow 함수의 세번째 인자로 윈도우의 스타일을 지정할 수 있는데..

WinUser.h  라는 헤더파일을 보면 여러가지 종류가 정의도어 있다.

독자가 그 파일을 열어 봤더니 아래와 같은 종류들이 나열 되어 있었다.

 

------------------ WinUser.h 에서 윈도우 스타일 정의------------------------

/*
 * Window Styles
 */
#define WS_OVERLAPPED       0x00000000L //디폴트 윈도우
#define WS_POPUP            0x80000000L  // 팝업 윈도우를 만든다. WS_CHILD와 함께 쓸수 없다.
#define WS_CHILD            0x40000000L  //차일드 윈도우를 만든다. WS_POPUP와 함께 쓸 수 없다.
#define WS_MINIMIZE         0x20000000L  //최초 최소화된 상태로 윈도우를 만든다.
#define WS_VISIBLE          0x10000000L  //윈도우를 만들자 마자 화면에 출력한다.
#define WS_DISABLED         0x08000000L  // 사용금지된 상태, 즉 입력을 받아들일 수 없는 상태로 만든다.
#define WS_CLIPSIBLINGS     0x04000000L //차일드끼리 상호 겹친 영역은 그리기 영역에서 제외된다.
#define WS_CLIPCHILDREN     0x02000000L //차일드가 위치한 영역은 그리기 영역에서 제외된다.
#define WS_MAXIMIZE         0x01000000L  // 최초 최대화된 ㅏㅇ태로 윈도우를 만든다.
#define WS_CAPTION          0x00C00000L     /* WS_BORDER | WS_DLGFRAME  */  // 타이틀 바를 가진 윈도우를 만들며 WS_BORDER 스타일을 포함한다.
#define WS_BORDER           0x00800000L  // 단선으로 된 경계선을 만들며 크기 조정은 할 수 없다.
#define WS_DLGFRAME         0x00400000L // 두꺼운 경계선을 가지며 타이틀 바를 가질 수 없다.
#define WS_VSCROLL          0x00200000L  // 수직 스크롤 바를 가진 윈도우를 만든다.
#define WS_HSCROLL          0x00100000L  // 수평 스크롤 바를 가진 윈도우를 만든다.
#define WS_SYSMENU          0x00080000L // 시스템 메뉴를 가진 윈도우를 만든다.
#define WS_THICKFRAME       0x00040000L // 크기 조정 가능한 두꺼운 경계선을 가진다.
#define WS_GROUP            0x00020000L  // 라디오 버튼 등 그룹을 이루는 컨트롤의 그룹 지정에 사용된다.
#define WS_TABSTOP          0x00010000L // Tab키로 포커스를 이동할 수 있다.

#define WS_MINIMIZEBOX      0x00020000L // 최소화 버튼을 만든다.
#define WS_MAXIMIZEBOX      0x00010000L // 최대화 버튼을 만든다.


#define WS_TILED            WS_OVERLAPPED
#define WS_ICONIC           WS_MINIMIZE
#define WS_SIZEBOX          WS_THICKFRAME
#define WS_TILEDWINDOW      WS_OVERLAPPEDWINDOW

/*
 * Common Window Styles
 */
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED     | \ /*가장 일반적인 윈도우 스타일*/
                             WS_CAPTION        | \
                             WS_SYSMENU        | \
                             WS_THICKFRAME     | \
                             WS_MINIMIZEBOX    | \
                             WS_MAXIMIZEBOX)

#define WS_POPUPWINDOW      (WS_POPUP          | \  /* 일반적인 팝업 윈도우*/
                             WS_BORDER         | \
                             WS_SYSMENU)

#define WS_CHILDWINDOW      (WS_CHILD)


------------------------------------------------------

이렇게 위와 같이 나와있었다. 오른쪽의 주석 표시는 독자가

책을 보고 일일이 따라 써본것이다^^: 실제 헤더파일은 저렇게 친절하게 한글로

안써있다.. -_-ㅋㅋㅋ


윈도우의 스타일은 서로 중복되어서 줄수 없는 것들이 있는데 그 대표적인 3가지가 아래 3가지 이다.

- 오버랩드

- 차일드

- 팝업


위의 3가지는 서로 겹쳐서 스타일을 줄수가 없다. 만약     WS_CHILD  | WS_POPUP  라고 추면 에러를 발생시킨다.

이유는 상식적으로 생각해봐도 기능적으로 봐도 서로 모순되는 기능들이라서 그렇다..


------------------------------------------------------------------------

[확장 스타일]

 

HWND CreateWindowEx(DWORD dwExSystel, LPCESTR lpClassName, ..............)


CreateWindow 함수에서 끝에 EX가 더붙은 건데 딱 봐도 확장된 이라는 뜻으로 보이며 맞다 -_-ㅋ

CreateWindowEx 함수는 CreateWindow 함수와 다~~~~~ 똑같은데  맨앞의 인자에 딱 하나만 더 추가할 수 있는데

(인자가 딱 하나 더 많다.. 그게 맨 앞에 꺼다..)

CreateWindow에서 지정할수 없는 좀더 고급스러운 스타일 옵션을 줄수 있다고 한다.. -_-ㅋ

그리고  맨앞의 인자가 고급스로운 옵션이라고 했는데 그냥 그 인자를 0 으로 주면 그냥 CreateWindow 함수를 호출하는 것과

동일하다..

사실 우리가 CreateWindow 라고 호출하면 내부에서는 CreateWindowEx함수의 앞에 0으로 넣고 호출하는 거라고 한다.

그러니 우리가 썼던 CreateWindow 함수는 결국 CreateWindowEx 함수의 첫번째 인자 0을 넣고 썼던 것이다. (물론 자동으로 그렇게 해준거지만..)

그 확장 스타일 또한 WinUser.h 라는 헤더 파일에 있는데.. 독자가 한번 열어 봤다. 아래와 같다.. (징그럽게 많다 -_-ㅋㅋ)

 

------------------ WinUser.h 에 있는 확장 윈도우 스타일 정의 ------------------

/*
 * Extended Window Styles
 */
#define WS_EX_DLGMODALFRAME     0x00000001L  // 이중 경계선을 가진 윈도우를 만든다.
#define WS_EX_NOPARENTNOTIFY    0x00000004L  // 생성되거나 파괴될때 부모 윈도우에게 WM_PARENTNOTIFY 메시지를 보내지 않는다.
#define WS_EX_TOPMOST           0x00000008L  // 모든 윈도우보다 수직적으로 위에 있는 윈도우를 만든다.비활성화상태도 다른윈도우에 가려지지 않는다.
#define WS_EX_ACCEPTFILES       0x00000010L  // 드래그 되는 파일을 받을 수 있다.
#define WS_EX_TRANSPARENT       0x00000020L  // 형제 윈도우가 다 그려지기 전에 그려지지 않아 투명하게 보이는 윈도우를 만든다.
#if(WINVER >= 0x0400)
#define WS_EX_MDICHILD          0x00000040L  // MDI 차일드 윈도우를 만든다.
#define WS_EX_TOOLWINDOW        0x00000080L  // 플로팅 툴바 형식의 윈도우를 만든다. 타이틀 바의 높이가 보통윈도우보다 낮으며 작은 폰트를 사용한다.
      // 툴 윈도우는 타스크바에 나타나지 않으며 Alt+Tab 키로 전환 할 수도 없다. 시스템 메뉴 아이콘은 없으나
      // Alt+Space키로 시스템 메뉴는 호출할 수 있다.


#define WS_EX_WINDOWEDGE        0x00000100L  // 양각 모양의 경계선을 가진 윈도우를 만든다.
#define WS_EX_CLIENTEDGE        0x00000200L  // 작업영역이 쑥 들어간 3차원 음각 모양을 만든다.
#define WS_EX_CONTEXTHELP       0x00000400L  // 타이틀바에 ? 버튼을 출력한다. 이 버튼은 도움말 제공에 사용되며 클릭시 커서가 ? 모양으로 바뀌며
      // 차일드를 클릭할 때 WM_HELP 메시지를 보낸다.

#define WS_EX_RIGHT             0x00001000L  // 캡션을 타이틀 바 오른쪽으로 정렬한다.
#define WS_EX_LEFT              0x00000000L  // 캡션을 타이틀 바 왼쪽으로 정렬한다. 이 스타일은 디폴트 이다.
#define WS_EX_RTLREADING        0x00002000L  // 오른쪽에서 왼쪽으로 텍스트를 출력한다. 한국어에는 적용되지 않는 스타일이다.
#define WS_EX_LTRREADING        0x00000000L  // 왼쪽에서 오른쪽으로 텍스트를 정렬한다.
#define WS_EX_LEFTSCROLLBAR     0x00004000L  // 수직 스크롤 바를 작업영역 왼쪽에 배치한다.
#define WS_EX_RIGHTSCROLLBAR    0x00000000L  // 수직 스크롤 바를 작업영역의 오른쪽에 배치한다.이 스타일은 디폴트이다.

#define WS_EX_CONTROLPARENT     0x00010000L  // Tab 키로 차일드 사이를 전환할 수 있다.
#define WS_EX_STATICEDGE        0x00020000L  // 사용자가 입력을 받아들이지 않는다는 의미로 삼차원 장식을 한다.
#define WS_EX_APPWINDOW         0x00040000L  // 윈도우가 보일 때 강제로 타스크 바 위에 있도록 한다.


#define WS_EX_OVERLAPPEDWINDOW  (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE)  // 복합 속성
#define WS_EX_PALETTEWINDOW     (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST) // 복합속성

----------------------------------------------------------------------------------------

 

역시나 옆에 한글로된 주석은 원래 헤더파일에 없고 독자가 책을 보고 쓴것이다. -_-ㅎㅎㅎ


저 많은 스타일을 일일이 다 해보면 좋겠지만  ( 진짜 좋나??? ) 솔직히 의미 정도만 파악하고  실무에서 찾아 쓸수 있으면 된다는

생각을 독자는 갖고 있다. -_-ㅋ 그렇다면 책에서 나온 예제로   몇가지 스타일만 실험 해보자

먼저 CreateWindowEx 함수의 첫번째 인자에 WS_EX_TOPMOST 를 줘서  모든 윈도우의 최상위에 보이게끔 옵션을 줘보자


---------------------------- WS_EX_TOPMOST 옵션을 준 윈도우 예제 ------------------------------


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("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;
  WndClass.lpszClassName = lpszClass;
  WndClass.lpszMenuName = NULL;
  WndClass.style = CS_HREDRAW | CS_VREDRAW;

  //------------ 위 부분은 윈도우 클래스를 설정해주는 것이다. --------------------

  RegisterClass(&WndClass);   //  <-- 여기서는 위에서 설정한 클래스를 등록한다.

  hWnd = CreateWindowEx(WS_EX_TOPMOST,lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
    CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);   // 설정하고 등록한 윈도우를 생성한다.

  ShowWindow(hWnd,nCmdShow);   //생성한 윈도우를 출력..(이 함수를 호출하지않으면 윈도우가 보이지 않는다.)

  while(GetMessage(&Message,NULL,0,0))   //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
  {
   TranslateMessage(&Message);
   DispatchMessage(&Message);
  }

  return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
 HDC hdc;
 PAINTSTRUCT ps;
 TCHAR buf[] = "이 윈도우는 WS_EX_TOPMOST 옵션을 줘서 항상 다른윈도우 위에 있다..";

  switch(iMessage)
  {
  case WM_PAINT:
  hdc = BeginPaint(hWnd,&ps);
  TextOut(hdc,10,10,buf,lstrlen(buf));
  EndPaint(hWnd,&ps);
   return 0;

  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
  }

 return DefWindowProc(hWnd,iMessage,wParam,lParam);  //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}


----------------------------------------------------------------------------------------

보는 바와 같이 화면 가장 앞으로 나와있어서 모든 윈도우를 가린다. 의미 그대로 가장 위에 올라와 있는 윈도우를 만든다..

 

 


----------------------------------------------------------------------------------


다음에는 윈도우의 경계선을 바꾸는 경계석 스타일을 확인해보자

스타일 이름뒤에 EDGE 가 붙는 스타일이 경계선 관련 옵션이다. 아래 코드는  총 8개의 윈도우를 차례대로 출력하되

각 경계션 스타일을 다르게하여 한눈에 비교할수 있게 하는 내용이다.  코드를 먼저 보자..


-------------------------- WS_EX 확장스타일 테두리 스타일 예제 ------------------------

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("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)(COLOR_BTNFACE+1);
  WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
  WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
  WndClass.hInstance = hInstance;
  WndClass.lpfnWndProc = 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,NULL,0,0))   //사용자가 종료하기 전까지 반복해서 메세지 처리를 호출한다.
  {
   TranslateMessage(&Message);
   DispatchMessage(&Message);
  }

  return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) //여기서 실제로 메시지를 처리한다.
{
  switch(iMessage)
  {
  case WM_CREATE:
  CreateWindow(TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE, 10,10,90,90,hWnd,(HMENU)0,g_hInst,NULL);
  CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE, 110,10,90,90,hWnd,(HMENU)1,g_hInst,NULL);
  CreateWindowEx(WS_EX_STATICEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE, 210,10,90,90,hWnd,(HMENU)2,g_hInst,NULL);
  CreateWindowEx(WS_EX_WINDOWEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE, 310,10,90,90,hWnd,(HMENU)3,g_hInst,NULL);

  CreateWindow(TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER, 10,110,90,90,hWnd,(HMENU)4,g_hInst,NULL);
  CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER, 110,110,90,90,hWnd,(HMENU)5,g_hInst,NULL);
  CreateWindowEx(WS_EX_STATICEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER, 210,110,90,90,hWnd,(HMENU)6,g_hInst,NULL);
  CreateWindowEx(WS_EX_WINDOWEDGE,TEXT("edit"),NULL,WS_CHILD | WS_VISIBLE | WS_BORDER, 310,110,90,90,hWnd,(HMENU)7,g_hInst,NULL);
   return 0;

  case WM_DESTROY:
   PostQuitMessage(0);
   return 0;
  }

 return DefWindowProc(hWnd,iMessage,wParam,lParam);  //프로그래머가 처리하지 않은 나머지 동작을 기본처리로 넘긴다.
}


--------------------------------------------------------------------------------------------------------


보시는 바와 같이 8개의 윈도우를 만들었는데

위에 4개와 아래 4개는 완전 똑같은 옵션이다..  다만 아래 4개는 위의 옵션에서 WS_BORDER 이라는 옵션만 추가 했는데

테두리만 진하게 한것인데 위에 두번째와 아래 두번째 윈도우는 WS_BORDER 옵션에 영향을 미치지 않는다.

그것은 의미가없기 때문이다. ( 해당 윈도우 옵션에 위반되기 때문이다.. )

 

'저장소 > VC++' 카테고리의 다른 글

[MFC] DestroyWindow  (0) 2011.11.24
[MFC] MainFrame 크기 고정  (0) 2011.10.21
[MFC] CFileDialog 사용 주의점  (0) 2011.09.23
[Error/Warnning] error LNK2005  (0) 2011.08.16
Visual C++ 컴파일러 버전  (0) 2011.04.29

[MFC] CFileDialog 사용 주의점

저장소/VC++
COM 사용을 위해 AfxOleInit 대신 CoInitializeEx를 사용한 상태에서
CFileDialog를 사용할 시 XP에서 문제가 되는 내용이 있어서 정리.

CFileDialog를 띄우고 Filter를 변경하거나 Directory를 변경하여도
파일 내용이 제대로 보이지 않는 문제가 XP에서 발생한다. Win 7에서는 정상동작되고 Vista는 모르겠다.
XP에서 이와 같은 문제가 발생하는 것으로 보아 XP 이전 버전에서도 동일한 문제가 있지 않을까 싶다.
구글링 해보니 알려진 제한 사항이라던데 대충 봤으므로 패스~
Thread Apartment 어쩌구 저쩌구 하던데 역시 패스~

해결 방법은?
CoInitialize를 사용하지 않으면 된다. 일단 되니까 패스~

'저장소 > VC++' 카테고리의 다른 글

[MFC] MainFrame 크기 고정  (0) 2011.10.21
[Win32 API] Window Styles  (0) 2011.10.10
[Error/Warnning] error LNK2005  (0) 2011.08.16
Visual C++ 컴파일러 버전  (0) 2011.04.29
Delay Load 관련 내용  (0) 2011.04.27

[Error/Warnning] error LNK2005

저장소/VC++
런타임 라이브러리 설정에 따른 문제 사항으로 이도 저도 안 될 경우 특정 라이브러리를 무시하도록 설정해야만 해결이 가능하다.
다음은 런타임 라이브러리 설정에 따른 무시해야 하는 라이브러리 목록이다.

Single Thread(libc.lib)
 - libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

Single Thread Debug(libcd.lib)
 - libc.lib, libcmt.lib, msvcrt.lib, libcmtd.lib, msvcrtd.lib

Multi Thread(/MT, libcmt.lib)
 - libc.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

Multi Thread Debug(/MTd, libcmtd.lib)
 - libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, msvcrtd.lib

Multi Thread DLL(/MD, msvcrt.lib)
 - libc.lib, libcmt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib

Multi Thread DLL(/MDd, msvcrtd.lib)
 - libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib


프로젝트 설정에 따라 관련 라이브러리를 무시하도록 설정해주면 된다.

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] Window Styles  (0) 2011.10.10
[MFC] CFileDialog 사용 주의점  (0) 2011.09.23
Visual C++ 컴파일러 버전  (0) 2011.04.29
Delay Load 관련 내용  (0) 2011.04.27
[Win32 API] File Version 확인  (0) 2011.02.22

Visual C++ 컴파일러 버전

저장소/VC++
Visual C++의 컴파일러 버전은 _MSC_VER 라는 매크로 상수로 정의되어있으며 각 버전에 대한 정보는 다음과 같다.


1000 : Visual C++ 4.X
1100 : Visual C++ 5.0
1200 : Visual C++ 6.0
1300 : Visual C++ .NET
1310 : Visual C++ .NET 2003
1400 : Visual C++ .NET 2005
1500 : Visual C++ .NET 2008
1600 : Visual C++ .NET 2010



'저장소 > VC++' 카테고리의 다른 글

[MFC] CFileDialog 사용 주의점  (0) 2011.09.23
[Error/Warnning] error LNK2005  (0) 2011.08.16
Delay Load 관련 내용  (0) 2011.04.27
[Win32 API] File Version 확인  (0) 2011.02.22
[Win32 API] File Information 확인 (1)  (0) 2011.02.22

Delay Load 관련 내용

저장소/VC++
Delay Load 처리 방법은 다음과 같이 소스코드에 추가해주면 된다.

#pragma comment(linker, "/DELAYLOAD:파일이름.dll")

근데 Visual Studio 2008에서 빌드해보면

warning LNK4229: invalid directive '/DELAYLOAD:파일이름.dll' encountered; ignored

이와 같은 경고를 표시한다.
제대로 처리되지도 않는다.

MSDN에 다음과 같이 기술되어있다.
(http://msdn.microsoft.com/en-us/library/7f0aews7%28v=VS.90%29.aspx)

Only the following (comment-type) linker options are available to be passed to the linker identifier:

결국은 Property 설정에서 지정하라는 말인 것 같은데
Property->Linker->Input->Delay Loaded DLLs 에 필요한 모듈을 기술하고 빌드하면 경고 없이 잘 된다.
Delay Load의 Unload는 다음과 같이 설정할 수 있다.
Property->Linker->Advanced->Delay Loaded DLL을 Support Unload(/DELAY:UNLOAD)로 설정해주면 된다.

Delay Load에 대한 보다 자세한 사항은 책과 검색을 통해서 익히도록... 후후후...

[Win32 API] File Version 확인

저장소/VC++
파일 버전만 필요로 할 때가 있으려나...
간단한 파일 버전 확인 방법을 정리한다.

#include 
#pragma comment(lib, "version.lib")

int GetFileVersion(LPCTSTR _lpszFilePath, LPTSTR _lpszBuf, DWORD _cchBuf)
{
	if( NULL == _lpszFilePath	||
		NULL == _lpszBuf		)
	{
		return -1;
	}

	DWORD dwHandle = 0;
	DWORD dwSize = 0;

	dwSize = ::GetFileVersionInfoSize(_lpszFilePath, &dwHandle);
	if(0 == dwSize)
		return -1;

	BYTE* pBlockData = new BYTE[dwSize];
	ZeroMemory(pBlockData, dwSize);

	if(FALSE == ::GetFileVersionInfo(_lpszFilePath, dwHandle, dwSize, pBlockData))
	{
		delete [] pBlockData;

		return -1;
	}

	// File Version
	VS_FIXEDFILEINFO* pVerInfo = NULL;
	UINT uLen = 0;

	if(FALSE == ::VerQueryValue(pBlockData, _T("\\"), (LPVOID*)&pVerInfo, &uLen))
	{
		delete [] pBlockData;

		return -1;
	}

	StringCchPrintf(_lpszBuf, _cchBuf,
					_T("%d.%d.%d.%d"),
					HIWORD(pVerInfo->dwFileVersionMS),	// Major
					LOWORD(pVerInfo->dwFileVersionMS),	// Minor
					HIWORD(pVerInfo->dwFileVersionLS),	// Release
					LOWORD(pVerInfo->dwFileVersionLS));	// Test

	delete [] pBlockData;

	return 0;
}
VerQueryValue의 두 번째 인자인 lpSubBlock의 다른 사용 예로 VS_FIXEDFILEINFO 를 얻어 버전 정보를 확인할 수 있다.
버전 확인 외에 다른 용도는 없는 것 같기도 하고...
버전만 확인할 때 쓰면 되겠다.

[Win32 API] File Information 확인 (1)

저장소/VC++
파일 정보를 확인해야 할 일이 얼마나 있을까?
그나마 많이 확인하는 것이 Attribute나 Size, Version 이정도?
혹시나 필요할 일이 생길까 싶어서 정리한다.

#include 
#pragma comment(lib, "version.lib")

#include 


typedef struct _Lang_And_Code_Page
{
	WORD	wLanguage;
	WORD	wCodePage;
}
LANGANDCODEPAGE, *LPLANGANDCODEPAGE;


int GetFileInformation(LPCTSTR _lpszFilePath, LPCTSTR _lpszInfoString, LPTSTR _lpszBuf, DWORD _cchBuf)
{
	if( NULL == _lpszFilePath	||
		NULL == _lpszInfoString	||
		NULL == _lpszBuf		)
	{
		return -1;
	}

	DWORD dwHandle = 0;
	DWORD dwSize = 0;

	dwSize = ::GetFileVersionInfoSize(_lpszFilePath, &dwHandle);
	if(0 == dwSize)
		return -1;

	BYTE* pBlockData = new BYTE[dwSize];
	ZeroMemory(pBlockData, dwSize);

	if(FALSE == ::GetFileVersionInfo(_lpszFilePath, dwHandle, dwSize, pBlockData))
	{
		delete [] pBlockData;

		return -1;
	}

	UINT uLangCodePage = 0;
	LPLANGANDCODEPAGE pLangCodePage = NULL;

	if(FALSE == ::VerQueryValue(pBlockData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&pLangCodePage, &uLangCodePage))
	{
		delete [] pBlockData;

		return -1;
	}

	//
	int nRet = 0;
	TCHAR szResource[50] = {0,};
	TCHAR* pszBuffer = NULL;
	UINT uBufSize = 0;

	for(UINT i = 0 ; i < (uLangCodePage / sizeof(LANGANDCODEPAGE)) ; i++ )
	{
		StringCchPrintf(szResource, 50, _T("\\StringFileInfo\\%04x%04x\\%s"), pLangCodePage[i].wLanguage, pLangCodePage[i].wCodePage, _lpszInfoString);

		if(::VerQueryValue(pBlockData, szResource, (LPVOID*)&pszBuffer, &uBufSize))
			StringCchCopy(_lpszBuf, _cchBuf, pszBuffer);
		else
			nRet = -1;
	}

	delete [] pBlockData;

	return nRet;
}
이렇게 하면 몇몇 정보는 얻어올 수 있지만 파일 등록정보에서 확인할 수 있는 모든 정보를 확인하지는 못한다.
for문과 같은 처리는 파일 정보가 여러 언어로 되어있을 때 확인하기 위해 사용되는건가?
GetFileVersionInfoSizeEx와 GetFileVersionInfoEx에 첫 번째 인자로 Flag를 받게끔 되어있는데 이와 연관되어있을듯 하다.
MSDN을 대충 해석하고 참고해서 만든 것인데 아무래도 설명이 필요할 것 같다.
GetFileVersionInfoSizeEx와 GetFileVersionInfoEx에 대한 내용을 포함해서 나머지 부분은 다음에 다시...

[Win32 API] 가변인자 처리 방식, 그리고 오류

저장소/VC++
최근 가변인자 처리 과정에서 생각치 못했던 오류가 발생했다.(원인은 내 실수 ㅡㅜ)
그리 어려웠던 것도 아니었는데 시간은 시간대로 소비하고 간신히 원인을 찾았는데 정말 생각하지도 못했던 문제였기에 적어본다.

우선 가변인자 처리에는 _vstprintf_s의 사용보다는 Strsafe.h에 있는 StringCchVPrintf 함수를 주로 사용한다.
익숙해져서이기도 하지만 안전한 문자열 처리를 위해 Strsafe.h에 있는 함수들을 사용하기 때문이다.
내가 보편적으로 쓰는 처리방식은 아래와 같다.
void OuputFunction(LPCTSTR lpszFormat, ...)
{
	TCHAR szContent[1024] = {0,};

	va_list vlist;
	va_start(vlist, lpszFormat);
	StringCchVPrintf(szContent, 1024, lpszFormat, vlist);
	va_end(vlist);

	...
}
로그 기록 처리에 주로 위와 같이 구현해서 사용하는데 쓰다보니 가변인자 처리를 2번에 걸쳐서 쓰게되는 상황이 생겼는데
문제는 여기서 발생했다.
처리 상황을 똑같이 구현해놓기는 뭐하고 다음과 같이 처리해놓으니 문제 증상이 재현된다.
void OuputFunction(LPTSTR _lpszRet, size_t _cchLen, LPCTSTR _lpszFormat, ...)
{
	TCHAR szContent[1024] = {0,};

	if(NULL != _lpszFormat)
	{
		va_list vl;
		va_start(vl, _lpszFormat);
		StringCchVPrintf(szContent, sizeof(szContent) / sizeof(TCHAR), _lpszFormat, vl);
		va_end(vl);
	}

	if(NULL != _lpszRet)
		StringCchCopy(_lpszRet, _cchLen, szContent);
}

void SomeFunction()
{
	TCHAR* pszSampleString = _T("C:\\Users\\Administrator\\Desktop\\style-12px%20Helvetica%2C%20Arial%2C%20Sans-serif;606060_FFFFFF_3399CC_99FF33_006600_666666_FFFFFF;0px%20solid;_blank[1].htm");
	TCHAR szContent[1024] = {0,};

	OuputFunction(szContent, _countof(szContent), _T("[test] %s"), pszSampleString);
	OuputFunction(NULL, 0, szContent);

	_tprintf_s(_T("%s\n"), szContent);
}
증상 재현을 위해 대충 만들었기 때문에 그냥 이러한 상황이 있다 가정한다.
주목해야 할 부분은 바로 pszSampleString의 파일 경로다.
첫 번째, OuputFunction을 거치고나면 szContent에 "[test] C:\Users..." 요로코롬 값이 들어간다.
두 번째, szContent가 다시 OutputFunction의 Format으로 전달되는데 이 때 문자열에 포함된 %로 인하여 문제 발생.
(디버깅으로 하나하나 찾아보니 %s를 두 번째 처리할 때 Access Violation이 발생했다.)

보통 가변인자 처리를 많이 하는 것도 아니고 2번에 걸쳐 처리되게 만들지도 않는다.
좀 편하게 만들자고 여기저기 만들어뒀는데 그것땜에 이런 문제를 발견했다.
생각치도 못했던 파일명으로 인하여 예상하지 못했던 증상을 발견했네. ㅡㅜ
이번 가변인자 처리과정의 문제로 인해 좀 더 생각하고 만들어야겠단 반성을 하게됐다.
끝!