보통 VC++에서
class A {
char c1;
char c2;
char c3;
char c4;
char c5;
};
class B {
char c1;
int i1;
};
sizeof(A) == 5, sizeof(B) == 8 이 됩니다. int와 char의 순서를 바꿔도 마찬가지입니다.
sizeof(B)의 값이 5 가 아니라 8이 되는 이유는 바이트 정렬(byte alignment)이라는 문제 때문인데, 물론 컴파일러 옵션에 보면 8바이트 정렬, 4바이트정렬... 1바이트 정렬이 있습니다. 디폴트는 8바이트 정렬이죠. (위의 예제는 바이트 정렬의 단위를 디폴트인 8로 했을 때입니다)
왜 이렇게 하냐면 (여러가지 이유가 있겠지만) 메모리를 일정 바이트 단위로 처리하는게 빠르기 때문입니다.
하지만 가끔씩 까먹으면 정말 치명적인 오류를 맞이하게 되죠. 파일 처리나, 통신 같은 곳에서는 장난 아니죠. 이런 경우 #pragma를 사용하세요.
#pragma pack( push, my_data_definition, 1 )
// 이제부터 정의하는 모든 데이터 타입은 1바이트 정렬로 됩니다.
#pragma pack( pop, my_data_definition )
// 여기서는 컴파일 옵션에서 설정한 정렬방법이 사용됩니다.
이렇게 하면 라이브러리로 배포하더라도 항상 정확한 실행이 보장되죠. 적어도 바이트 정렬문제는 없어지죠.
실제로 MS가 배포하는 헤더 파일에도 사용되는 방법입니다.
얘네들은 좀 더 간편한 방법으로 쓰고 있지만...
그런데, 8바이트로 했더라도 멤버중에 가장 큰 데이터형이 long이거나 int면 그것의 크기인 4바이트로 정렬됩니다. 이건 이렇게 구조체를 정의해서 sizeof를 구해보면 알수 있습니다.
typedef struct tagJin {
int a;
int b;
char c;
} Jin;
이건 유닉스랑 똑같죠. 헌데 8바이트 데이터형(double, __int64)가 사용되면 VC++은 8바이트로 정렬하고 유닉스 상에서는 여전히 32비트(4바이트)로 정렬하더군요. 이건 다음과 같이 테스트해봤습니다.
typedef struct tagJin {
double a;
char b;
} Jin;
그럼 유닉스는 32비트 OS라서 32비트씩 처리하지만 PC는 64비트라서
64비트씩 처리할 수 있다는 말이....되네요.
byte alignment는 register가 한번에 처리할 수 있는 크기로 optimize되는거로 알고 있는데...
바이트 얼라인을 1로 해서 B를 만들고 배열을 선언한다면 어떤 위치의 i1의 값을 가져오기 위해서는 메모리에 두번 접근하는 일이 생기게 됩니다. 한번에 메모리를 처리하는건 메모리에서 일정 단위의 배수를 기준으로 이루어지는데 (레지스터의 크기에 따라 결정되는 걸겁니다. 저도 열심히 공부하진 않아서...-_-;) 그 단위 사이에 걸리는겁니다. (char의 경우는 위치만 결정되면 항상 한번에 가져올 수 있으니까 char만 있는 클래스에는 바이트 얼라인이 의미가 없습니다.)
즉, 구조체/클래스를 배열로 선언해서 쓰실 경우 메모리를 조금 더 쓰더라도 속도가 중요하다면 바이트 얼라인을 변경하지 않으시는게 좋습니다. 사실 변수 몇개 선언하면서 메모리 크기를 걱정하진 않으니까요. (비디오 카드에서 24비트보다 32비트 모드가 더 빠를 수 있다는 얘기를 들은 적이 있는데 같은 이유일겁니다.) 물론 올리신대로 통신에서 보내고 받을 때 사용한다면 반드시 pack 사이즈를 확인해주셔야 합니다. 서버쪽이 UNIX일 경우, 그쪽도 확인해주셔야 하고요. 참고로
#pragma pack(1)
struct tagLINK_DATA{
BYTE cbID;
.
.
.
BYTE cbData[1];
}
##pragma ()
위처럼 패킷정보를 처리하게 되면 ...좋은점이 무얼까요? 메모리 순서가 맞게 byte alignment가 되는거죠.
거기다가..추가적인 데이터를 cbData가 계속 할당받을 수 있게 되는거죠..vtabe 쪽 이해가 되신다면 더 쉽게 이해하실 겁니다.
툴바나 다이얼로그 바를 포함한 컨트롤바를 메뉴를 사용해서 보이기, 숨기기를 할 때 다음과 같이 하는게 가장 편한 것 같습니다.
어떤 컨트롤 바를 m_wndBar 라는 이름으로 만들었다고 합시다.
CMainFrame::OnCreate에서 Create를 하겠죠?
그리고 그걸 보이고 숨기는 메뉴가 있겠죠?
그 메뉴의 아이디를 ID_VIEW_BAR 라고 합시다.
그러면 m_wndBar.Create(... , ID_VIEW_BAR); 이렇게 만듭니다.
즉 메뉴의 아이디가 child의 아이디가 되게 하는거죠.
다른 차일드 컨트롤의 아이디와 겹치지 않도록 주의하세요.
그리고 CMainFrame의 메시지 맵에서
ON_COMMAND_EX(ID_VIEW_BAR, onBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_BAR, onUpdateControlBarMenu)
이렇게 두줄을 넣어줍니다. 그럼 끝이에요.
OnBarCheck이나 onUpdateControlBarMenu는 CFrameWnd의 함수인데, 넘어온 인자를 가지고 그 아이디에 해당하는 control bar를 찾아서 알아서 보이고 숨기거나, 상태를 업데이트 해주는 함수입니다.
필요하다면 직접 소스를 찾아서 복사해와서 원하는대로 고쳐서 써도 되겠죠.
콘트롤들의 위치나 크기를 변경하고자 할 때 통상 SetWindowPos()나 MoveWindow() 함수를 이용합니다.
그런데 이 함수들은 각각의 콘트롤들이 개별적으로 그려지기 때문에 화면 깜박임이 심합니다.
특히, FormView나 Dialog를 사용하면 더 심하지요.
이럴때 BeginDeferWindowPos(), DeferWindowPos(), EndDeferWindowPos()라는 Window API 함수를 써보세요. 자세한 사용법은 Help를 보시면 되지만 간단히 요약하면
HDWP hdwp = ::BeginDeferWindowPos (2);
::DeferWindowPos (hdwp, ctrl1.GetSafeHwnd (), HWND_TOP,
Rect1.left, Rect1.top, Rect1.Width (), Rect1.Height (),
SWP_NOZORDER | SWP_SHOWWINDOW);
::DeferWindowPos (hdwp, ctrl2.GetSafeHwnd (), HWND_TOP,
Rect2.left, Rect2.top, Rect2.Width (), Rect2.Height (),
SWP_NOZORDER | SWP_SHOWWINDOW);
::EndDeferWindowPos (hdwp);
이러면 각 콘트롤의 위치와 크기가 결정된후, 한꺼번에 갱신되기 때문에 화면 깜박임이 훨씬 줄어듭니다.
========
제가 즐겨 사용하는 방법은 FormView에다가 다이얼로그 리소스 사용해서 모양을 편집하고 그걸 리사이징시에 컨트롤 위치를 변경시켜주는 방법이죠.
이 방법을 사용하면 리소스 편집으로 하기 때문에 소스에서 동적으로 생성시키느라 소스가 길어지는 일이 없고 maintenance도 쉬울 뿐 아니라, 다이얼로그 박스 처리와 유사하기 때문에 소스 변경이 쉽거든요.
화면 깜박임을 없애는 방법은 여러 곳을 뒤져 봤습니다.
코드 구루도 찾아 봤고 이곳저곳 찾아본 결과, 가장 간단하면서도 강력한 방법은 WS_CLIPCHILDREN을 사용하는 방법이더군요.
다이얼로그 리소스의 프로퍼티에서 WS_CLIPCHILDREN이라는 style만 추가해주시면 대부분의 컨트롤들이 깜박거리지 않으면서 리사이징 됩니다.
플로피티스켓을 포맷하는 기능을 프로그램안에 넣은 일은 그리 흔한일은 아니지만 막상 이 기능이 필요할때는 어떻게 구현할지 좀 막막하겠죠?
DeviceIoControl()이란 함수로 디스크드라이버의 기능을 호출할 수도 있지만 누구나 쉽게 쓸수 있을 정도로 쉬운 함수는 아니기 때문에 좀 더 쉬운 방법을 찾을 수밖에 없게 됩니다.
Shell API중에 SHFormatDrive()라는 함수가 있기는 하지만 ShellApi.h에 정의되지도 않을 뿐더러 MSDN의 Shell API Reference에도 나타나지 않습니다.
하지만 잘 찾아보면 MSDN의 KnowledgeBase에서
HOWTO: Call SHFormatDrive in Windows 95 and Windows NT
Article ID: Q173688
라는 글에서 이 함수에 대한 설명을 찾을수 있습니다.
KnowledgeBase에 나온 내용을 기초로 여기서 SHFormatDrive()라는 API를 설명하겠습니다.
함수의 선언은 다음과 같습니다.
DWORD WINAPI SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options);
HWND hwnd |
HWND 파라메터는 다들 아시겠죠? 부모 윈도우를 지정하는 것입니다.이 파라메터에 NULL을 대입할수 없습니다. 반드시 어떤 윈도우인가를 지정해야 합니다. |
UINT drive |
이 파라메터에는 0으로 시작하는 드라이브의 인덱스를 지정합니다. |
UINT fmtID |
디스크의 식별자를 지정하는 파라메터인데 현재는 SHFMT_ID_DEFAULT만 쓸수 있다고 되어있더군요. |
UINT options |
이 파라메터는 0 과 SHFMT_OPT_FULL, SHFMT_OPT_SYSONLY 중 하나를 지정할 수 있습니다. 0은 빠른포맷을 뜻하고 SHFMT_OPT_FULL은 전체포맷을, SHFMT_OPT_SYSONLY는 시스템 파일만 복사하는 것을 뜻합니다.부팅 디스크를 만들려면 SHFMT_OPT_SYSONLY를 써야겠지요. |
리턴값 : 0, SHFMT_OPT_FULL(1), SHFMT_OPT_SYSONLY(2)의 조합이 리턴됩니다. 파라메터로 넘겨준 옵션은 사용자가 다른 옵션을 선택하면 무시되기 때문에 이 리턴값으로 사용자가 어떤 선택을 했는지 알수 있습니다.
그런데 저는 전체포맷을 선택하고 실행했더니 5라는 리턴값이 나오더군요.
5란 조합은 없는데 리턴값이 이런것을 보면 다른 옵션이 있나 보다 하고 5란 옵션을 주고 SHFormatDrive를 실행해보았지만 SHFMT_OPT_FULL을 준 것과 똑같더군요.
이 함수를 사용하려면 헤더에 이런 선언들을 추가해주어야 합니다. 꼭 헤더가 아니더라도 사용하기 전에만 선언하면 되죠.
#pragma comment(lib,"SHELL32.LIB")는 제가 기본라이브러리가 아닌것을 사용할 때 쓰는 방법인데 FileView 탭에서 라이브러리를 찾아서 넣은것보다 이 방법이 더 편합니다. (이것도 Tip이군. *^^*)
//----------------------------------------------------------------------------
#pragma comment(lib,"SHELL32.LIB")
#if !defined(SHFMT_OPT_FULL)
#if defined (__cplusplus)
extern "C" {
#endif
DWORD WINAPI SHFormatDrive(HWND hwnd,
UINT drive,
UINT fmtID,
UINT options);
//
// Special value of fmtID which means "use the defaultformat"
//
#define SHFMT_ID_DEFAULT 0xFFFF
//
// Option bits for options parameter
//
#define SHFMT_OPT_FULL 0x0001
#define SHFMT_OPT_SYSONLY 0x0002
//
// Special return values. PLEASE NOTE that these are DWORD values.
//
#define SHFMT_ERROR 0xFFFFFFFFL // Error on last format,
// drive may be formatable
#define SHFMT_CANCEL 0xFFFFFFFEL // Last format wascanceled
#define SHFMT_NOFORMAT 0xFFFFFFFDL // Drive is not formatable
#if defined (__cplusplus)
}
#endif
#endif
//----------------------------------------------------------------------------
<CAnimateCtrl 등에서 WM_LBUTTONDOWN 과 같은 마우스 메시지 처리>
CAnimateCtrl 등에서 WM_LBUTTONDOWN 과 같은 마우스 메시지가 오지 않습니다.
WM_NCHITTEST 메시지는 사용자가 윈도우에 마우스를 클릭할 때마다 발생하는 함수로 이 함수가 리턴하는 값에 따라,
HTCLIENT : 윈도우의 클라이언트 영역
HTCAPTION : 윈도우의 캡션 영역
을 결정하게 됩니다.
CAnimateCtrl 에서 WM_LBUTTONDOWN 메시지를 받으려면, WM_NCHITTEST 메시지 핸들러에서
return HTCLIENT;
하면 돼요 쉽죠?
<Console Window 에 Trace 정보 보내기>
Debugging 할때 trace 하고 싶은 정보를 디버깅 창이 아닌 (왜냐하면 디버깅창은 반드시 debug 모드로 프로그램을 debugger 에 attach 한 상태로 실행해야 하니까..) Console 창에 보여주는 방법에 대해서 알아보기로하겠습니다.
실제로 이와 같은 비슷한일을 해주는 프로그램이 있는데, 우리의 간단한 구조와는 관계가 없지만, 잠깐만 살펴보도록 하죠.
debug 모드로 프로그램이 컴파일 되면..Trace() 함수도 프로그램에 같이 포함됩니다.
그래서 프로그램이 실행되는 도중에 trace 문장을 만나면 프로그램은 system trace queue 에 trace 문장을 넣게 되죠..
물론 이때 디버거가 active 한 상태라면 debugger 가 trace queue 를 후킹해서 메세지를 가져오는것 같습니다.. ( 예상입니다. ^^;;;;)
자. 그럼 어떻게 프로그램이 console 에 trace 처럼 원하는 값을 보여줄 수 있을까요?
방법은 아래의 코드 처럼 명시적입니다.
#include <conio.h> // _cprintf 를 위한 header file
// debug 모드라면..
#ifdef _DEBUG
AllocConsole();
#endif
// trace 대신 사용할 함수
// 물론 Trace 를 모두 대체하고 싶다면.
// _cprintf() 대신에.
// #define TRACE( _cprintf(
// 로 선언하시면 됩니다.
#ifdef _DEBUG
_cprintf(... /* any string */);
#endif
// Console 창을 닫습니다.
#ifdef _DEBUG
FreeConsole();
#endif
이렇게 사용하시면.. Trace 에서 찍는 내용이 console 창에 보여진답니다.
make file는 bat 파일입니다. 그러니까 순서대로 읽으시면 됩니다.
문제는 해석이 아니고 쓰이는 용도 이겠죠. 즉, makefile 을 dsw 로 만드는 것 말이죠.
먼저 make file 가 dll, exe 인지 판단합니다. ( 예제 make file 은 exe 입니다.)
그 다음에 VC++ 에서 new 로 만드실때 win32 로 시작하는 프로젝트 4가지 중에 한가지를 택합니다.
대부분 win32 Application 이고, 간혹 win32 Dynamic_Link Library 이겠죠 (예제는 win32 Application)
빈 프로젝트로(Step1 of 1) 해서 만듭니다.
프로젝트가 완성되면 이 프로젝트가 있는 폴더로 make file 이 있던 곳의 *.cpp, *.c, *.h 등을
복사해 놓습니다. 그다음에 프로젝트의 FileView 에서 필요하신 화일들을 추가합니다.
아마 컴파일 오류는 거의 일어나지 않을겁니다. 대신 link 오류가 많이 일어날 가능성이 있습니다.
여기서 다시 make file 해석이 들어 가야 합니다.
예제에서는 ilvfonts.lib winviews.lib 가 보이는 군요. 이것들을 링크 시켜 주시면 되겠습니다.
어떤것은 Visual Stdio 가 대부분을 해주지만 어떻것은 수동으로 해줘야 합니다.
여기서는 두 개 모두 기본 링크 lib 가 아니군요. 이상입니다.
이 모든 것이 모든 makefile 에 다 적용되는 것이 아닙니다.
예를 들면 ddk 에 있는 makefile 는 밑에 해석및 기타 등등 차이가 많아서 아직까지 직접 makefile 에서 .dsw 를 만든적은 없습니다.
********************** Make file **********************************************
# --------------------------------------------------------------------------
# platform : msvc5
# subsytem : stat_md
# --------------------------------------------------------------------------
// # 은 주석입니다.
ROOTDIR = ..
VIEWSDIR = $(ROOTDIR)\..\..
VIEWSINCDIR = $(VIEWSDIR)\include
VIEWSLIBDIR = $(VIEWSDIR)\lib\$(SYSTEM)\$(SUBSYSTEM)
SYSTEM = msvc5
SUBSYSTEM = stat_md
// 무엇에 쓰이는지 모르지만 ROOTDIR 은 .. 이라고 했군요.
// 무엇에 쓰이는지 모르지만 VIEWSDIR 은 $(ROOTDIR)\..\..
// 그러면 VIEWSDIR 은 ROOTDIR 을 아니까
// MIEWSDIR ..\..\.. 이 되는 군요.
// 여기서 $(문자열) 은 ROOTDIR 로 선언한 것을 대치됩니다.
// 이정도면 위에 것은 다 해석이 되셨고
// # 은 주석
# Debug options:
DEBUG = 0
LDDEBUG = 0
!if $(DEBUG)
DEBUGFLAGS = /Zi /Od /D"DEBUG"
LDDEBUG = 1
RCDEFINES = /d_DEBUG
!else
DEBUGFLAGS = /Gs /Ot /Ox /O2
RCDEFINES = /dNDEBUG
!endif
!if $(LDDEBUG)
LDDBGFLAGS = /debug /DEBUGTYPE:CV
ARFLAGS =
!else
LDDBGFLAGS = /PDB:none
ARFLAGS =
!endif
// if - else 문은 아실테니 설명 안 하겠습니다.
CCC = cl
COMPILERFLAGS= /c /DWIN32 /MD /nologo /W3 /G3
LD = link
LDFLAGS = $(LDDBGFLAGS) /NOLOGO /SUBSYSTEM:WINDOWS /MACHINE:I386 /INCREMENTAL:YES
OUTPUTFILE = -Fo
RC = rc
RCFLAGS = /c1252 /I$(VIEWSDIR)\data\res $(RCDEFINES)
SYSLIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib shell32.lib advapi32.lib wsock32.lib imm32.lib
CCFLAGSSYS = /I$(VIEWSINCDIR) $(COMPILERFLAGS)
CCFLAGS = $(DEBUGFLAGS) $(CCFLAGSSYS)
VIEWSLNK = views.lnk
ILVFONTSDIR = $(ROOTDIR)\..\vectfont
ILVFONTSLIB = $(ILVFONTSDIR)\$(SYSTEM)\ilvfonts.lib
ILVFONTSLIBNAME= ilvfonts.lib
ILVFONTSDEP = $(ILVFONTSDIR)\$(SYSTEM)\$(ILVFONTSLIBNAME)
// 상당히 길어 보이지만 위에 설명한 것으로 모잘란 것이 있나요.
// 설명 한 것으로 해석이 다 되죠.
// 예를 들어서 ILVFONTSDEP 는
// 다음과 같이 해석 되겠군요.
// ..\..\vectfont\msvc5\ilvfonts.lib
# --------------------------------------------------------------------------
PROGRAMS = readdxf dxf2ilv ilv2dxf
// 여기까지가 Define 된 것이군요.
all: $(PROGRAMS)
# --------------------------------------------------------------------------
readdxf: readdxf.exe
readdxf.exe: $(ILVFONTSDEP) dxread.obj readdxf.obj viewsico.res
// readdxf.exe 은 dxread.obj readdxf.obj viewsico.res 로 이루워진다.
-@if exist readdxf.exe del readdxf.exe
// 만일 있다면 readdxf.exe 를 지워라
$(LD) $(LDFLAGS) $(ILVFONTSLIB) $(VIEWSLIBDIR)\ilvgadgt.lib $(VIEWSLIBDIR)\views.lib $(VIEWSLIBDIR)\winviews.lib
$(USERSYSLIBS) $(SYSLIBS) -OUT:$@ readdxf.obj dxread.obj $(VIEWSLIBDIR)\ilvmain.obj viewsico.res
// readdxf.exe 은 dxread.obj readdxf.obj viewsico.res 를 link 해라
// 링크 옵션은 link /PDB:none /NOLOGO /SUBSYSTEM:WINDOWS /MACHINE:I386 /INCREMENTAL:YES
// $(ILVFONTSDIR)\$(SYSTEM)\ilvfonts.lib
// $(VIEWSLIBDIR)\winviews.lib $(USERSYSLIBS) $(SYSLIBS)
// -OUT:$@ readdxf.obj dxread.obj
// $(VIEWSLIBDIR)\ilvmain.obj viewsico.res 이다.
readdxf.obj: $(ROOTDIR)\src\readdxf.cpp $(ROOTDIR)\dxfincl\dxread.h
-@if exist readdxf.obj del readdxf.obj
$(CCC) /I$(ROOTDIR) /I$(ILVFONTSDIR) $(CCFLAGS) $(ROOTDIR)\src\readdxf.cpp
dxread.obj: $(ROOTDIR)\src\dxread.cpp $(ROOTDIR)\dxfincl\dxread.h
-@if exist dxread.obj del dxread.obj
$(CCC) /I$(ROOTDIR) /I$(ILVFONTSDIR) $(CCFLAGS) $(ROOTDIR)\src\dxread.cpp
# --------------------------------------------------------------------------
$(ILVFONTSDEP):
cd $(ILVFONTSDIR)\$(SYSTEM)
nmake $(ILVFONTSLIBNAME)
cd ..\..\dxf\$(SYSTEM)
// 밑에 것은
// 예를 들어서 readdxf.obj 가 있으면 지워라.
// ... 등등등.
# --------------------------------------------------------------------------
clean1:
@echo Cleaning ....
-@if exist readdxf.obj del readdxf.obj
-@if exist dxread.obj del dxread.obj
-@if exist dxf2ilv.obj del dxf2ilv.obj
-@if exist dxwrite.obj del dxwrite.obj
-@if exist ilv2dxf.obj del ilv2dxf.obj
-@if exist readdxf.exe del readdxf.exe
-@if exist dxf2ilv.exe del dxf2ilv.exe
-@if exist ilv2dxf.exe del ilv2dxf.exe
# --------------------------------------------------------------------------
viewsico.res: $(VIEWSDIR)\data\res\viewsico.rc
$(RC) $(RCFLAGS) -r -foviewsico.res $(VIEWSDIR)\data\res\viewsico.rc
// viewsico.res 는 rc 가 컴파일 하므로
// 다음과 같은 파라미터로 컴파일이 되겠군요.
// ..\..\..\data\res\viewsico.rc rc /c1252 /I..\..\..\data\res /d_DEBUG -r -foviewsico.res ..\..\..\data\res\viewsico.rc
// 파라미터 설명은 rc 컴파일을 보셔야 겠군요.
clean: clean1
-@if exist *.ncb del *.ncb
-@if exist *.pdb del *.pdb
-@if exist *.ilk del *.ilk
-@if exist *.idb del *.idb
-@if exist *.plg del *.plg
-@if exist *.map del *.map
-@if exist *.res del *.res
-@if exist *.bak del *.bak
-@if exist *.lnk del *.lnk
***************************************** Ending ******************************
- The end of this article -
CRect rect;
m_Btn.GetWindowRect(rect);
int x,y,cx,cy;
x = rect.left;
y = rect.top;
cx = (rect.right-rect.left) + 30;
cy = (rect.bottom-rect.top) + 30;
m_Btn.MoveWindow(x,y,cx,cy,TRUE); // m_Btn은 버튼 변수.
위는 버튼 컨트롤에 대해서 했는데 다른 컨트롤도 위처럼 사용하시면 됩니다.
- 요약
어플리케이션을 릴리즈 모드로 Build 할 때 디버깅 정보를 남기어서 VC++ Debugging Tool에서 디버깅을 가능하게 합니다. 이 방법을 사용하는 경우, 실제 릴리즈 실행 파일은 거의 영향을 받지 않으면서, 디버그에서 브레이크 포인터를 잡거나, Trace를 가능하게 하므로, 릴리즈모드 에서만 발생하는 버그를 잡을수 있습니다.
- 추가정보
이 방법을 사용하게 되면 _DEBUG free define으로 포함되는 디버깅 메크로는 포함되지 않으나, Source code안으로 Step in 가능하게 하는 디버깅 정보들은 OBJ와 PDB 파일에 남게 됩니다. 이를 이용하게 되면 VC++ IDE 환경에서 source level 까지의 step in이 가능해 집니다.
- 방법
1. Project를 open한뒤 menu 'Project/Settings'를 선택합니다.
2. 'Settings For'를 'Win32 Release'로 선택합니다.
3. 'C/C++' tab에서 'category'를 'General'로 선택하고 'Program Database'로 선택합니다.
4. 'Link' tab에서 'category'를 General'로 선택하고 'Generate debug info'를 체크합니다.
5. 'Rebuild All'를 실행하여서 프로그램을 다시 빌드 합니다.
이제 디버깅 하고자 하는 위치에 브레이크포인터를 잡고 'Go'를 실행하면, 디버깅을 진행할수 있습니다.
[↓ Click! byte alignment / 컨트롤바(툴바, 다이얼로그바) 보이기/숨기기 /
컨트롤의 사이즈나 위치 변경시 깜박임 현상 줄이기 /
플로피디스켓 포맷 다이알로그 호출하기 /
CAnimateCtrl 등에서 WM_LBUTTONDOWN 과 같은 마우스 메시지 처리 /
Console Window 에 Trace 정보 보내기 / makefile 을 .dsw 로 바꾸어 보자 ]
'IT_Programming > MFC · API' 카테고리의 다른 글
LRESULT와 CALLBACK의 데이터형에 관해 / I/O 포트 제어법 (0) | 2007.12.25 |
---|---|
다이얼로그 박스 동적으로 키우기 / 도스&콘솔 프로그램 관련 (0) | 2007.12.25 |
Visual C++의 유용한 단축키 / ALT+F4로 종료 안되게 하려면 (0) | 2007.12.25 |
키보드로 마우스 커서 움직이기 / 파일 등록정보 보여주기 (0) | 2007.12.25 |
새창을 활성화시키기 않고 생성시키기 / 생성한 Class를 간단히 완전제거 (0) | 2007.12.25 |