최신라이브러리 사용(2008)
1. 2005부터는 배포방법이 바뀌었다.
2. 2008에서는 sp1등의 업데이트를 설치해도 프로젝트 생성시 최신 라이브러리를 기본으로 사용하지 않는다.
-> _BIND_TO_CURRENT_VCLIBS_VERSION를 미리 선언해야 최신 라이브러리를 사용한다.
위의 두가지 내용은 아래 페이지에 정리해놨음.
VC++ 버전별 배포방법과 재배포패키지(Redistributable Package)
Security-Enhanced Versions of CRT Functions - MSDN
warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
버퍼의 길이체크를 하기 위한 _s접미사가 붙는 보안 버전의 CRT 함수가 추가되었다. 사용방법은 기존 함수에 _s를 붙이고 버퍼의 길이를 인자로 더 추가해주면 된다. 당장은 VC에만 존재하지만 앞으로 C++표준에 추가될 수 있다고 한다.
참고사항
1. _s관련 함수는 errno_t를 반환하게 변경되었다.(에러발생)
2. _CRT_SECURE_CPP_OVERLOAD... 관련 3개의 define을 사용하면 버퍼가 배열형일 경우 Template overloads를 이용해서 기존 코드를 자동으로 _s관련 함수로 변경할 수 있다.
Default 값과 설명
_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1
-> secure함수에 길이 인자관련을 생략해준다.
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 0
-> 기존함수 지원 ex) strcpy
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 0
-> 길이체크하는 기존함수 지원 ex) strncpy
위와같이 편한 방법이 있지만 포인터형의 버퍼변수 일경우는 기존과 같이 길이값을 인자로 넣어야 한다.
char a[100]; // 가능
strcpy_s(a, "hello");
char * p = new char[100]; // 불가능(컴파일 에러)
strcpy_s(p, 10, "hello");
위와 같은 코드는 혼란만 올뿐이다. 결론은 secure함수를 사용할꺼라면 인자값을 사용하지말고 overload함수도 사용하지 말자.
해결방법
_CRT_SECURE_NO_DEPRECATE를 정의하면 secure함수를 사용하지 않는다.
또는
_CRT_SECURE_NO_WARNINGS 나 #pragma warning( disable : 4996 )를 사용해서
경고만 무시한다.
참고
http://blog.naver.com/kyuniitale?Redirect=Log&logNo=40021387400
C/C++ Secure Function 에 대해서
secure function 쉽게 사용하는 팁
Deprecated CRT Functions - MSDN
warning C4996: 'stricmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _stricmp. See online help for details.
ISO C++의 명명 규칙을 준수하기 위해 POSIX 이름이 이제 사용되지 않는다. 예를 들어, getch 대신 _getch를 사용한다.
보안 함수와 똑같은 4996 경고가 뜬다. 표준이므로 지키자.
해결방법(임시)
_CRT_NONSTDC_NO_DEPRECATE를 정의하거나
#pragma warning( disable : 4996 )를 사용한다.
Using the Strsafe.h Functions - MSDN
안전한 문자열 함수들(strsafe.h)
warning C4995: 'wsprintf': 이름이 #pragma deprecated로 표시되었습니다.
c/c++ 문자열의 오버플로우를 막기 위해 MS가 제공하는 방안으로 strsafe.h를 선언해서 관련 함수를 사용할 수 있다.
해결방법
#define STRSAFE_NO_DEPRECATE를 정의하거나
#pragma warning(disable : 4995)를 사용한다.
Time Management - MSDN
time_t가 기본 64비트로 변경되었다. (기존 32비트로 3000년까지만 처리 가능했던걸 확장)
실제선언코드
// VC6
// c:\Program Files\Microsoft Visual Studio\VC98\Include\TIME.H
#ifndef _TIME_T_DEFINED
typedef long time_t; /* time value */
#define _TIME_T_DEFINED /* avoid multiple def's of time_t */
#endif
/////////////////////////////////////////////////////////////////////////
// VC9(2008)
// c:\program files\microsoft visual studio 8\vc\include\crtdefs.h
#ifndef _TIME64_T_DEFINED
#if _INTEGRAL_MAX_BITS >= 64
typedef __int64 __time64_t; /* 64-bit time value */
#endif
#define _TIME64_T_DEFINED
#endif
문제점
이부분은 기존 long형으로 처리되던 부분들이 에러없이 자동으로 64비트로 변경되므로 32비트로 처리되던 코드들은 메모리주소가 밀려서 쓰레기값으로 처리될수 있다.
해결방법(임시)
_USE_32BIT_TIME_T 를 정의한다.
MSDN을 참고해보면 위와 같이 define해놓으면 time_t를 32비트로 쓸수 있다.
User-Defined Handlers - MSDN
아래 내용은 기존에 정의되어 사용되고 있던 것이지만 VC6에서 대충 넘어가던것을 2005부터는 정확하게 사용되어야 하는 것들이다.
MFC에서 사용자 정의 메세지를 사용시 User-Defined Handlers의 원형은 아래와 같은데
afx_msg LRESULT memberFxn( WPARAM, LPARAM );
VC6에선 반환값을 void형으로 선언하고 사용해도 문제가 없었지만 2005부터는 컴파일 에러가 발생한다
해결방법
1. ON_MESSAGE를 ON_MESSAGE_VOID로 변경한다.
-> AFXPRIV.H에 선언되어 있는 ON_MESSAGE_VOID를 사용하면 문제는 해결할 수 있지만 AFXPRIV.H파일 자체가 MFC 버젼이 바뀔경우 예고없이 바뀔 수 있는 파일이므로 조심해야하고 위매크로를 사용시 함수의 인자값이 이상하다는 글을 본적이 있으므로 사용시 주의하자. 매크로의 선언은 아래와 같다.(VC6,2008 sp1)
// like ON_MESSAGE but no return value2. LRESULT를 반환하게 함수를 변경한다.
#define ON_MESSAGE_VOID(message, memberFxn) \
{ message, 0, 0, 0, AfxSig_vv, \
(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(void))&memberFxn },
-> 이게 표준이니 이렇게 사용하자.
ON_THREAD_MESSAGE - MSDN
CWinThread를 상속한 클래스내에서는 ON_MESSAGE가 아닌 ON_THREAD_MESSAGE를 사용해야한다.
사용법은 동일하지만 함수원형에 반환 값이 없다.
afx_msg void memberFxn( WPARAM, LPARAM );
매크로의 선언을 비교해보자.(AFXMSG_.H)
// for Windows messages
#define ON_MESSAGE(message, memberFxn) \
{ message, 0, 0, 0, AfxSig_lwl, \
(AFX_PMSG)(AFX_PMSGW)(LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))&memberFxn },
// for Thread messages
#define ON_THREAD_MESSAGE(message, memberFxn) \
{ message, 0, 0, 0, AfxSig_vwl, \
(AFX_PMSG)(AFX_PMSGT)(void (AFX_MSG_CALL CWinThread::*)(WPARAM, LPARAM))&memberFxn },
/Zc:forScope(for 루프 범위의 강제 규칙) - MSDN
/Zc:forScope가 기본적으로 활성화되어 있다. 이부분은 VC6에서 비표준으로 지원 되던 부분의 수정이므로 표준을 준수하자.
해결방법(임시)
속성 -> 구성속성 -> C/C++ -> 언어 -> For 루프 범위 강제 규칙 -> 아니요
또는 #pragma conform(forScope, on) ,
컴파일 옵션에 /Zc:forScope
위방법중 하나를 선택하면 되겠다.
/Zc:wchar_t(wchar_t를 네이티브 형식으로 인식) - MSDN
/Zc:wchar_t가 기본적으로 사용된다.
속성 -> 구성속성 -> C/C++ -> 언어 -> wchar_t를 기본 제공 형식으로 처리 -> 아니요
함수 오버로드에 대한 묵시적 형변환을 사용할 수 없다. VC6에선 상관없던 코드가 최신툴에선 error를 발생한다.
error C2668: 'pow' : 오버로드된 함수에 대한 호출이 모호합니다.
error C2668: 'sqrt' : 오버로드된 함수에 대한 호출이 모호합니다.
위의 에러는 double pow(double x, double y)인 pow함수등을 pow(2,2)같이 호출했을때 발생한다. 이때는 형변환을 하거나 숫자뒤에 '.'를 표시해서 실수로 만들어준다. 표준이므로 지키자.
※표준 준수를 더욱 강화하기 위해
pow의 오버로드 double pow(int, int)가 제거되었습니다. - MSDN
-> int형의 인자를 받던 pow함수가 제거되었다. 그리고 _Pow_int라는 템플릿함수가 추가되었다.
VC6프로젝트를 2005이상으로 업그레이드시 WINVER 가 정의 되지 않아 Default 값을 설정한다는 메세지를 볼수 있다.
WINVER not defined. Deafaulting to 0x0502 (Windows Server 2003)
-> 2008은 Vista가 기본이다.
VS2005이상으로 프로젝트를 새로 생성시는 stdafx.h에 #include "targetver.h"가 선언되며 이곳에 프로젝트가 최소로 지원하는 플랫폼을 정의해놨다.
참고
WINVER값이 잘못설정되어 있으면 API나 라이브러리에서 윈도우의 버젼이 잘못 설정되어 이상하게 동작하거나 에러가 발생할 수도 있으므로 업데이트 후 WINVER관련을 잘 체크하자.
->_WIN32_WINNT값을 0x0500으로 선언하고 필자의 경우 CFileDilog를 사용하면 error가 발생한다. 이유는 OPENFILENAME구조체의 선언때문인데 아래 링크를 참조하자.
MFC 프로젝트를 Visual C++ .NET 이나 대상 운영 체제에서 Visual C++ 2005 변경 이식 - MSDN
해결방법
Using the Windows Headers - MSDN
What's the difference between WINVER, _WIN32_WINNT, _WIN32_WINDOWS, and _WIN32_IE? (구글번역)
-> 윈도우 버젼관련 매크로가 아래와 같이 진행되어온 과정을 설명해준다.(참고)
WINVER | _WIN32_WINNT | _WIN32_WINDOWS | Product release |
0x0400 | not used | 0x0400 | Windows 95 |
0x0400 | not used | Windows NT 4.0 | |
0x0410 | not used | 0x0410 | Windows 98 |
0x0500 | not used | 0x0500 | Windows Me |
0x0500 | not used | Windows 2000 | |
0x0501 | 0x0501 | not used | Windows XP |
0x0502 | 0x0502 | not used | Windows Server 2003 |
0x0600 | 0x0600 | not used | Windows Vista |
아래코드를 stdafx.h의 젤 윗부분에 선언해주면 되며 설정값을 변경하고 싶으면 위 MSDN링크를 참고한다.
#ifndef WINVER
#define WINVER 0x0400
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#if (_MSC_VER > 1200)
#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0410
#endif
#endif // _MSC_VER
#ifndef _WIN32_IE
#define _WIN32_IE 0x0400
#endif
http://support.microsoft.com/kb/912790
2005의 버그인데 2008에도 똑같이 존재한다.
ANSI로 인코딩된 소스코드를 VS.NET 2005 (한글판)에서 빌드하면서 발생하는 문제로 일본판의 경우에도 비슷한
문제가 발생하였고 영문판 VS.NET 2005에서는 발생하지 않는 것으로 알려져있다. 그냥 무시해도 무방할 듯 하다.
해결방법
#pragma warning(disable: 4819) // <- 이 부분을 소스에 추가하거나.
2005버전 이상인 경우는 프로젝트 옵션에서
"프로젝트->속성->구성속성->C/C++->고급->특정 경고 사용 안함" 에 4819를 넣어주거나.
'파일->저장 고급 옵션'
"유니코드 - 코드페이지 1200" 형태로 저장하면 된다.
참고
http://blog.naver.com/khs01016?Redirect=Log&logNo=44587778
http://www.killereco.pe.kr/134
위 정리된 사항을 필자는 아래코드로 헤더파일 하나에 넣고 stdafx의 상위에서 설정해서 사용한다.
sy는 필자 이름이므로 헷갈리지 말자 ㅎㅎ
// syDef.h
#pragma once
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 최소로 지원하는 플랫폼 정의
// Modify the following defines if you have to target an OS before the ones
// specified in the following code. See MSDN for the latest information
// about corresponding values for different operating systems.
#ifndef WINVER // Permit use of features specific to Windows 95 and Windows NT 4.0 or later.
# define WINVER 0x0400 // Change this to the appropriate value to target
#endif // Windows 98 and Windows 2000 or later.
#ifndef _WIN32_WINNT // Permit use of features specific to Windows NT 4.0 or later.
# define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target
#endif // Windows 98 and Windows 2000 or later.
#if (_MSC_VER > 1200) // VC6 초과
# ifndef _WIN32_WINDOWS // Permit use of features specific to Windows 98 or later.
# define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target
# endif
#endif // _MSC_VER // Windows Millennium Edition or later.
#ifndef _WIN32_IE // Permit use of features specific to Internet Explorer 4.0 or later.
# define _WIN32_IE 0x0400 // Change this to the appropriate value to target
#endif // Internet Explorer 5.0 or later.
// #include "targetver.h" -> .net툴에서 위코드가 포함된 헤더파일
// http://msdn.microsoft.com/en-us/library/aa383745(VS.85).aspx - Using the Windows Headers(MSDN)
///////////////////////////////////////////////////////////////////////////////////
// Visual C++ 8이상 세팅
//#define SYUTIL_USE_CRT_SECURE // CRT 보안관련 함수 사용
#define SYUTIL_NOTUSE_NONSTDC_NO // POSIX관련 CRT사용안함
#define SYUTIL_USE_32BIT_TIME_T // time_t를 32비트로 사용함
// VC8(VS2005) 이상 컴파일러설정.
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
// 최신버젼의 VC라이브러리 사용
// Redistributing an Application and Binding It to Specific Libraries - MSDN
// http://msdn.microsoft.com/en-us/library/cc664727.aspx
# ifdef _BIND_TO_CURRENT_VCLIBS_VERSION
# undef _BIND_TO_CURRENT_VCLIBS_VERSION
# define _BIND_TO_CURRENT_VCLIBS_VERSION 1
# else
# define _BIND_TO_CURRENT_VCLIBS_VERSION 1
# endif
// CRT 보안관련 라이브러리 설정
// Security-Enhanced Versions of CRT Functions - MSDN
// http://msdn.microsoft.com/ko-kr/library/wd3wzwts.aspx
# ifdef SYUTIL_USE_CRT_SECURE
# define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 0
# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 0
# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 0
# else
# ifndef _CRT_SECURE_NO_DEPRECATE
# define _CRT_SECURE_NO_DEPRECATE
//#define _CRT_SECURE_NO_WARNINGS
//#pragma warning(disable : 4996)
# endif
# endif // SYUTIL_USE_CRT_SECURE
// POSIX관련 CRT 사용
// Deprecated CRT Functions - MSDN
// http://msdn.microsoft.com/en-us/library/ms235384.aspx
# ifdef SYUTIL_NOTUSE_NONSTDC_NO
# ifndef _CRT_NONSTDC_NO_DEPRECATE
# define _CRT_NONSTDC_NO_DEPRECATE
//#pragma warning(disable : 4996)
# endif
# endif // SYUTIL_USE_NONSTDC_NO
// 안전한 문자열 사용(오버플로우 방지)
// Using the Strsafe.h Functions
// http://msdn.microsoft.com/ko-kr/library/ms647466(en-us,VS.85).aspx
# define STRSAFE_NO_DEPRECATE
//#pragma warning(disable : 4995)
// time_t 64비트 처리
// Time Management - MSDN
// http://msdn.microsoft.com/ko-kr/library/w4ddyt9h.aspx
# ifdef SYUTIL_USE_32BIT_TIME_T
# define _USE_32BIT_TIME_T
# endif // SYUTIL_USE_32BIT_TIME_T
// 유니코드 형식으로 저장하라는 경고 무시 -> VS 버그임
// http://support.microsoft.com/kb/912790
# pragma warning(disable: 4819)
#endif // _MSC_VER
정리중...
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 문자 집합이 기본 유니코드이다.
속성 -> 구성속성 -> 일반 -> 프로젝트 기본값에서 문자 집합 -> 멀티코드 문자 집합 사용
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 런타임라이브러리(CRT)이 기본 /MD, CRT라이브러리에 대해서는 고민해보아야 하고
// 기존라이브러리들과 맞춰주는게 좋다.
속성 -> 구성속성 -> C/C++ -> 언어 -> 런타임 라이브러리 -> /MT
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 비증분 링크
LINK : warning LNK4076: '.\Debug/IIS.ilk' 증분 상태 파일이 잘못되었습니다. 비증분 링크합니다.
프로젝트 -> 속성 -> 링커 -> 일반 -> 증분 링크 사용 -> 아니요(/INCREMENTAL:NO)
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 증분 링크
LNK4075: '/EDITANDCONTINUE'이(가) '/INCREMENTAL:NO' 사양으로 인해 무시됩니다.
프로젝트 -> 속성 -> 링커 -> 일반 -> 증분 링크 사용 -> 예(/INCREMENTAL)
증분링크란?
obj를 합치는과정에서 메모리배치랑 순서 함수들 코드, 데이터 영역등을 계산하게 되는데 이걸 매번 재계산하게되면 시간이 오래 걸리게되죠
그래서 변한건만 재계산하는 과정을 말합니다. 위의 속성은 "증분 링크" 하겠다는거죠.간간히 이전obj가 껴있어 문제가 생기는데
이땐 rebuild all해서 풀링크 하면된다고 하네요 ^^;;
http://cafe.naver.com/bit1004/554
http://blog.naver.com/amoros21?Redirect=Log&logNo=140061746992
http://blog.naver.com/blue7water?Redirect=Log&logNo=10051860035
http://hongyver.pe.kr/ttblog/entry/VC6-%EC%97%90%EC%84%9C-VS2005%EB%A1%9C-%EC%98%AE%EA%B8%B0%EA%B8%B0
'프로그래밍 > Win32 API & MFC' 카테고리의 다른 글
[VSGesture] - Visual Studio 마우스 동작 인식 추가기능 (0) | 2009.12.17 |
---|---|
VC++ 버전별 배포방법과 재배포패키지(Redistributable Package) (9) | 2009.08.24 |
VC의 Profiling(프로파일링) 사용과 수행시간 측정 함수사용법(CRunTimeChk) (0) | 2009.08.18 |
Visual Studio ATL Security Update (0) | 2009.08.03 |
VC++ 관련 다운로드(서비스팩,재배포,Platform SDK,Windows SDK,DirectX SDK) (0) | 2009.04.30 |