VC6(Visual Studio 6.0에 들어있는 VC++)에서는 유니코드 문자(wchar_t)를 unsigned short로 처리하고,
VC8(Visual Studio .NET 2005에 들어있는 VC++)에서는 native type으로 처리한다.
그래서 VC6으로 제작된 유니코드 문자열을 다루는 DLL을 VC8에서 사용할 때는 Link에러가 나기 쉽상이다.
// VC6의 DLL 함수 선언
TEST_API const wchar_t* fnTest_wchar(void);
// VC8에서 VC6 DLL 사용
const wchar_t* text = fnTest_wchar();
코드상에서는 아무 문제가 없다.
하지만 VC8에서 컴파일해보면 아래와 같이 링크 에러가 난다.
error LNK2001: "__declspec(dllimport) wchar_t const * __cdecl fnTest_wchar(void)" (__imp_?fnTest_wchar@@YAPB_WXZ) 외부 기호를 확인할 수 없습니다.
VC6은 컴파일과 동시에 wchar_t를 unsigned short로 바꿔 버렸는데, VC8은 링크할 때 wchar_t의 함수를 찾기 때문에 찾을 수가 없어서 오류가 발생하는 것이다.
이런 문제는 클래스를 링크할 때 더욱 심각해진다.
// VC6 DLL의 클래스 선언
class TEST_API cStrTool
{
protected:
wchar_t* m_pBuff;
public:
cStrTool(const wchar_t*);
...
const wchar_t* getText(void) const;
};
// VC8에서 VC6 DLL의 클래스 사용
cStrTool use = new cStrTool(L"test string");
const wchar_t* output = use.getText();
역시나 코드상으로는 전혀 문제가 없지만 생성과 사용 둘 다 링크 에러를 발생한다.
그래서 VC6쪽에서 약간의 수정을 가해주어야 한다.
// VC6 DLL의 클래스를 수정
class TEST_API cStrTool
{
protected:
wchar_t* m_pBuff;
public:
cStrTool(const void*); // <-- void*로 받아서 생성하도록 수정
...
const wchar_t* getText(void) const;
};
// 구현은 형변환을 한 후 수행하도록 수정
cStrTool::cStrTool(const void* init_)
{
const wchar_t* init = static_cast<const wchar_t*>(init_);
...
}
이제 VC6과 VC8에서 아무 문제없이 생성할 수 있다.
하지만 여전히 getText 메소드는 링크 에러를 발생시킨다.
게다가 본의 아니게 유니코드 문자열이 아닌 다른 종류의 포인터를 넘겨서 오류를 발생시킬 수도 있다.
문제를 일반적으로 해결하기 위해 Visual C++의 wchar_t에 대해 좀 더 자세한 정보를 찾아보았다.
VC6은 wchar.h 헤더에 아래와 같이 선언되어 있다.
#define _WCHAR_T_DEFINED
typedef unsigned short wchar_t;
그리고 VC8은 컴파일러 자체에 내장형으로 선언되어 있으며, 아래와 같은 매크로를 포함하고 있다.
내장형 type : wchar_t, __wchar_t
#define _WCHAR_T_DEFINED
#define _NATIVE_WCHAR_T_DEFINED
불행하게도..
코드상으로 완전하게 호환되게 하기 위해서는 VC6 DLL을 다소 수정하고 재컴파일해야 한다.
아래와 같이 사용되는 클래스를 확장하여 연결하는 방식으로 고쳐서 VC6에서 사용할 때도 VC8에서 사용할 때도 문제가 없도록 만들 수 있다.
그리고 VC6이던 VC8이던 다음과 같이 그냥 사용하면 된다.

VC8(Visual Studio .NET 2005에 들어있는 VC++)에서는 native type으로 처리한다.
그래서 VC6으로 제작된 유니코드 문자열을 다루는 DLL을 VC8에서 사용할 때는 Link에러가 나기 쉽상이다.
// VC6의 DLL 함수 선언
TEST_API const wchar_t* fnTest_wchar(void);
// VC8에서 VC6 DLL 사용
const wchar_t* text = fnTest_wchar();
코드상에서는 아무 문제가 없다.
하지만 VC8에서 컴파일해보면 아래와 같이 링크 에러가 난다.
error LNK2001: "__declspec(dllimport) wchar_t const * __cdecl fnTest_wchar(void)" (__imp_?fnTest_wchar@@YAPB_WXZ) 외부 기호를 확인할 수 없습니다.
VC6은 컴파일과 동시에 wchar_t를 unsigned short로 바꿔 버렸는데, VC8은 링크할 때 wchar_t의 함수를 찾기 때문에 찾을 수가 없어서 오류가 발생하는 것이다.
이런 문제는 클래스를 링크할 때 더욱 심각해진다.
// VC6 DLL의 클래스 선언
class TEST_API cStrTool
{
protected:
wchar_t* m_pBuff;
public:
cStrTool(const wchar_t*);
...
const wchar_t* getText(void) const;
};
// VC8에서 VC6 DLL의 클래스 사용
cStrTool use = new cStrTool(L"test string");
const wchar_t* output = use.getText();
역시나 코드상으로는 전혀 문제가 없지만 생성과 사용 둘 다 링크 에러를 발생한다.
그래서 VC6쪽에서 약간의 수정을 가해주어야 한다.
// VC6 DLL의 클래스를 수정
class TEST_API cStrTool
{
protected:
wchar_t* m_pBuff;
public:
cStrTool(const void*); // <-- void*로 받아서 생성하도록 수정
...
const wchar_t* getText(void) const;
};
// 구현은 형변환을 한 후 수행하도록 수정
cStrTool::cStrTool(const void* init_)
{
const wchar_t* init = static_cast<const wchar_t*>(init_);
...
}
이제 VC6과 VC8에서 아무 문제없이 생성할 수 있다.
하지만 여전히 getText 메소드는 링크 에러를 발생시킨다.
게다가 본의 아니게 유니코드 문자열이 아닌 다른 종류의 포인터를 넘겨서 오류를 발생시킬 수도 있다.
문제를 일반적으로 해결하기 위해 Visual C++의 wchar_t에 대해 좀 더 자세한 정보를 찾아보았다.
VC6은 wchar.h 헤더에 아래와 같이 선언되어 있다.
#define _WCHAR_T_DEFINED
typedef unsigned short wchar_t;
그리고 VC8은 컴파일러 자체에 내장형으로 선언되어 있으며, 아래와 같은 매크로를 포함하고 있다.
내장형 type : wchar_t, __wchar_t
#define _WCHAR_T_DEFINED
#define _NATIVE_WCHAR_T_DEFINED
불행하게도..
코드상으로 완전하게 호환되게 하기 위해서는 VC6 DLL을 다소 수정하고 재컴파일해야 한다.
아래와 같이 사용되는 클래스를 확장하여 연결하는 방식으로 고쳐서 VC6에서 사용할 때도 VC8에서 사용할 때도 문제가 없도록 만들 수 있다.
// 앞으로 DLL 내부의 모든 유니코드 문자는 아래의 wchar을 사용한다.
#if defined(_NATIVE_WCHAR_T_DEFINED)
typedef unsigned short wchar;
#elif defined(_WCHAR_T_DEFINED)
typedef wchar_t wchar;
#else
typedef unsigned short wchar;
#endif
// VC6 DLL에서 제공될 클래스
class TEST_API cStrTool_
{
protected:
wchar* m_pBuff;
public:
cStrTool_();
cStrTool_(const wchar* init);
virtual ~cStrTool_();
int getLength(void) const;
const wchar* getText(void) const;
};
#if !defined(_NATIVE_WCHAR_T_DEFINED)
// VC6에서 사용할 때는 그냥 바로 연결해서 사용
typedef cStrTool_ cStrTool;
#else
// VC8에서 사용할 때는 상속 받아서 변환하기 위한 클래스 선언해서 사용
class cStrTool : public cStrTool_
{
public:
// 모든 종류의 생성자를 다 연결해줘야 똑같이 사용할 수 있다.
cStrTool() {}
cStrTool(const wchar_t* init) : cStrTool_( (const wchar*)init ) {}
// 메서드는 wchar에 관련된 것만 재정의해줘도 된다.
const wchar_t* getText(void) const
{ return (const wchar_t*)__super::getText(); }
};
#endif
그리고 VC6이던 VC8이던 다음과 같이 그냥 사용하면 된다.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <windows.h>
#include "vc6_dll.h"
#pragma comment(lib, "vc6_dll")
int main(int argc, char* argv[])
{
cStrTool str1(L"문자열 test");
const wchar_t* output = str1.getText();
cout << "str1 length: " << str1.getLength() << endl;
MessageBoxW(NULL, output, L"DLL Link test : wchar_t", MB_OK);
cStrTool str2;
cout << "str2 length: " << str2.getLength() << endl;
MessageBoxW(NULL, str2.getText(), L"DLL Link test : wchar_t", MB_OK);
return 0;
}
예제 프로젝트
'스킬북 > 코드 조각' 카테고리의 다른 글
| VC6과 VC8에서 wchar_t가 호환되게 만들기 (0) | 2009/10/16 |
|---|---|
| C++에서 상속이 안되는 클래스 만들기 (0) | 2009/10/16 |
| 자바스크립트로 만든 한글IME (0) | 2009/09/01 |
| 소스에서 유니코드 시스템 판단하기 (0) | 2007/11/28 |


test_wchar.zip
|꼬마늑대|


댓글을 달아 주세요