윈도우 프로그램은 Windows가 기본 제공하는 각종 .dll 들을 이용해서 프로그램을 하게 된다.

그런데 소스코드를 실행 중에 다음과 같은 고약한 에러가 발생하면서 프로그램이 강제 종료된다.

기본적으로 친절하지 않은 에러 메시지이다.




아래는 프로그램이 멈춘 곳의 콜스택(CallStack)의 정보이다.

Windows가 제공하는 user32.dll에서 에러가 발생했는데 어떤 함수인지 등에 대한 정보가 없이 그냥 메모리 주소 값만 표시해 주고 있다.




이럴 경우 사용하게 되는 것이 윈도우즈의 심볼파일이라고 불리는 PDB 파일들이다.

즉 user32.dll에 대한 .PDB 파일을 마이크로소프트의 Symbol Server로부터 내려 받으면 막연한 메모리 주소 값이 아닌 user32.dll의 어떤 함수에서 에러가 발생했는지의 정보까지를 확인하게 된다.

아래는 Symbol파일이 설치되었을 때 보여주는 정보이다.




그러면 어떻게 Symbol 파일을 설치할수 있는지를 알아야겠는데 과정이 약간은 복잡성이 있다.

프로그램이 실행 중에 위와 같이 프로그램이 강제 종료된 상황에서 Call Stack 탭을 연 후 마우스 우측 클릭 후 팝업 메뉴에서 "Symbol Settings" 메뉴를 클릭한다.




Options 다이얼로그 창에서 아래 작업을 진행한다.


1) PDB 심볼파일을 다운로드 받을 경로를 설정한다(①).

Debugging - Symbols에서 우측 항목 중 Cache symbols in this directory 항목에 심볼파일을 다운로드 받을 경로를 지정해 준다.


2) Symbol file (.pdb) locations: 항목에 아래 경로를 추가해 준다(②③) 

http://msdl.microsoft.com/download/symbols


3) Load all symbols 버튼을 눌러 모든 .pdb 파일들을 다운로드 받는다(④)

아래 그림은 다운로드 받는 장면 중 하나이다.



이렇게 심볼파일이 설치가 되면 Call Stack의 메시지가 아래와 같이 user32.dll 중에서 wsprintfW()함수에서 에러가 발생했음을 보여준다.

-. CallStackFunction.png



아래 이미지는 다운로드된 심볼 파일들 목록 중 일부이다. 이 경우는 Visual Studio 2010이며 Windows 7 64bit 환경일 경우이다.


MFC에서 CString 문자열을 cout을 통해서 콘솔 창에 출력하는 방법


간단한 이야기 같으나 멋모르고 달려들다간 간단하지 않다는 걸 깨닫게 된다는게 문제.


CString msg = _T("");

msg += "::_TrackMouseEvent()가 WM_MOUSELEAVE 메시지를 발생 시켰군";

msg += "\n현재의 클라이언트 뷰의 자식 윈도우의 영역을 빠져~~~ 나갈 때~~ 발생시키는 메시지이다.";


//wcout << (const wchar_t*)msg << endl; //이건 띄워쓰기 뒷 부분은 안 나옴

cout << (CString)msg << endl;


위의 코드를 실행하면 cout을 출력하는 부분에서 msg에 대한 주소 값만 달랑 출력하고 끝난다.

0078F488


wcout << (const wchar_t*)msg << endl 

이 방법을 사용해 보면 문자열 내용의 첫 번째 띄워쓰기 뒷 부분은 또 나오질 않는다.


해법은 

프로젝트명 - 마우스 우 클릭 - Properties - Configuration Property -

General - Character set을 Multi-Byte character set으로 설정해 줘야 가능하다.


이렇게 설정하고 나면 cout 대신에 printf()를 이용해도 된다.

참고로 printf()와 cout은 전자가 속도에서 훨씬 빠르다는 것.


printf("%s", msg);  //가능



MFC에서 두 개의 문자열 합치기


자바, C#, python 등의 언어들에서 2개의 문자열을 합치는 것은 간단하고 고민할 필요가 없는 작업이다.

그러나 MFC에서는 자바와 같은 언어들에서 하던 방법으로는 안통한다.

편리한 언어들에 비해서는 좀 불편하긴 하지만 다음과 같은 방법을 사용해서 처리할 수 있다.


CString msg1, msg2, msg3;


msg1 = "여기는 메시지 맵과 메시지 핸들러 함수를 연결하는 방식이 아닌 Win32방식으로 처리해 봄";

msg2 = "\n여기서 이렇게 처리를 해도 메시지 맵과 연결된 메시지 핸들러 함수도 동일하게 처리가 된다.";

msg3 = msg1 + msg2;


MessageBox(msg3);



Visual Studio 2010의 Dark color theme 적용하기


Visual Studio 2017의 경우는 코드 편집창을 Dark로 변경하는 일이 아주 쉬우나 Visual Studi 2010의 경우는 해당 기능이 제공되지 않는 것 같다.

그렇다고 강렬한 흰색의 압박에 대해 소중한 눈을 방치해 둘수도 없는 노릇이기에 방법을 정리해 본다.


먼저 아래 사이트에서 자신이 원하는 셋팅 파일을 다운로드 받는다.


https://studiostyl.es/


필자의 경우는 아래 두 개를 보통 사용한다.

vs2017.vssettings

wekeroad-ink.vssettings


위의 환경 설정 파일을 다운로드 받았다면 


도구(Tools) - 설정 가져오기 및 내보내기(Import and Settings) - No, just import new settings, overwriting my current settings 항목 선태 - Browser 버튼 클릭하여 저장된 *.vssettings 파일 가져오기 - Finish







이 후에 글자 크기가 너무 작다면 

도구(Tools) - Options - Environment - Fonts and Colors에서 원하는 크기로 조정하면 된다.




Java나 C#을 사용하다가 MFC를 사용하면서 느끼는 짜증나는 불편함이 있다면 문자열 처리에 대한 것이다.

Java나 C#에서의 문자열 처리의 개념으로 MFC에서 시도해보면 당황 스러울 정도로 답답함이 느껴진다.

본 포스트는 MFC에서의 문자열을 사용할수 있는 나름 편리한 도구인 CString을 이용한 코드조각을 소개하고자 한다.


같은 CString끼리는 + 연산으로 쉽게 두 문자열을 합칠수 있으므로 여기서는 CString 타입과 UINT 타입을 합쳐서

하나의 문자열로 만드는 경우를 다뤄보고자 한다.


현재 사용가능한 Serial Port를 출력한다고 가정할 경우 COM이라는 문자열과 1,2,3...과 같은 숫자를 하나의 문자열로 합친다면 다음과 같이 처리하면 된다.


#include <iostream>

using namespace std;


CString str = "COM";

CString port;

//UINT k = 3;

//str += k; //불가능


for (UINT i = 0; i < 7; i++)

{

                //CString과 UINT가 막바로 port = str + i와 같이 합쳐지지 않으므로 

                //UINT를 CString형으로 변환하는 작업

port.Format("%d", i);

port = str + port;


cout << "Available Serial Ports : " << port << endl;

printf("Ports : %s\n", port);

}


그런데 여기서 또 답답한 건 이 소스 코드의 문자 집합이 유니코드 집합을 사용할 경우는 컴파일 단계에서 아예 에러를 뿜는다.


CString str = "COM"; 이 코드에서는 『"const char [4]"에서 "ATL::CStringT<wchar_t, StrTraitMFC_DLL<wchar_t, ATL::ChTraitsCRT<wchar_t>>>"(으)로 변환하기 위한 적절한 생성자가 없습니다라』는 에러를 뿜는다.


port.Format("%d", i); 이 코드에서는 

『인수 목록이 일치하는 오버로딩된 함수 ...의 인스턴스가 없습니다.

              인수 형식이(const char [3], UINT)입니다....』와 같은 에러가 발생한다.


이건 현재 Visual Studio에서 사용중인 문자 집합을 "멀티바이트 문자 집합 사용"으로 변경해 주어야 한다.

문자셋 인코딩 문제는 항상 모든 프로그래밍 언어들에서 신경쓰야 할 부분이지만 이건 정상적인 문법 자체가 잘못됐다고 에러를 내 보내니... 답답한 노릇이다.


문자 집합을 변경하는 방법은

해당 프로젝트 이름에 마우스 우측 클릭 ⇒ 팝업 메뉴에서 "속성" 클릭 ⇒ 해당 프로젝트의 속성 페이지 창에서 ⇒ 구성 속성의 하위 항목 중 "일반" ⇒ 우측 항목들 중 "문자 집합"의 드랍 다운 메뉴에서 "멀티바이트 문자 집합 사용"을 선택 ⇒ 확인




위의 코드를 실행하면 다음과 같을 결과를 내 보이게 될 것이다.


Available Serial Ports : COM0

Ports : COM0

Available Serial Ports : COM1

Ports : COM1

Available Serial Ports : COM2

Ports : COM2

Available Serial Ports : COM3

Ports : COM3

Available Serial Ports : COM4

Ports : COM4

Available Serial Ports : COM5

Ports : COM5

Available Serial Ports : COM6

Ports : COM6


MFC 개발시 콘솔창(DOS 창)에 로그 출력하기.


MFC 개발시 프로그램 실행의 정보를 콘솔 창에 로그로 출력하기 위해서는 

stdafx.cpp안에 아래 코드를 추가하면 프로그램이 실행될 때 콘솔 창이 뜨고 printf()나 cout으로 출력하는 값이 표시가 된다.


#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")    //semicolon이 없음


TestView.cpp에서 특정 변수의 값을 콘솔창에 출력하고 싶다면


#include <iostream> //cout으로 출력하기 위해


... 중 략 ...


std::cout << "x : " << point.x << std::endl;

printf("결과 : %d\n", point.x);


과 같이 사용하면 된다.





+ Recent posts