성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
2006/06/30일자로 MSDN 다운로드 센터에 간단한 유틸리티 함수를 제공하는 "Microsoft National Language Support Downlevel APIs 1.0"이 올라왔습니다.<br /> <br /> 다음의 기사를 참고하십시오.<br /> Microsoft National Language Support Downlevel APIs 1.0 <br /> ; <a target="_blank" href="/2/1/353">http://www.sysnet.pe.kr/2/1/353</a><br /> <br /> 그런데, 잠시 테스트해 볼려고 VS.NET 2005에서 예제로 MFC Dialog 유형의 프로젝트를 만들어서 다음과 같은 코드를 컴파일 해보았습니다.<br /> <br /> <pre class="code"> #include "..\include\Nlsdl.h" #pragma comment( lib, "..\\lib\\x86\\Nlsdl.lib" ) LCID lcid = DownlevelLocaleNameToLCID( L"ko-KR", DOWNLEVEL_LOCALE_NAME ); // lcid == 1024 LCID parentLcid = DownlevelGetParentLocaleLCID( lcid ); // lcid == 18 wchar_t name[ 1024 ] = { 0 }; DownlevelLCIDToLocaleName( lcid, name, 1024, 0 ); // name == "ko-KR" wchar_t parentName[ 1024 ] = { 0 }; DownlevelGetParentLocaleName( lcid, parentName, 1024 ); // parentName == "ko" </pre> <br /> 그런데 ^^; 이게 웬일입니까?<br /> 다음과 같은 오류가 나는 것입니다.<br /> <br /> <pre class="code"> TestDlgDlg.obj : error LNK2019: unresolved external symbol "int __stdcall DownlevelGetParentLocaleName(unsigned long,wchar_t *,int)" (?DownlevelGetParentLocaleName@@YGHKPA_WH@Z) referenced in function "protected: virtual int __thiscall CTestDlgDlg::OnInitDialog(void)" (?OnInitDialog@CTestDlgDlg@@MAEHXZ) TestDlgDlg.obj : error LNK2019: unresolved external symbol "int __stdcall DownlevelLCIDToLocaleName(unsigned long,wchar_t *,int,unsigned long)" (?DownlevelLCIDToLocaleName@@YGHKPA_WHK@Z) referenced in function "protected: virtual int __thiscall CTestDlgDlg::OnInitDialog(void)" (?OnInitDialog@CTestDlgDlg@@MAEHXZ) TestDlgDlg.obj : error LNK2019: unresolved external symbol "unsigned long __stdcall DownlevelLocaleNameToLCID(wchar_t const *,unsigned long)" (?DownlevelLocaleNameToLCID@@YGKPB_WK@Z) referenced in function "protected: virtual int __thiscall CTestDlgDlg::OnInitDialog(void)" (?OnInitDialog@CTestDlgDlg@@MAEHXZ) C:\Microsoft NLS Downlevel APIs\TestDlg\Debug\TestDlg.exe : fatal error LNK1120: 3 unresolved externals </pre> <br /> 분명히, Nlsdl.h 파일에 정의된 대로 정확하게 사용을 했는데 위와 같은 에러가 나는 것입니다.<br /> 오호... Microsoft가 뭔가 실수를 했을까요?<br /> <br /> 우선, Nlsdl.h 파일에 있는 정의 대로 LIB 파일에 있는지 검사를 해야 했습니다. 여러 가지 툴을 사용해 볼 수 있겠지만, 단순히 export 된 함수에 대한 signature만 확인하면 되기 때문에 그냥 LIB 파일을 VS.NET IDE로 끌어다 놓아서 binary 형식으로 보았습니다.<br /> <br /> 아래와 같이 export 되어 있는 것을 확인해 볼 수 있는데요.<br /> <pre class="code"> CRIPTOR_Nlsdl__NULL_IMPORT_DESCRIPTOR Nlsdl_NULL_THUNK_DATA ?DownlevelLocaleNameToLCID@@YGKPBGK@Z__imp_ ?DownlevelLocaleNameToLCID@@YGKPBGK@Z ?DownlevelLCIDToLocaleName@@YGHKPAGHK@Z__imp_ ?DownlevelLCIDToLocaleName@@YGHKPAGHK@Z ?DownlevelGetParentLocaleLCID@@YGKK@Z__imp_ ?DownlevelGetParentLocaleLCID@@YGKK@Z ?DownlevelGetParentLocaleName@@YGHKPAGH@Z__imp_ ?DownlevelGetParentLocaleName@@YGHKPAGH@Z </pre> <br /> 그런데, 한 가지 이상한 점이 있습니다. 함수 이름 이후의 "@@" 문자뒤에 오는 signature 값이 VS.NET 컴파일 화면에 있는 값과 일치하지 않았습니다.<br /> <br /> <pre class="code"> 컴파일 오류 : ?DownlevelLocaleNameToLCID@@YGKPB_WK@Z LIB export : ?DownlevelLocaleNameToLCID@@YGKPBGK@Z </pre> <br /> 자, 그럼 위의 signature를 우리가 읽기 편하게 변환을 하면 될 텐데요. 이를 위해 VC++ 툴에 있는 "undname.exe"를 이용해 보겠습니다. (자세한 사항은 <a target="_blank" href="/2/0/151">http://www.sysnet.pe.kr/2/0/151</a>을 참조하십시오.)<br /> <br /> 결국, 다음과 같은 결과를 얻어냈습니다.<br /> <br /> <pre class="code"> 컴파일 오류 : ?DownlevelLocaleNameToLCID@@YGKPB_WK@Z - unsigned long __stdcall DownlevelLocaleNameToLCID(wchar_t const *,unsigned long) LIB export : ?DownlevelLocaleNameToLCID@@YGKPBGK@Z - unsigned long __stdcall DownlevelLocaleNameToLCID(unsigned short const *, unsigned long)" </pre> <br /> 확실히 다르군요. ^^ 그런데, Nlsdl.h 파일에는 해당 함수에 대해서 다음과 같이 선언되어져 있습니다.<br /> <br /> <pre class="code"> LCID WINAPI DownlevelLocaleNameToLCID( __in LPCWSTR lpName, __in DWORD dwFlags); LPCWSTR : CONST WCHAR * WCHAR : wchar_t </pre> <br /> 어쨌든, 문제 파악은 제대로 된 것 같습니다. 이제 이러한 불일치를 해결하기 위해서 2가지 방식으로 풀어볼 수 있습니다.<br /> <br /> 1. 헤더 파일 및 소스의 강제 포인터 형변환<br /> 예를 들면 더욱 설명이 빠르겠지요.<br /> <br /> <pre class="code"> === 헤더 파일에 다음의 선언 추가 === LCID WINAPI DownlevelLocaleNameToLCID( __in unsigned short const *lpName, __in DWORD dwFlags); === 소스 파일에서의 강제 형변환 === LCID lcid = DownlevelLocaleNameToLCID( (unsigned short*)L"ko-KR", DOWNLEVEL_LOCALE_NAME ); </pre> <br /> 나머지 2개의 함수에 대해서도 위와 같은 방법으로 처리해 줄 수 있습니다.<br /> <br /> 2. 컴파일러 스위치 사용<br /> 프로젝트 대화 상자에서 아래와 같이 "Treat wchar_t as Build-in Type"을 "No (/Zc:wchar_t-)"로 주어서 해결할 수 있습니다. 이렇게 해주면, wchar_t는 하나의 내장 형식이 아닌, typedef을 통해서 unsigned short로 바뀌게 됩니다. <br /> <img alt="wchar_t 처리" src="/SysWebRes/bbs/vs_net_project_prop_c_cpp_lang_wchar_t.png" /> <hr /> 첨부된 파일은 제가 사용한 간단한 예제 프로젝트입니다. 4개의 함수 사용 및 unsigned short로 변환된 헤더 정의를 포함하고 있습니다. Nlsdl.lib와 Nlsdl.dll을 포함시켜 두었는데 모두 x86 버전입니다. iax6/x64 버전으로 테스트하시려면 "Microsoft National Language Support Downlevel APIs 1.0"을 직접 다운로드하면 그에 대한 재배포 파일을 구하실 수 있습니다.
첨부파일
스팸 방지용 인증 번호
1049
(왼쪽의 숫자를 입력해야 합니다.)