1. 작업 계획 세우기
변환작업은 생각보다 만만한 작업이 아닙니다.
물론 소스가 몇줄 안된다면 아무 상관없겠지만 (그렇다면 새로 짜는게 낳을지도..ㅋ)
보통 툴 업그레이드를 생각하고, 소스를 그대로 가져갈 계획이라면
이미 그동안 6.0으로 작업했던 소스량은 엄청날 것입니다.
당연히 계획수립은 이루어져야 합니다.
담당자가 프로젝트를 변환 하면,
나머지 팀원들이 소스 변환 작업은 언제까지 할 것이며,
그 도중에 급한 요구사항은 어떻게 처리 할 것인지..
툴 업그레이드가 완료되면, 릴리즈 테스트는 어떻게 할 것인지 등등...
하지만, 이런 계획이 제대로만 세워진다면
그다음의 작업 진행은 일사천리로 이루어질 것입니다.
2. 프로젝트 변환
6.0 은 워크스페이스 파일(.dsw) 및 프로젝트 파일(.dsp)로 구성되어 있습니다.
2010 에서는 솔루션 파일(.sin) 및 프로젝트 파일(.vcxproj)로 구성되어 있구요.
Visual Studio 2010에서 Visual C++6.0 워크스페이스 파일을 오픈하게되면,
변환과정을 거치게 됩니다. 우선은 그냥 OK만 계속 누르면 알아서 변환해줍니다.
단 소스세이프를 사용했을때, 소스세이프에 제대로 연결하지 못할수도 있습니다.
물론 Visual Studio 2010에서 소스세이프 연결 메뉴가 존재하기 때문에
그것을 사용해도 무방하지만, 소스세이프 구조를 이상하게 사용하시는 분들은
그것 마저도 안될 수 있습니다. 그때는 새로 생성된 sin 파일고 vcxproj 파일을 메모장에서
열어서 수동으로 소스세이프 연결을 진행하면 됩니다.
3. 컴파일 에러
프로젝트 변환 후 컴파일을 시도 하게 되면 반드시 직면할 수 밖에 없는 문제입니다.
문법 및 사용 함수의 프로토타입 변경등으로 컴파일 에러가 발생합니다.
하지만, 툴에서 비교적 자세히 에러메시지를 보여주기 때문에 그리 문제될 점은 없습니다.
a. C++ 문법에 관련된 오류
- For Loop 에서 선언된 지역변수는 Loop 밖에서 사용할 수 없습니다. VC++6.0은 가능했습니다.
- 반환 값을 정의하지 않았을 경우 VC++6.0 은 기본 int로 선언되었지만, VS2010에서는 에러가 납니다.
b. MFC 관련 오류
클래스/함수/메시지 헨들러 형태 및 정의 변경으로 인해 발생합니다.
최신 MSDN을 참조하여 VS2010 MFC 에 맞게 수정해야 합니다.
핸들러 오류 예제)
ON_WM_NCHITTEST -> LRESULT OnNcHitTest(CPoint point)
ON_MESSAGE -> LRESULT OnProgressing(WPARAM wParam, LPARAM lParam)
c. 오버로드 된 함수 문제
2010에서는 함수의 다형성을 지원하기 위해, 많은 함수들이 오버로드 되었습니다.
즉, 인자값의 타입만 바뀌어서 함수게 새롭게 제공된것들이 많다는 이야기지요
그러다보니, 6.0에서는 그냥 넘어갔던 녀석들이 2010에 와서는 호출이 모호해지는 경우가 종종 발생합니다.
적절하게 인자를 casting 하면 해결됩니다.
d. 함수 포인터 정의의 경우 VC++6.0 은 default 값 정의가 가능했지만, VS2010에서는 불가능 합니다.
예) typedef int (*FUNCPTR)(void *pClass, int iValue = -1); -> VC++6.0 가능 / VS2010 불가능.
※ VS2010 C++ 에는 자료형이 long long(__int64와 같음), long double 형이 존재하며,
이런 자료형으로 함수가 오버로딩 되거나 새롭게 변경된 함수가 많습니다.
참고로 VS2010의 CFile Class Length 관련 데이터는 ULONGLONG(unsigned long long) 자료형을 사용하여,
대용량을 지원합니다.
4. 컴파일 경고
a. VC++2005 이상에서는 C 표준 함수들 대신 보안 함수 사용을 권장합니다.
보안 함수는 접미사 _s 가 붙습니다.
보안 함수를 사용함으로써 메모리 관련 문제를 근본적으로 막을수 있습니다.
strcpy 대신 strcpy_s, scanf 대신 scanf_s 등의 사용을 권장하며, 기존 함수 사용시 Warning을 발생시킵니다.
_CRT_SECURE_NO_WARNINGS define을 사용함으로써 Warning을 무시할수 있습니다.
b. warning C4996: '기존 함수 명': The POSIX name for this item is deprecated. Instead,
use the ISO C++ conformant name: '교체 함수명'.
위와 같은 경고시에는 교체 함수 명"의 함수를 써서 작업해주면 됩니다.
c. Type Library 경고
다양한 함수들이 추가됨에 따라, 타입라이브러리를 불러올 때,
라이브러리내에 같은 이름의 함수가 존재할 가능성이 많아져 충돌이 발생하게 됩니다.
적절하게 rename을 해줘야 합니다. 그렇지 않으면 실제 해당 함수를 사용할때 에러가 발생합니다.
5. 릴리즈 테스트
변환과정만 마치면 실행은 똑같이 될거라고 생각했다면 오산입니다.
빌드후 생성된 제품이 사용하는 모듈도 변경되었기 때문에 (예-MFC dll)
visual 2010용 배포모듈도 함께 배포해야 하며,
그전에 제대로 동작을 하는지 꼭 확인해봐야 합니다.
6.0에서 잘되던 것이, 변환하고 나서 안될 경우도 수두룩합니다.
해결방법은 다 있으니, 차근차근 해결해나가면 됩니다.
6. 그 이외의 참고 사항
소스를 6.0용과 2010용으로 동일하게 사용하기 위해서는 _MSC_VER define을 사용하도록 합니다.
아래 방법이 컴파일러 조건 컴파일에 보편적으로 사용되는 방법입니다.
컴파일러 버전별 _MSC_VER 값은 다음과 같이 정의되어 있습니다.
1000 : Visual C++ 4.x
1100 : Visual C++ 5
1200 : Visual C++ 6
1300 : Visual C++ .NET
1310 : Visual C++ .NET 2003
1400 : Visual C++ .NET 2005
1500 : Visual C++ .NET 2008
1600 : Visual C++ .NET 2010
소스예제)
#if _MSC_VER >= 1600
HANDLE hHandle = Create( a, b, c, d ) // VS 2010
#else
HANDLE hHandle = Create( a, b, c ); // VC++6.0
#endif
-------------------------------------------------------------------------------------
출처: http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=8221&page=4
VC++ 6.0 -> VC++ 2008 변환 사례
| VC++ 일반 2009-01-20 오후 4:56:46 이기호 (fleem) 번호: 8221 / 읽음:6,833
안녕하세요.
매번 DEVPIA에서 정보만 얻어가다가 정보글을 한번 올려봅니다.
VC++ 6.0 에서 개발되었던 프로그램을 VC++ 2008로 변환하면서 생겼던 에러입니다.
확인하시고 업무에 도움이 되셨으면 좋겠습니다.
혹시 지적하실 부분이 있으면 꼭 달아주시면 감사하겠습니다.
1. error C2065 (변수 선언 부분)
for (int i;i<MAX;i++)과 같이 for, if, while 등의 조건 문에 선언된 변수는 VC++ 2008에서 error C2065를 발생시킵니다. 정확히는 처음 변수가 선언된 조건 문에서는 문제 없이 돌아가지만 이후 변수를 재사용하고자 할 경우 선언 없이 사용하면 에러가 발생합니다. 변수를 조건 문 밖에서 선언하면 에러가 사라집니다.
2. error C2440 (Message Map 관련 함수 Return 값 변환)
소스코드에 정의되어 있는 Message Map의 일부 함수들의 반환 값이 VC++ 2008에서 error C2440를 발생시킵니다. 기존에 이 함수들을 Void 형으로 선언하여 사용해도 문제가 없었으나 VC++ 2008에서는 에러를 발생시키기 때문에 반환형을 LRESULT로 바꾸어 주어야 합니다. 또한 함수 내부에서도 Return 값을 선언하여야 에러 없이 프로그램이 실행됩니다.
3. error C2668 (함수 오버로딩 부분)
VC++ 2008은 오버로딩에 매우 민감하게 반응하여 VC++ 6.0에서 허용되던 것이 에러를 발생시킵니다. 예를 들어 Pow 함수의 경우 Pow 함수가 double Pow(double x, double y)로 정의되어 있으므로
Pow(2,i)로 사용할 경우 에러가 발생합니다. 첫 번째 인자 2가 double 형이 아니기 때문인데, 2.0로 바꾸어 주면 에러가 발생하지 않습니다. 함수를 사용할 때, 오버로딩 규정에 맞게 모든 인수를 입력해야 에러가 발생하지 않습니다.
4. Warning 발생 관련
VC++ 2008으로 변환하면서 많은 Warning가 발생하는데, 우리 설비 프로그램에서 발생하는 것은 크게 두 가지입니다. 첫 번째로 Warning 4996은 swprtinf, strcpy 등 문자열을 다루는 crt 함수에 취약점이 많은 관계로 MS에서 새롭게 보완한 crt 함수를 사용하기를 권장하는 경고입니다. 함수 명 뒤에 '_s'를 붙인 보안 강화 함수로 대체하여 사용하거나(ex, swprintf_s) 또는 #pragma warning(disable:4996) 을 선언해주어 경고를 무시하면 해결됩니다. #pragma warning(disable:4996) 선언 시 "stdafx.h"에 선언해주면 편리합니다.
두 번째로 Warning 4819는 ANSI로 인코딩된 소스코드를 사용하는 프로그램이 Visual Studio 2005 이후의 한글 버전에서 경고를 발생시키는 겁니다. 주로 주석 등에 한글 또는 외국어로 작성한 것이 문제가 된다고 하는데, 소스코드를 유니코드로 새로 저장, 해당 외국어를 삭제 또는 첫 번째와 같이 #pragma warning (disable : 4819) 을 선언하여 경고를 무시하면 해결됩니다.
5. 멀티코어 CPU를 활용한 /MP(Build with Multiple Processes)
Visual Studio 2005 Service Pack 1부터 멀티코어 CPU를 활용한 Native C++ 컴파일이 가능하다고 하며 전체 Build 시간을 줄여 준다고 합니다.
위의 그림과 같이 프로젝트 속성 → 구성 속성 → C/C++ → 명령줄 에 "/MP" 명령을 추가해주면 Build with Multiple Processes 가 수행됩니다. 또, 아래와 같이 프로젝트 속성 → 구성 속성 → C/C++ → 코드 생성에서 "최소 다시 빌드 가능" 을 "아니요"로 바꾸어 주어야 "/MP"가 제대로 동작합니다.
7. 기타 세부 사항
a. std::vector iterator 관련 사항
Vision 쪽에서 사용하던 std::vector이 VC++ 2008로 변환 시 문제가 발생합니다.
디버깅 시에는 잡히지 않지만 프로그램 실행 시 프로그램 오류가 발생합니다.
std::vector을 사용할 때, iterator 를 선언하여 for문을 사용하는 경우,
for (i = m_vectorData.begin(); i < m_vectorData.end(); i++)
와 같이 사용할 경우 문제가 없지만
for (i = m_vectorData.end() - 1; i >= m_vectorData.begin(); i--)
와 같이 역순으로 사용할 경우 오류가 발생합니다. 역순으로 iterator를 사용할 경우 reverse_iterator 를 대신 선언하여 사용해야 하며, begin()과 end()도 rbegin() rend()로 바꾸어서 사용해야 합니다.
b. SystemParametersInfo 관련 문제
VC++ 2008에서 SystemParametersInfo 이 문제가 발생했었는데 문제가 발생한 부분은 다음과 같이 SystemParametersInfo 을 이용하여 시스템 설정을 읽는 부분이었습니다.
VC++ 2008에서는 WINVER을 Windows XP로 정의하지 않으면 Vista로 기본 설정하는데, Vista 설정에서 문제가 발생합니다.
위의 부분 중
ncm.cbSize = sizeof(NONCLIENTMETRICS); 을
ncm.cbSize = sizeof(NONCLIENTMETRICS) - sizeof(ncm.iPaddedBorderWidth);
으로 바꾸어 주면 문제가 해결됩니다. VC++ 2008이 Windows Vista 기반의 개발환경(대화상자 등)을 제공하는데 이 부분에서 4 Pixel(iPaddedBorderWidth) 만큼 더 크기를 사용한다고 합니다. 그래서 SystemParametersInfo을 사용할 때, cbSize의 크기를 iPaddedBorderWidth 만큼 빼야 SystemParametersInfo가 정상적으로 작동합니다. 그러나 VC++ 6.0 버전에서 Windows XP로 정의하여 사용할 경우 (#define WINVER 0x0501) 원래대로
ncm.cbSize = sizeof(NONCLIENTMETRICS); 을 사용해야 합니다.
c. Windows, Visual Studio Version 설정
프로그램에서 Windows나 Visual Studio의 Version을 확인할 경우 다음의 설정을 사용하시면 됩니다.
Macro | WINVER | _MSC_VER | ||
설명 | Using the Windows Headers | Visual Studio Version | ||
Version /Number | Windows Server 2008 | 0x0600 | VC 9.0 (2008) | 1500 |
Windows Vista | 0x0600 | VC 8.0 (2005) | 1400 | |
Windows Server 2003 with SP1, Windows XP with SP2 | 0x0502 | VC 7.1 (2003) | 1310 | |
Windows Server 2003, Windows XP | 0x0501 | VC 7.0 (2002) | 1300 | |
Windows 2000 | 0x0500 | VC 6.0 (1998) | 1200 |