본문 바로가기

Robotics/Software Tech.

Visual Studio 6.0에서 2005이상으로 넘어가야 하는 이유..

사실 쓰기 제일 편하면 그만이다.
하지만.. 시대가 변하고 있는데 아직도 주판을 쓸수야 있나...
아래 글은 마이크로소프트 포럼인가? 암튼.. 그곳에서 신형철이라는 분이 쓴 글입니다.
원문 : http://www.microsoft.com/korea/msdn/msdnmag/issues/06/06/CAtWork/default.aspx

많은 분들이 현재 Visual Studio® 2005로 업그레이드 중일 것으로 생각 됩니다. 그래서 지금 이야 말로 새 컴파일러와 저의 경험담에 대한 글을 쓰기에 좋은 시기인 것으로 생각 되어 이 기사를 쓰게 되었습니다. 왜 이제서야 쓰게 되었냐고요? 늦었다고 생각 될 때가 가장 빠른 것 아니겠습니까?

여러분이 Visual Studio 2005에서 가장 먼저 주목할 것이 바로 버전 관리자 입니다. 이 버전 관리자는 여러분의 프로젝트를 열어본 뒤 어떤 버전을 실행 시킬지를 결정하는 역할을 합니다. Visual Studio 2005를 Visual Studio 2003과 나란히 설치 하실 수도 있습니다. 이 둘은 여러분의 컴퓨터에서 사이 좋게 동거를 하게 되므로 이는 여러분이 한가 할 때 원하는 프로젝트를 따로 업그레이드 하기에 좋겠죠. 2003 버전의 프로젝트를 열면 Visual Studio 2005는 프로젝트를 변환을 하기 전에 복사본을 만들 지를 물어보고 난 이후 변환을 합니다. 변환 중에는 발견되는 모든 문제를 기술한 XML 보고서를 생성 합니다.


언어의 작은 변화

Visual Studio 2005를 간단히 사용해 보기 위해 이전 기사들의 프로젝트 몇 개를 불러와 컴파일 해 보았습니다. Visual Studio 2005는 최신 언어 표준을 따르는 최신 컴파일러 이기 때문에 모든 프로젝트들은 약간의 수정이 필요 했습니다. 대부분의 “새로운” 문법들은 C++ 표준에 올라 간지 꽤 되었으나 Visual Studio는 이제서야 이를 따르게 되었네요.

for loop 안의 지역 변수는 loop 밖에서는 더 이상 유효 하지 않습니다. 전에는 다음과 같이 작성 할 수 있었습니다

for (int i=0; i<max; i++) {
   // do something
}
if (i>0) {
   // do something else
}

이 예제에서 변수 i 의 scope는 for 문 안으로 되어 있으면서 그 밖에서 다시 사용됩니다. 공식적으로 C++는 이를 허용하지 않으므로 이제는 이 코드를 다음과 같이 수정해야 합니다:

int i; // for loop 밖으로 뺍니다
for (i=0; i<max; i++) {
   // do something
}
if (i>0) {
   // do something else
}

선언 되지 않은 정적 변수(지역 또는 전역 변수) 들은 더 이상 default로 정수 형을 갖지 않습니다. 이전에는 다음과 같이 쓸 수 있었고

const BUFLEN=255;

컴파일러는 암묵적으로 BUFLEN 에 int 형을 지정했습니다. 암묵적 int 는 이제 허용 되지 않습니다. 반드시 아래와 같이 선언을 해주어야 합니다:

const int BUFLEN=255;

이는 모든 종류의 변수에 적용 됩니다 – 정적, 전역, 멤버 데이터 그리고 함수의 반환형. int 를 빠트리면 이젠 컴파일러는 “error C4430: 형식 지정자가 없습니다. int로 가정합니다. 참고: C++에서는 기본 int를 지원하지 않습니다.” 라는 에러 메시지를 보냅니다.

C/C++에 대한 변화의 다른 카테고리로 새로운 Safe C 와 Safe C++ 라이브러리를 들을 수 있습니다. 이 라이브러리들은 여러분들이 잘 알고 계시고 애용 하시는 기존의 유행 지난C 런타임(CRT) 함수 보다 안전한 버전을 제공 합니다. strcpy, fopen 등등. Safe C++에 대해서는 다음 기사에서 좀더 다루려고 합니다. 그 때까지 못 기다리시는 분들을 위해 Martyn Lovell 이 쓴 2005년 5월호의 “Safe! Repel Attacks on Your Code with the Visual Studio 2005 Safe C and C++ Libraries”를 소개해 드립니다.

(msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC (영문)).

C++는 그렇다 치고 MFC 는 어떻게 되었을까요? Visual Studio 2005에는 MFC 에는 큰 변화가 없고 이는 제가 전에 말 했던 것처럼 좋은 일이라 할 수 있습니다. 이는 곧 MFC 가 안정적이란 뜻으로 해석 할 수 있습니다. 그러나 CWnd::OnNcHitTest 의 리턴 형이 UINT에서 LRESULT로 바뀌는 등 이과 같은 다른 작은 변화들이 있을 수 있지만 여러분의 기존 MFC 프로그램과 호환이 안 되는 경우는 없을 것으로 보입니다.


페이지 맨 위로페이지 맨 위로

관리 세계로 이동

C++와 MFC는 프로그래밍에 있어 이미 안정화된 부분이므로 이 부분에서 업그레이드를 통한 문제가 발생 하리라 생각 되진 않습니다. Visual Studio 2003과 Visual Studio 2005 간의 큰 변화가 들어간 부분은 관리 코드의 영역입니다. 이 변화 중 하나로 여러분들이 많이 읽어 봤을 새 C++/CLI 구문이 있습니다. 이는 Managed Extension 의 버전 V2 라고 생각 하시면 됩니다. 여러분들이 이를 사용하기에 아직 준비가 안 되셨다고 생각하면 /clr:oldSyntax 옵션을 이용해 이전의 Managed Extension 을 그대로 사용하면 됩니다. 이 옵션은 관리 또는 관리/네이티브 프로젝트를 Visual Studio .NET 2003 에서 Visual Studio 2005로 업그레이드 하면 기본으로 사용됩니다.

새 컴파일러에서 관리 코드를 테스트 해보기 위해 지난 2005년 4월호의 기사 "Wrappers: Use Our ManWrap Library to Get the Best of .NET in Native C++ Code"의 ManWrap 라이브러리를 사용 해보았습니다. ManWrap 은 wrapper DLL (regexWrap.dll)과 RegexText, RegexForm 그리고 WordMess 테스트 프로그램으로 구성 되어 있습니다. (그림 1 참조) ManWrap은 작으면서 수행하는 일이 - 관리/비관리(Managed/Unmanaged) 코드를 한 DLL에 넣음으로 - 꽤 복잡한 편이라 이 글에 사용하기에 좋은 예제라 판단이 됩니다. RegexWrap 은 공용 언어 런타임(CLR)의 Regex 클래스를 wrapping 하는 네이티브 DLL 입니다.

그림 1 관리 코드 테스트 하기
그림 1 관리 코드 테스트 하기

기존의 구문을 그대로 두고 컴파일러를 돌렸습니다. 곧바로 스크린에는 다음과 같은 에러 메시지들이 죽 올라 왔고요. “C3395 ... __declspec(dllexport)를 __clrcall 호출 규칙이 있는 함수에 적용할 수 없습니다.” 뭐시라고?

ManWrap은 순수 네이티브 C++ 코드에 관리 클래스를 wrapping 할 수 있게 해주는 라이브러리 입니다. /clr 옵션 없이도 네이티브 C++ 코드에서 CLR을 호출 할 수 있게 해 주는 것이죠. 예를 들어 Visual C++® 6.0 컴파일러를 사용하는 기존의 프로그램이 있는데 CLR 을 사용하는 특정 기능을 추가 하고자 한다고 합시다. /clr 옵션을 사용하지 않고는 C++에서 관리 클래스를 직접 호출 할 수 없습니다. (Visual C++ 6.0 은 이 옵션을 지원 하지도 않습니다.) 따라서 관리 클래스를 호출 하기 위해서는 이를 네이티브 entry point가 있는 DLL에 wrapping 하는 방법을 사용 해야 합니다.

ManWrap이 사용하는 꼼수는 _MANAGED 라는 미리 정의된 전처리 심볼을 이용하여 내부 사용이나 외부 사용에 따라 다른 코드를 생성 하게 하는 방법 입니다. 각 wrapper 클래스는 한 개의 데이터 멤버 – 관리 객체의 핸들 - 를 갖습니다:

#ifdef _MANAGED
# define GCHANDLE(T) gcroot<T*>
#else
# define GCHANDLE(T) intptr_t
#endif

Wrapper 클래스들은 GCHANDLE을 이용해 객체 핸들을 다음과 같이 선언 합니다:

// wrapper for managed Object
class CMObject { 
   GCHANDLE(Object) m_handle;
};

CMObject가 정의된 헤더 파일은 두 가지 방법으로 컴파일 됩니다. Wapper DLL을 빌드 할 때에는 _MANAGED 가 정의 되도록 /clr 옵션을 주고 컴파일 하면 컴파일러는 m_handle 을 gcroot<Object*>로 판단 하게 됩니다. Wrapper를 호출 하는 네이티브 프로그램을 빌드 할 때에는 _MANAGED 가 정의 되지 않도록 /clr 옵션이 없이 컴파일 하고 이때 컴파일러는 m_handle을 intptr_t로 판단 합니다. 이게 제대로 작동 하는 이유는 gcroot<Object*>가 intptr_t 와 동일한 크기를 갖는다는 것이 보장 되기 때문입니다. Wrapper DLL 만이 그 핸들이 무엇인지 알 수 있습니다. 바깥 (네이티브) 에서 봤을 땐 m_handle 은 HWND, HINSTANCE나 다른 핸들과 비슷한 매직 쿠키에 지나지 않습니다. 단지 여기서 주의 할 점은 복사 생성자와 대입 연산자가 인라인 함수가 아닌 실제 함수이어야 한다는 것입니다. 그래야 실제 wrapper로 호출이 들어가서 그 핸들을 실제 객체로 보고 다루게 됩니다. (intptr_t 핸들을 복사 하면 안되고 gcroot를 통해야 합니다.)

이 핸들을 갖고 있는 것과 더불어 ManWrap은 객체를 생성하고 복사하는 함수들을 정의 합니다. 또한 각 Wrapper 클래스는 ctor 와 -> 연산자를 정의 하여 wrapper가 해당 관리 형으로부터 네이티브 wrapper 객체 들을 생성 하고 접근할 수 있게 금 합니다. 예를 들어 관리 Regex 에서 네이티브 CMRegex를 생성 하는 생성자가 있습니다. 관리 클래스들은 ctor와 -> 연산자를 내부적으로 사용합니다. 그림 2 에서 ManWrap.h의 일부 코드를 보실 수 있습니다. 관리 Method들이 #ifdef _MANAGED 안에 있는 것도 보실 수 있습니다.

그리고 클래스 전체가 WREXPORT로 익스포트 되어 있는데 이 때문에 C3395 에러가 나는 것 입니다. 네이티브 함수와 관리 함수들은 서로 다른 호출 규약을 사용하기 때문에 __declspec(dllexport)를 이용해 관리 method(관리 인자 들을 갖고 있는 method들)들을 익스포트 할 수 없습니다. 충분히 말이 되는 말이죠. 네이티브 DLL에서 관리 함수들을 익스포트 하려는 것 자체가 이상하니까요. 그러나 이는 실제로 익스포트 하는 것이 아닙니다. 이들은 모두 인라인으로 정의 되어 있습니다. 이 관리 method 들은 네이티브 interface에 필요하지도 않고 보이지도 않습니다. 그러나 컴파일러는 이를 모릅니다. Visual Studio 2005가 이전 컴파일러만큼 똑똑 하지 않아 클래스 전체를 익스포트 할 수 있게 허용 한 것으로 보입니다. 아니라면 너무 똑똑 하여 관리 method를 네이트브 코드에서 익스포트 한다는 것 자체가 말이 안된다고 판단 하는 건지.. 어쨌든 Visual Studio 2005는 관리 method를 갖는 클래스가 익스포트 되는 것을 허용하지 않는다는 것입니다.

그럼 이제 어떻게 할까요? 제가 컴파일러에게 명령하고 싶은 것은, “클래스 전체를 익스포트 하되 이 세 method 들만은 제외 시켜라.” 입니다. 다시 말해 특정 method 에 대해서 __declspec(dllexport)를 적용 안되게 하는 방법을 원하는 것이죠. 이런, 그런 옵션은 존재 하지 않는 군요. 따라서 이를 해결 할 수 있는 방법으로 두 가지가 있습니다. : WREXPORT를 클래스 선언에서 제거 하고 이를 각 네이티브 method 앞에 붙이거나 문제를 일으키는 method 들을 완전히 제거 하는 방법입니다. 첫 번째 방법이 더 간단 하여 전 이 방법을 택했습니다. WREXPORT를 method 선언으로 옮기는 것이 좀 반복적이고 새 method를 추가 할 때 WREXPORT를 추가 하는 것을 잊어 버려 실수 할 여지가 많이 보이지만 컴파일러가 알아서 알려 주겠죠.

두 번째 방법으로 정말, 꼭 클래스 전체를 익스포트 하고 싶다면 문제가 되는 관리 복사 생성자와 -> 연산자method 들을 모두 제거 하는 것입니다. 그렇게 하면 -> 연산자를 자동으로 호출 하는 다음과 같은 코드 대신에

// MClass의 내부 wrapper 클래스
(*this)->ManagedMethod();

다음과 같이 코드를 작성 해주셔야 합니다:

(static_cast<MClass*>((Object*)m_handle))->ManagedMethod();

정말 깁니다. 다음과 같은 매크로를 사용하면 타이핑을 좀 덜 수 있겠네요:

THISOBJ(MClass*)->ManagedMethod();

이렇게 해도 약간은 거추장스럽거니와 아직 생성자도 직접 건드려 주셔야 합니다. 지금 설명이 잘 안 와 닿는 다면(많은 독자 분들이 그러시리라 생각 됩니다.) 걱정 마시라. 전 좀더 간단한 방법인 첫 번째 방법을 택했습니다. 그림 3을 보시면 WREXPORT를 모든 method에 추가한 수정된 코드를 보실 수 있습니다. 이렇게 수정 한 후엔 ManWrap은 문제 없이 컴파일 됩니다.


페이지 맨 위로페이지 맨 위로

ManWrap 실행 하기

코드를 제대로 컴파일 되게 하였는데 이젠 이 코드가 제대로 실행 되게 해야 합니다. 이 부분이 막혔던 부분 입니다. dbgheap.c 속 깊은 곳의 ASSERT 폭탄 입니다:

ASSERTE(_CrtIsValidHeapPointer(pUserData));

으악! 디버그 심볼 없이 시스템 DLL만 잔뜩 보여주는 stack trace는 거의 쓸모가 없었습니다. 이런 버그가 가장 나쁘고 가장 추적하기 힘든 버그입니다. 프로그램이 시스템 코드 깊은 곳 어딘가에서 죽고 무엇이 문제인지 실마리 조차 없는 경우죠. 그래도 잘 찾으면 실마리는 있습니다. Stack trace를 좀더 자세히 들여다 보니 약 50 frame 앞에 제 코드가 g_Allocator라는 정적 ATL 변수를 접근하는 것이 보였습니다. 아하! 이것이 바로 이 문제 해결의 실마리 였습니다.


g_Allocator는 전역으로 선언된 정적 변수 입니다. C++에서 정적 변수 초기화는 언제나 섬세하게 다루어야 하는 일중 하나로 DLL에서 특별히 더욱 그렇습니다. 컴파일러는 DllMain을 호출 하기 전에 정적 변수들을 초기화 하는 CRT 초기화 함수를 호출하도록 코드를 생성 합니다. 네이티브 나라에서는 모든 것이 잘 작동 하나 여러분의 DLL 이 관리 클래스들을 호출 한다면 Loader-lock 문제에 걸릴 수 있습니다: Windows® 는 여러분의 DLL을 로드 하려고 하고 이는 CLR 을 로드 하려고 합니다. 이는 다시 여러분의 DLL을 로드 하려고 하고 – 즉, loader lock 이라고 알려진 데드락 상황에 처하게 되는 것이죠. 일반적으로 DLL이 로드 될 때에 다른 DLL을 로드 하면 안됩니다. 흔하게 경험할 수 있는 예로는 DllMain 또는 정적 객체 생성자에서 ::MessageBox를 호출하여 진단 메시지를 표시할 경우입니다. 이렇게는 결코 제대로 작동 하지 않죠.

이 loader lock을 피하기 위해 Visual Studio .NET 2003 은 관리 DLL들을 /NOENTRY DLL(DllMain Entry point가 없는 DLL)로 만드는 것을 의무화 했습니다. 그 결과 여러분의 DLL은 _DllMainCRTStartup이 없게 되어 정적 정적 변수들이 초기화가 안됩니다. loader lock은 피 할 수 있지만 벼룩 잡으려다 초가삼간 다 태우는 격이 되어 버린 거죠. 제 2005년 2월 기사에 이 수수께끼에 대한 자세한 설명이 있습니다(msdn.microsoft.com/msdnmag/issues/05/02/CATWork (영문)). MFC와 ATL 에서 정적 객체를 사용 하기 때문에 이는 중요한 문제입니다. DllMain 없이는 ATL 또는 MFC를 사용하는 혼합 DLL 을 만들 수 없으니까요. 이 문제를 해결 하기 위해 친절한 Redmond 사람들은 __crt_dll_initialize 와 __crt_dll_terminate()가 들어 있는 <_vcclrit.h>를 만들어 제공 했습니다.

이 모든 것들이 그냥 거추장스럽게만 들리실 겁니다. 반갑게도 Visual Studio 2005는 혼합 assembly loader-lock 문제를 해결해 출시 되었습니다. 더 이상 _vcclrit.h 나 /NOENTRY 가 없이 혼합 DLL 들을 평소 대로 컴파일 하실 수 있게 되었습니다. 더 자세한 설명은 “http://msdn2.microsoft.com/ko-kr/library/ms173266(vs.80).aspx" 에 “혼합 어셈블리 초기화 " 글을 참조 해보시기 바랍니다.

그러면 왜 ManWrap이 dbgheap.c 에서 죽었을 까요? 이 이유는 이전 프로젝트의 /NOENTRY 가 아직 남아 있었기 때문입니다. 당연히 죽을 상황이 였죠. DllMain도 없었으며 따라서 ATL의 g_Allocator가 초기화 되지 못했습니다. 그래서 바로 /NOENTRY를 없애니, 휴! 제대로 작동 하는 군요.


페이지 맨 위로페이지 맨 위로

새 모자(hat)로 새로 시작

이런 어려운 버그들로부터 얻을 수 있는 축복 이라면 그 버그를 고친 후 맛 볼 수 있는 날아 갈 것 같은 좋은 기분 일 겁니다. ManWrap의 세 test 프로그램(RegexTest, RegexForm, and WordMess) 을 성공적으로 컴파일 하고 실행 시킨 후 전 꽤나 싱글 벙글 했죠. 지난 몇 년간을 겨울잠을 자고 오신 분을 위해 설명 드리자면 C++/CLI의 핵심은 ^(hat) 심볼로 표시 되는 tracking handle 이라는 새 타입이라고 할 수 있습니다. 그래서 저는 /clr:oldSyntax(그림 4 참조)를 없애고 ManWrap.h의 * 를 ^ 로 변경 했습니다:

#ifdef _MANAGED
# define GCHANDLE(T) gcroot<T^>
#else
# define GCHANDLE(T) intptr_t
#endif
그림 4 새로운 구문 사용하기
그림 4 새로운 구문 사용하기

이렇게 하여 변경하고 컴파일 한 이후 컴파일러가 뱉어 내는 에러를 하나씩 고쳐 나갔습니다. 대부분의 에러는 Mumble *를 Mumble ^로 고치는 정도 였죠. 물론 고쳐야 하는 다른 구문들도 있었습니다. 다음이 ManWarp을 컴파일 하면서 나온 특유의 구문 에러 목록 입니다. C++/CLI 에 능통한 독자들에겐 진부해 보일 지도 모르니 CLI 전문가 이신 분들은 그냥 훑어 보시고 넘기시기 바랍니다.

• 관리 클래스들은 이제 __gc 또는 __value 대신 ref 또는 value로 선언 되어야 합니다. 일반적으로 모든 __managed 키워드들은 문맥에 더 맞는 키워드로 교체 되었습니다.

• Default 인덱서들은 이제 Item 대신 “default” 로 불립니다. 전엔 이랬던 것을:

x = m->Item[name];

이젠 이렇게 해야 합니다:

x = m->default[i];

이는 Regex 라이브러리의 MatchCollection에서처럼 복수의 인덱서들이 있을 때에도 작동 합니다.

MatchCollection* mc;
mc->default[0];       // int
mc->default["alpha"]; // string

• 관리 객체들은 이제 gcnew로 할당 되어야 합니다. 관리 객체를 할당 하는 곳에는 new를 gcnew로 변경 하시기 바랍니다.

• 어떤 변환 들은 더 이상 암시적이지 않습니다. 다음 코드를 보면:

// 네이티브 Entry
void Foo(LPCTSTR lpsz)
{
   // 관리 ctor 는 String을 받는다
   Mumble *m = new Mumble(lpsz); 
}

이전 Managed Extensions 에서는 컴파일러가 Mumble 을 생성 하기 위해 lpsz로 초기화 한 관리 String 객체를 암시적으로 생성 하였습니다. Visual Studio 2005 에서는 다음처럼 String을 명시적으로 할당 해주어야 합니다:

void Foo(LPCTSTR lpsz)
{
   Mumble ^m = gcnew Mumble(gcnew String(lpsz));
}

약간의 타이핑이 더 들어 가지만 이전 보다 좀더 의미가 명료 해졌습니다. 저는 언제 어디서 관리 힙에서 할당 하는지 알게 해주기 때문에 gcnew를 좋아 합니다. 암시적 변환은 코드를 단순하고 깨끗하게 보이게 하지만, 경우에 따라서는 오해를 살 수 있을 정도로 간결하기 때문입니다. C++는 상대적으로 low-level 언어에 속하며(전 이점을 좋은 점이라 생각 합니다.) 따라서 코드 뒷면에서 많은 일을 수행 하게 하는 것 보다 눈에 직접 보이게 하는 것이 좋습니다. RegexWrap에서 여기 저기서 String을 생성 하기 때문에 전 타이핑을 덜어주기 위해 다음의 매크로를 작성 했습니다:

#define S(s) (gcnew String(s))

S“Hello, world.” 에서처럼 관리 string의 S modifier처럼 닮아 보이게 만들어 보았습니다. 따라서 이젠 다음처럼 쓸 수 있습니다:

Mumble ^m = gcnew Mumble(S(lpsz));

C++/CLI 는 관리 배열의 구문이 새롭게 바뀌었습니다. 아래의 선언 대신

ManagedType* myarray[];

이젠 이렇게 작성하셔야 합니다:

array <ManagedType^>^ myarray;

전 두 번째 ^ 때문에 처음엔 약간 의아해 했었습니다. 그 것을 빼고 컴파일 하면 “error C3149: 여기에 이 형식을 사용하려면 최상위 '^'이(가) 있어야 합니다.”라는 약간은 애매한 에러가 나옵니다(최상위 뭐??). 그러나 규칙을 이해 하시면 당연히 나야 할 에러죠. 컴파일러는 이 배열이 “array” 키워드의 효능에 의해 관리 된다는 것을 아는데도 왜 최상위 hat이 필요 한지는 저도 확실히 는 잘 모르겠습니다. 그러나 확실한 것은 언어를 만들어 낸 분들이 그렇게 할만한 이유가 있었을 것이고 이 또 말이 되긴 한다는 것이죠. 관리되는 것들은 hat을 갖습니다. 기본 형의 관리 배열에서도 최상위 hat 이 필요 합니다. 예를 들어:

// int 형 관리 배열
array<int>^ foo;

• Count 대신 Length를 이용해 배열의 길이를 얻습니다.

• 관리 NULL 포인터에 대한 검사를 해야 한다면 NULL 대신 nullptr을 사용합니다.

• 템플릿은 관리 클래스와 사용될 때 더 잘 작동 합니다. 이 것이 C++/CLI를 사용해야 하는 가장 중요한 이유 중에 하나 입니다. 관리 클래스와 네이티브 클래스들은 각자 자신만의 구문을 갖게 되고 (overload 된 *를 공유하는 대신) 템플릿 생성자는 이를 쉽게 구분 할 수 있기 때문입니다.

여기서 제가 언급 하지 않은 구문 변화들이 더 있습니다. 이들에 대해선 여러분들도 자연히 알게 되겠죠. 이에 대한 개요로 Stan Lippman이 쓴 "Hello C++/CLI"를 보시는 것을 권해 드립니다. MSDN Magazine의 특별 Visual Studio 2005 판에 있습니다(msdn.microsoft.com/msdnmag/issues/06/00/PureC (영문)). 이 글과 Stan의 다른 기사 "A Baker's Dozen: Thirteen Things You Should Know Before Porting Your Visual C++ .NET Programs to Visual Studio 2005" (msdn.microsoft.com/library/en-us/dnvs05/html/BakerDozen.asp (영문))도 추천 해드립니다.

새로운 구문 때문에 너무 겁 먹지는 마시고요. * 를 ^ 로 /clr:oldSyntac를 /clr로 바꾸기만 하니 나머지는 컴파일러 에러 고치는 수준 이였습니다. ManWrap이 컴파일러를 통과 하고 나니 아무런 문제 없이 작동 하더군요. Redmond 사람들은 이에 대해 자랑스러워 할 만 합니다. 컴파일러가 코드의 정확함을 보장 할 수 있다면 그 보다 좋은 것이 있겠습니까? ^ 로의 변환이 너무 쉽게 끝나 너무 싱글벙글 한 나머지 GCHANDLE을 MANHANDLE로 바꿀까 까지 생각 했지만. 안 하기로 했습니다.


페이지 맨 위로페이지 맨 위로

두 가지 작은 불평

전체적으로 Visual Studio .NET 2003에서 Visual Studio 2005로의 이동은 큰 문제 없이 진행 되었습니다. 전 Emacs 같은 에디터 이외에는 거들떠 보지도 않는 텍스트 해커 이기 때문에 IDE 에 대해서는 크게 말씀 드릴 것이 없군요. 그러나 Visual Studio 2005에 대해 두 가지 불평이 있습니다. 우선 첫 번째로 “내 문서” 폴더를 제가 필요하지도 않고 쓰지도 않을 폴더로 더럽히더군요. 이것 저것 뒤지다 보니 이 폴더를 다른 곳으로 옮길 수 있는 레지트스리 키를 찾아 대부분의 폴더들을 제 눈에 안 띄는 TEMP 디렉터리로 옮길 수 있습니다. 전 제 컴퓨터의 폴더를 정리 하는데 상당한 노력을 드리는 지라 어떤 권위적인 프로그램이 제 하드디스크를 맘대로 고쳐 버리는 것이 싫더군요. 그래서 경고합니다: 만약 여러분의 프로그램이 폴더를 필요로 한다면 그 폴더들을 어디에 만들지 사용자들이 직접 선택 하게 하십시오.

제 다른 불만은 Visual Studio 2005가 더 이상 sound schemes 을 지원 하지 않는 다는 것입니다. 저도 시끄러운 프로그램을 좋아라 하진 않습니다만 이런 경우엔 유용하더군요. Visual Studio 2003에서는 빌드를 시작시킨 후 다른 창에서 작업을 하러 갑니다. 컴파일이 끝났을 때 나는 소리에 따라 컴파일이 성공 했는지 실패 했는지 바로 알 수 있었으나 Visual Studio 2005 에서는 결과 창을 읽어 봐야 알 수 있죠. 별로 재미 없는 일 중에 하나가 결과 창을 읽어 보는 것 입니다. 경고 하나 더 갑니다: 절대 기존의 기능을 제거 하지 마십시오.

이 두 개의 작은 불만과 /NOENTRY 에러를 제외 하고는 Visual Studio 2005로 업그레이드 하기가 상당히 쉬웠습니다. 아직 업그레이드 하지 않으셨다면 바로 해보세요. 혼합/관리 assembly를 작성 하신다면 더더욱 추천 해드립니다. 새 구문이 더 좋습니다. 물론 어떤 변화에서든 약간의 수정은 필요 합니다. 그러나 한번 적응 되신다면 이보다 좋을 수 없죠.

ManWrap은 MSDN Magazine 웹사이트에서 받으실 수 있습니다. 해당 다운로드는 세 버전으로 구성 되어 있으며 Visual Studio .NET 2003 버전, Visual Studio 2005 버전 용의 이전 C++/CLI 구문을 사용한 버전과 새 C++/CLI 구문을 사용한 버전을 제공 합니다. 즐거운 프로그래밍 하세요~!