반응형

Visual Studio에서 "First Chance Exception"이 발생할 때가 있다.
이건 또 뭔소리여... 첫번째 기회 예외??

대략 인터넷을 뒤져 보니 이런 뜻이더군... 맞게 이해했나 모르겠다.


  1. 어플리케이션이 디버그 모드로 실행될 때, 디버거는 모든 Exception 발생을 알아차릴 수 있다. (이 Exception이 Handle되든 아니든..) 이 단계를 "First Chance"라 한다.
  2. 만약 이 Exception이 적절하게 Handling되었다면 실제로 응용프로그램은 문제를 일으키거나 종료(Crash)되지 않을 것이다. 하지만, 디버거의 설정에 따라서 적절히 Handling된 Exception에 대해서 조차도 반응 (실행중지 및 오류메시지 발생)하도록 설정할 수 있는데, 이 것을 First-Chance Exception이라 한다.
  3. First-Chance Exception이 발생했으나, 실제 Release 실행시에는 별 문제가 생기지 않는다면 이것은 Exception이 발생했으나 내부적으로 Handling되었음을 의미한다. 따라서 이러한 경우 Debug모드에서 Exception이 발생했다 하더라도 큰 문제가 되지 않는다. 대부분 WinAPI 내부에서 처리되는 경우가 많다.
  4. 단, 이 Exception이 적절하게 Handle되지 않은 경우, Release 실행시에 실제로 오류가 발생하고 프로그램이 종료되게 된다. (Second Chance Exception) 이 단계라면 당연히 적절한 조치를 해주어야 한다.
    http://blogs.msdn.com/davidklinems/archive/2005/07/12/438061.aspx

    Visual Studio에서도 First-Chance Exception을 Handling하도록 (혹은 하지 않도록) 설정할 수 있다. 간혹 디버그 모드에서 디버그 실행을 시키자마자 First-Chance란 놈이 발생해서 아예 디버그 시작을 못하는 경우가 있는데 이럴 땐 First-Chance Exception을 Handle하지 않도록 설정해 주어야 한다.
    http://blog.naver.com/li0129?Redirect=Log&logNo=60018574262
반응형
반응형
프로그램이 실행되는 모습
CLR(The Common Language Runtime)는 MSIL(Intermediate Language)를 실행함
Code는 MSIL로 compile됩

자바의 JRE와 class를 생각하면 될 것 같음

* assembly : 어떤 기능을 하는 하나의 모듈을 의미
* manifest : assembly가 동작하는 데 어떤 파일이 필요한 지 가지는 목록
* program : 하나 혹은 여러개의 assembly로 구성

* CLR은 assembly로부터 그것이 어떤 보안/권한 범위를 가지는지, 사용버전은 어디서부터 어디까지인지를 보고 실행하게 됨

* DLL지옥의 관점에서 Private Assembly, Shared Assembly
   http://hoons.kr/Board.aspx?Name=cshaptip&Mode=2&BoardIdx=406&Key=&Value=

어셈블리는 DLL 지옥을 해결하였다는데…
앞에서 언급했듯이 직접 작성한 대부분의 어셈블리는 private이다. 그러므로 각 어플리케이션은 자체적으로 설치된 폴더에 있는 어셈블리를 참조한다. Private형식에서는 같은 이름의 여러버전이 있다하더라도 충돌을 피할 수 있다.

이해를 돕기위해 한가지 예를 들어본다.
1. Assembly1이라는 이름의 어셈블리를 제작한다.
2. Assembly1을 이용하는 Client1이라는 어플리케이션을 만든다.
3. 클라이언트 프로그램을 c:\MyApp1이라는 폴더에 설치하고, Assembly1도 이 폴더에 설치한다.
4. 며칠이 지난 후에 Assembly1이 수정이 되었다고 가정한다.
5. 수정된 Assembly1을 이용한 클라이언트 어플리케이션(Client2)를 제작한다.
6. 이 클라이언트 프로그램을 c:\MyApp2라는 폴더에 설치하고 Assembly1도 이 폴더에 설치한다.
7. 각각의 프로그램은 같은 이름의 Assembly1이라는 어셈블리를 사용하고 있지만, 버전은 서로 다른 것

* 데브피아에서 퍼옴 왕성현 님의 강좌입니다.


*private assembly를 shared assembly로 만드는 과정
반응형
반응형
CRichEditCtrl에서 GetLine(?) 문제점 한번 정리해보기
반응형
반응형
IMPLEMENT_DYNAMIC
DECLARE_DYNAMIC
에 대해 알아보기

static library로 compile할 때는 위 매크로가 있으면 compile안됨

반응형
반응형
CWinAppEx VS2008 Sp1설치 후 
MFC project를 생성하면 Wizard가 생성하는 code중 약간 바뀐 부분이 있습니다.

App는 CWinAppEx(기존에는 CWinApp를 상속)를 상속받고
stdafx.h에 #include <afxcontrolbars.h>가 추가됩니다.

그런데 문제는 VS2008 sp1에서 생성한 project를
VS2008 sp1이 설치되지 않은 computer에서 compile할 경우
Error가 발생한다는 점입니다.
stxafx.h에 afxcontrolbars.h를 찾을 수 없어 Compile Error가 발생합니다.

이 때는 간단히 수정할 수 있습니다.
1. CWinAppEx를 CWinApp로 고치고
2. #include <afxcontrolbars.h>를 삭제해줍니다.

그런데 의문이 드는 것은
MSDN에서 CWinAppEx를 찾아보니 afxwinappex.h를 필요로 하고 있습니다.
왜 VS2008가 afxcontrolbars.h를 include했는지 궁금하네요

한번 찾아봐야겠네요
반응형

'Tech > 프로그래밍' 카테고리의 다른 글

CRichEditCtrl에서 GetLine(?) 문제점  (0) 2008.12.30
IMPLEMENT_DYNAMIC, DECLARE_DYNAMIC 의문  (0) 2008.12.30
VB6, VB.NET, VS.NET 과 COM  (0) 2008.12.29
CSerialPort 사용해보자 Free API  (0) 2008.12.29
Win32 문자열  (0) 2008.12.11
반응형
자작프로그램 파일명변환기

프로그램 : 파일명변환기.zip
소스(VC++2008): 
특정 폴더에 있는 파일들의 이름을 일괄 변환해 주는 프로그램입니다.

인터넷에서 파일을 다운받다 보면 가끔 파일명에 불필요한 문자가 들어가 있는 경우가 있습니다.

예를들면 "file%20two%20file.bmp"이런 식의 파일이 많이 있고, 
%20자리에 스페이스가 들어가길 원한다면 어떻게 하시겠습니까?
파일 하나하나마다 다 F2를 누르고 rename을 하게 되는 경우가 많을텐데요
이 때 파일명변환기를 이용해서 폴더를 선택하고
Find What 에 "%20", Replace with에 " " 이렇게 설정하고 convert버튼을 누르면
해당 폴더에 있는 파일들의 이름을 모두 변환할 수 있습니다.

또 하나의 예를 들면,
음악파일의 경우 파일명에 앨범이름이 있어서 너무 길 경우 일괄로 앨범이름을 지우고 싶다면
Find What 에 앨범이름,  Replace with에 아무것도 안치면 
앨범이름이 일괄 삭제될 것입니다.

ps. 날림으로 만든 프로그램이라 버그가 있을 수도 있습니다. 

ScreenShot:
반응형
반응형
전병선 왜 COM인가 49page에서
반응형
반응형
반응형
반응형
출처 : http://blog.naver.com/seunghyni/110014783397

“ Win32 문자열 ”
ColdFloor  |  2006/09/30 20:09  |  개발/Etc
C++ 문법을 배우고 Win32 프로그래밍을 시작 할 때,
가장 어려운 것중 하나는 엄청난 수의 Win32 DataType들과 생소한 Macro들이었다.

생전 처음 보는 그 녀석들을 이해하려면 상당한 범위를 돌아다녀야 했고,  
이해하기 보다는 대충 이렇게 쓰면 오류없이 컴파일 되더라 정도로 사용하는게 현실이었다.

그 중에서도 문자열부분은 꽤나 두통을 유발하는 것들인데 유니코드고 멀티바이트고 신경안쓰고 대충 만들고 싶어도 어디에서건 꼭 발목을 잡히게 된다.
그렇다고 아주 해결이 안되는것도 아닌데, 그 때 그때 급하게 땜질식으로 코딩을 하다보니
문자열관련 부분에 대해서는 계속 골치가 아플수밖에 없었다.

싱글바이트캐릭터(SBCS : Single-byte character set),
멀티바이트캐릭터(MBCS : Multi-byte character set),
유니코드 ( Unicode characters ), 와이드 캐릭터 ( Wide characters )로 시작한 문자코드들부터 시작해서
wchar_t, char, TCHAR, BSTR, _bstr_t 등의 관련 데이터 타입들.. L, _T()의 매크로들
거기에 기반한 LPSTR, LPCSTR, LPWSTR, LPTSTR, LPCTSTR등의 데이터 타입들에 대해 간략히 보자


지금 정리하는 내용들은 기본적으로 코드프로젝트의 아티클에 대한 정리 요약본이다.
원본 아티클 링크는 다음과 같다.
The Complete Guide to C++ Strings, Part I - Win32 Character Encodings
The Complete Guide to C++ Strings, Part II - String Wrapper Classes

문자 Encoding 방식

싱글바이트캐릭터
SBCS (Single-byte character set)
한 문자 표현에 1Byte를 사용하는 방식이다.
예로 ASCII 코드가 있으며, 한글이나 일본어표현은 불가능하다.


멀티바이트캐릭터
MBCS (Multi-byte character set)
한 문자 표현에 1Byte 이상을 사용하는 방식으로 Windows에서 MBCS에는 딱 두종류가 있다.
SBCS와 DBCS( Double-byte character set) 결국 많아봐야 최대 2Byte라는 얘기다.
한글이나 일본어가 처리되는 기본 방식이다.
즉,

printf( “안녕하삼” );
std::cout<<”배고프네”;
 

  이렇게 코드를 작성하고 컴파일해서 실행했을 때, 이게 바로 MBCS를 사용한 것이 된다.


유니코드
Unicode (wide characters)
유니코드는 모든캐릭터들을 2Byte로 표현하는 표준 Encoding 방식이다.
즉 구조적으로 한 글자가 1Byte, 2Byte, 3Byte 어느것이든 가능한 MBSC와 구분된다.


> C++에서 종료 문자열
SBCS/MBCS
코드상 별도의 구분없이 사용하므로, 기본 C-Style 문자열에서 처럼 ‘\0’ 한번
즉, 0Byte 값이 문자열의 끝을 표현.

Unicode
모든 캐릭터를 2Byte로 Encoding 하므로, 종료 문자열도 ‘\0’이 두번 위치.
즉, 0Byte 2개가 문자열의 끝을 표현.



> Data type
SBCS/MBCS
char : 일반적인 1Byte 문자형 char를 사용해서 표현

Unicode
wchar_t : wide-character 타입 문자형을 사용하며, 값 지정시 prefix L 을 사용한다.
wchar_t wch = L’즐’; //2Bytes
wchar_t* wstr = L”Hi”; // 6Bytes



> 문자열 처리 함수
SBCS
strcpy(), sprintf(), atol()등의 함수

MBCS
_mbscpy()처럼 _mbsXXX()식으로 이름이 붙은 mbcs전용 함수를 사용해야 한다.

Unicode
wcsXXX()식의 함수나 swprintf(), _wtol()처럼 앞에 w등이 붙은 unicode전용 함수를 사용해야 한다.



Win32 API에서 MBCS와 Unicode사용
windows에서는 두종류의 api를 제공한다.
SetWindowTextA() / SetWindowTextW()처럼 ~A()함수는 MBCS용 그리고 ~W()함수는 Unicode용이다.
실제로 코딩 할 때에는 직접 문자열 Encoding에 맞추어 호출하지 않고 Macro를 사용해서 전처리기에 따라 처리를 하게 된다.

즉,


#ifdef UNICODE

   #define SetWindowText SetWindowTextW
#else
   #define SetWindowText SetWindowTextA
#endif



이런식이다.

문제는 이렇게 전처리기를 통해 컴파일시에 적용되기 때문에 발생하는데,
실제로는 코드에 사용된 문자값들을 지정하는 코드들까지 바뀌어야 한다는 것이다.
HWND hwnd = GetSomeWindowHandle();

#ifdef UNICODE

   wchar_t szNewText[] = L"we love Bob!";
#else
   char szNewText[] = "we love Bob!";
#endif

  SetWindowText ( hwnd, szNewText );


이렇게 리터럴값을 지정할 때에도 Unicode경우 L prefix가 붙기 때문에 상당히 귀찮은 작업이 된다.
그리고 결국 이것을 해결하기 위해 몇가지가 더 추가될 수 밖에 없었던 것 같다.

그래서 해결책으로 나온것이 TCHAR 님이시다.
#ifdef UNICODE
   typedef wchar_t TCHAR;
#else
   typedef char TCHAR;
#endif

#ifdef UNICODE
   #define _T(x) L##x
#else
   #define _T(x) x
#endif

이렇게 매크로 되어있기 때문에 TCHAR 타입을 사용하면, 상황에 맞게 wchar_t / char로 구분되어 처리되고,
prefix L의 문제도 _T()를 사용해서 해결이 가능한것이다.
즉, TCHAR과 _T() 매크로를 사용해서 코드를 작성하면, 컴파일러의 옵션변경만으로 MBCS/Unicode 컴파일이 가능해진다.

거기에 더해서 문자열 처리 함수들의 경우들도 strrchr() / _mbsrchr() / wcsrchr()등으로 구분해서 사용하던 것을
_tcsrchr()식으로 _t가 붙은 함수들로 대체 할 수 있다.

이 함수 매크로들은 TCHAR.H에 정의 되어있는데,
http://msdn2.microsoft.com/en-us/library/tsbaswba.aspx 여기에서 확인가능하다.

즉, TCHAR은 Windows에서 MBCS/Unicode 호환코드를 작성하기 위해 사용하는것이다.

또 일반적으로 사용되는 문자열 관련 데이터타입은 다음과 같다.
WCHAR : wchar_t
LPSTR : char*
LPCSTR : const char*
LPWSTR : wchar_t*
LPCWSTR : const wchar_t*
LPTSTR : TCHAR*
LPCTSTR : const TCHAR*

..알고보면 아무것도 아니다; 더 해서.
OLECHAR : Unicode 문자 wchar_t
LPOLESTR : OLECHAR*
LPCOLESTR : const OLECHAR*

Prefix 경우에는
_T(x) : Unicode빌드일 때, L
OLESTR(x) : LPOLESTR 문자열을 지정하기위해 L
TEXT(x), _TEXT(x), __T(x) : _T(x)와 동일

COM/ATL/STL - BSTR과 VARIANT, string, CComBSTR
COM 관련 코드를 작성하려고 보면 여기서만 쓰이는 생소한 데이터 형들이 등장하는데, 그중 문자열관련해서 다음과 같은 것을
볼 수 있다.


BSTR
Pascal-Style(길이값 내장)과 C-Style(널종료문자)을 섞어 놓은 형식으로 기본 구조는 다음과 같다.
-    4Byte(길이정수) + 문자값(2Byte) + 종료문자( 0 2개 )
즉, 최초에 DWORD의 정수데이터가 붙고 그 뒤로 Unicode식의 2Byte Encoding 문자열이 붙는형식이다.
그러나 이 앞쪽의 정수 부분은 C++ 코드 작성시에는 없다고 생각해야 한다.
왜냐하면, typedef OLECHAR* BSTR; 로 선언 되어 있기 때문.
COM을 통해 데이터가 전송될 때 알아서 마샬링 되는 것 같다.
아무튼 실제로 BSTR은 WCHAR과 다름에도 불구하고 내부적으로 같은 형식으로 인식되기 때문에 주의를 해야한다.
함수에 인자로 넘길경우 컴파일 오류가 안지 않더라도 내부적으로 오류가 발생하기 쉽다.

게다가 BSTR 은 COM 라이브러리를 통해 마샬링 되어야 하기 때문에 메모리 관리를 다른 곳에서 해야한다.
즉, 사용할 때 메모리 할당과 해제를 명시적으로 API를 통해서 해야한다.
SysAllocString() : 메모리 할당시 사용
SysFreeString() : 메모리 해제시 사용
BSTR bstr = NULL;

bstr = SysAllocString ( L"Hi Bob!" );

if ( NULL == bstr )
  // out of memory error

// Use bstr here...

SysFreeString ( bstr );

이렇게 사용한다.


_bstr_t
BSTR데이터형을 사용하는게 귀찮은 사람들을 위한 BSTR Wrapper 클래스다.
BSTR대신 함수에 넘겨줄수는 없다 ? 가능하지만 상당히 제약적이다.
직접 내부 BSTR에 접근이 안돼기 때문에 함수에 BSTR대신 넘겨주기 위해서는 ATL에서 지원하는 CComBSTR클래스를
사용하면 된다.
다음과 같이 생성 및 문자열 encoding 변환을 할 수 있다.
// Constructing
_bstr_t bs1 = "char string"; & // construct from a LPCSTR
_bstr_t bs2 = L"wide char string"// construct from a LPCWSTR
//내부적으로 2Byte Unicode 형식이지만, char / wchar_t 양쪽에서 생성 할 수 있다.

_bstr_t bs3 = bs1;  // copy from another _bstr_t
_variant_t v = "Bob";
_bstr_t bs4 = v;  // construct from a _variant_t that has a string

// Extracting data
LPCSTR psz1 = bs1;  // automatically converts to MBCS string
LPCSTR psz2 = (LPCSTR) bs1;  // cast OK, same as previous line
LPCWSTR pwsz1 = bs1;  // returns the internal Unicode string
LPCWSTR pwsz2 = (LPCWSTR) bs1; // cast OK, same as previous line 변환된다!!
BSTR  bstr = bs1.copy();  // copies bs1, returns it as a BSTR

// ...
SysFreeString ( bstr )// 수동적으로 메모리를 해제해줘야 한다.




_variant_t
COM에서 사용되는 VARIANT의 wrapper 클래스다.
당연히 BSTR과 _bstr_t의 관계처럼 좀더 사용하기 용이하다.
기본적으로 VARIANT는 문자열외에 다양한 데이터를 저장하기 위한 구조체지만, 문자열을 저장할 경우 BSTR형식으로
저장이 된다.
_bstr_t와는 다르게 _variant_t는 VARIANT를 상속받은 클래스로 모든 함수에 VARIANT 대신 넘겨주는 것이 가능하다.
내부의 VARIANT는 감춰져있다.
// Constructing
_variant_t v1 = "char string";  // construct from a LPCSTR
_variant_t v2 = L"wide char string"// construct from a LPCWSTR
_bstr_t bs1 = "Bob";
_variant_t v3 = bs1;  // copy from a _bstr_t object

// Extracting data
_bstr_t bs2 = v1;  // extract BSTR from the VARIANT
_bstr_t bs3 = (_bstr_t) v1; // cast OK, same as previous line
위와 같이 _variant_t와 _bstr_t 사이에 전환이 용이 하다.



basic_string::string / basic_string::wstring
STL의 문자열 클래스 basic_string에는 MBSC/Unicode용으로 각각 string/ wstring이 존재 한다.
string은 char / wstring은 wchar_t를 저장하는데, TCHAR은 존재하지않는다.
TCHAR과 STL을 함께 사용하려면 간단히 다음처럼 직접 만들어주면된다.
// Specializations
typedef basic_string<TCHAR> tstring; // string of TCHARs 새로 정의 해준다.

// Constructing 이렇게 각각 생성할 수 있다.
string str = "char string";  // construct from a LPCSTR
wstring wstr = L"wide char string"// construct from a LPCWSTR
tstring tstr = _T("TCHAR string")// construct from a LPCTSTR

// Extracting data
// 값을 사용할 때에는 .c_str()을 통해 해당하는 원 데이터형으로 반환된다.
LPCSTR psz = str.c_str();  // read-only pointer to str's buffer
LPCWSTR pwsz = wstr.c_str()// read-only pointer to wstr's buffer
LPCTSTR ptsz = tstr.c_str()// read-only pointer to tstr's buffer
_bstr_t에 바로 할당하기 위해서는
_bstr_t bs1 = wstr.c_str(); 와 같은 식으로 내부 데이터 값을 받아오면 된다.



CComBSTR
ATL의 BSTR wrapper 클래스로 _bstr_t보다 좀더 유용한 기능들이 있다.
우선 COM함수에 BSTR대신 넘겨줄 수 있고, BSTR 메모리 관리를 자동으로 해준다.
내부에 MBCS 변환 기능은 없다.
문자열 변환에는 ATL 변환 Macro를 사용하면 된다. <- 매우 편리하다
// Constructing
CComBSTR bs1 = "char string";  // construct from a LPCSTR
CComBSTR bs2 = L"wide char string"// construct from a LPCWSTR
CComBSTR bs3 = bs1;  // copy from another CComBSTR
CComBSTR bs4;

bs4.LoadString ( IDS_SOME_STR )// load string from string table

// Extracting data
BSTR bstr1 = bs1;  // returns internal BSTR, but don't modify it!
BSTR bstr2 = (BSTR) bs1; // cast ok, same as previous line
BSTR bstr3 = bs1.Copy()// copies bs1, returns it as a BSTR
BSTR bstr4;

// CComBSTR의 메모리 관리를 꺼버릴 수 있다.
bstr4 = bs1.Detach()// bs1 no longer manages its BSTR, 메모리 관리는 수동으로 해야한다.

// ...
SysFreeString ( bstr3 );
SysFreeString ( bstr4 );


추가로, 연산자&는 내부의 BSTR*를 리턴하도록 오버로딩 되어있기 때문에 사용상 고려할점이 존재한다.
STL의 list같은 컬렉션에서 CComBSTR을 사용하기 위해서는 &연산자 오버로딩으로 일반 데이터타입과는 다르게,
CAdapt 를 사용해야 한다. 즉 다음과 같다.
std::list< CAdapt<CComBSTR> > bstr_list;



CComVariant
ATL의 VARIANT wrapper 클래스다. _variant_t와는 다르게 내부의 VARIANT가 감춰져 있지 않아서 직접 접근이 가능.
게다가 CComBSTR과 간단히 형 변환되지는 않기 때문에 값을 넣기 위해서는 검사를 해야한다.
CComVariant v4 = ... // Init v4 from somewhere
CComBSTR bs3; 
// 검사하고 변환이 가능하면 넣는다.
if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))
bs3 = v4.bstrVal;



ATL Conversion Macros ? MBCS / Unicode / BSTR 간의 Encoding 변환
Macro 함수의 이름은 다음과 같은 구조로 돼어있다.
[원본 타입]2[새 타입] / [원본타입]2C[새 타입]
2는 그냥 변환 / 2C는 constant pointer를 말하는 C이다.

A : MBCS 문자열 char*
W : Unicode 문자열 wchar_t*
T : TCHAR 문자열 TCHAR*
OLE : OLECHAR 문자열 OLECHAR*
BSTR : BSTR

예를 들어, W2A() 매크로는 Unicode문자열을 MBCS문자열로 변환한다.
매크로를 사용하기 위해서는 atlconv.h 헤더를 포함해야 하는데, 해당 헤더파일만 포함하면 굳이 ATL프로젝트가 아니라도
사용이 가능하다.

사용시에는 우선 USES_CONVERSION 이라는 매크로를 사용전에 호출해주어 변환에 필요한 기본 변수들을 정의 한뒤,
실제 변환 매크로를 사용하면 된다.
// Functions taking various strings:
void Foo ( LPCWSTR wstr );
void Bar ( BSTR bstr );
// Functions returning strings:
void Baz ( BSTR* pbstr );

#include &lt;atlconv.h&gt;

main()
{
using std::string;
USES_CONVERSION;  // declare locals used by the ATL macros

// Example 1: Send an MBCS string to Foo()
LPCSTR psz1 = "Bob";
string str1 = "Bob";

Foo ( A2CW(psz1) );
Foo ( A2CW(str1.c_str()) );

// Example 2: Send a MBCS and Unicode string to Bar()
LPCSTR psz2 = "Bob";
LPCWSTR wsz = L"Bob";
BSTR bs1;
CComBSTR bs2;

bs1 = A2BSTR(psz2);  // create a BSTR
bs2.Attach ( W2BSTR(wsz) )// ditto, assign to a CComBSTR

Bar ( bs1 );
Bar ( bs2 );

SysFreeString ( bs1 );  // free bs1 memory
// No need to free bs2 since CComBSTR will do it for us.

// Example 3: Convert the BSTR returned by Baz()
BSTR bs3 = NULL;
string str2;

Baz ( &bs3 )// Baz() fills in bs3

str2 = W2CA(bs3)// convert to an MBCS string
SysFreeString ( bs3 )// free bs3 memory
}
반응형
반응형
출처 : http://support.microsoft.com/kb/166275/ko

기술 자료 ID: 166275 - 마지막 검토: 2003년 8월 19일 화요일 - 수정: 1.1

HOWTO: VC++에서 기계어 코드 Visual Basic 구성 요소를 디버깅하는 방법

이 문서는 이전에 다음 ID로 출판되었음: KR166275

요약

코드를 .exe, .dll 또는 .ocx로 컴파일하기 전에 디자인 타임에서 Visual Basic 5.0 디버거를 사용하여 디버깅할 수 있습니다. Visual Basic으로 만든 COM 구성 요소를 디버깅할 때 동일한 Visual Basic 5.0 인스턴스에서 복수의 프로젝트를 실행하거나, Visual Basic 5.0의 한 인스턴스에서 클라이언트를 실행하고 다른 인스턴스에서 COM 구성 요소를 실행하는 등 별개의 Visual Basic 5.0의 인스턴스를 실행함으로써 프로세스 외부에서 COM 구성 요소를 디버깅할 수 있습니다. 

Visual Basic 5.0 디버거는 디자인 타임에서만 구성 요소를 디버깅하기 때문에 컴파일한 후에는 구성 요소를 Visual Basic 5.0 디버거에서 디버깅할 수 없습니다. 컴파일된 Visual Basic 구성 요소를 디버깅하려면 Visual C++ 5.0 디버거의 기능을 사용해야 합니다. 아래와 같은 경우에 컴파일된 Visual Basic 구성 요소를 디버깅해야 할 수도 있습니다.
  • Visual Basic 5.0이 아닌 컨테이너에서 사용하기 위해 ActiveX 컨트롤을 만드는 경우
  • 컴파일된 .dll만을 실행할 수 있는 Microsoft Transaction Server 같은 응용 프로그램 실행 환경인 경우
  • 디자인 타임에서 Visual Basic 구성 요소가 컴파일 시와 다르게 동작한다는 의심이 들 때
본 문서에서는 Microsoft Developer Studio 환경에서 Visual Basic 구성 요소를 디버깅하는 방법을 설명합니다. 아래에서 설명하는 예제를 수행하려면 개발용 컴퓨터에 Visual Basic 5.0과 Visual C++ 5.0을 설치해야 합니다.

추가 정보

아래의 단계를 수행하려면 디버깅할 표준 EXE(.exe), ActiveX DLL(.dll), ActiveX EXE(.exe) 또는 ActiveX 컨트롤(.ocx)을 Visual Basic 5.0에서 미리 만들어 두어야 합니다.
  1. 디버깅할 Visual Basic 프로젝트를 Visual Basic 5.0에서 엽니다. 파일 메뉴에서 프로젝트_이름.exe 만들기를 선택합니다. 옵션 단추를 누르고 컴파일 탭을 선택합니다.기계어 코드로 컴파일과 심볼 디버그 정보 만들기를 선택합니다. 확인을 누른 다음 다시 확인을 눌러 구성 요소를 컴파일합니다.
  2. Visual C++ 5.0 File 메뉴에서 Open Workspace를 선택합니다. Open Workspace 대화 상자에서 Files of Type을 All files(*.*)로 설정한 다음 컴파일된 구성 요소를 선택합니다.
  3. 이번에는 Visual C++ 5.0 File 메뉴에서 Open Workspace 대신 Open을 선택한 다음 디버깅할 Visual Basic 모듈(.bas), 폼(.frm) 또는 클래스(.cls)를 엽니다. 일반 프로그램을 디버깅할 때와 마찬가지로 중단점(F9), 조사식(Watch), 단계별 실행(Step-Through) 명령 등을 설정합니다. 또한, Visual C++ 5.0 Tools 메뉴에서Options를 선택한 다음 Debug 탭을 눌러 디버그 환경에서 변수 정보를 표시할 수도 있습니다. Debug 탭에서 Display unicode strings 확인란을 선택합니다. 

    별개의 스레드에 있는 변수는 조사할 수 없습니다. 그러한 예로 .ocx를 사용하는 백그라운드 스레드나 숨겨진 vb 백그라운드 스레드가 있습니다. Visual Basic 전역 변수는 아파트별(Per-apartment) 또는 단일 스레드(Single-thread)이므로 다른 스레드에 있는 전역 변수를 스택에서 볼 수 없습니다.
    1. 표준 EXE: Visual C++ 5.0의 Build 메뉴에서 Start Debug를 선택한 다음Go를 선택하거나 F5 키를 누릅니다. 컴파일된 Visual Basic 구성 요소가 Visual C++ 5.0에서 중단점이 설정된 줄까지 도달하여 실행이 중지된 후 일반적인 디버깅 작업을 수행할 수 있습니다.
    2. ActiveX EXE, DLL 또는 OCX: DLL의 경우에는 디버깅할 exe를 지정해야 한다는 점에서 약간 다릅니다. 이를 위해 Project 메뉴에서 Settings를 선택하고Debug 탭을 누릅니다. Executable for debug session 입력란에 .dll을 참조하는 .exe 파일을 지정합니다. 이제 실행 파일과 .dll을 시작하는 3a단계를 수행하여 Visual C++ 5.0 디버거가 실행되면 이 곳에서 .dll에 중단점을 설정할 수 있습니다.
    3. Microsoft Transaction Server(MTS) 하에서 실행하는 ActiveX DLL: 이 DLL을 설정하기 위해 Project 메뉴에서 Settings를 선택하고 Debug 탭을 누릅니다. Executable for debug session 입력란에 MTX.EXE를 지정합니다. 그런 다음 Program arguments 입력란에 /p:{00000000-0000- 0000-0000- 000000000000}을 입력합니다. 여기서 0들을 실제 MTS 패키지 ID로 바꾸어야 합니다. 패키지 ID는 트랜잭션 서버 탐색기에서 패키지의 등록 정보를 검사하여 알아낼 수 있습니다. 위의 3a단계를 수행하여 MTX.EXE 및 .dll을 시작합니다. 이제 MTS 하에 실행하는 COM 구성 요소를 호출하는 기본 클라이언트 .exe를 실행하면 Visual C++ 5.0 디버거가 실행되고 이곳에서 .dll에 중단점을 설정할 수 있습니다.
      1. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. 

      2. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. 호출되는 dll이 시스템 경로에 있습니까?
      3. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. 실수로 com 개체의 dll을 다시 등록하여 레지스트리에서 MTS 변경 사항이 제거되지는 않았습니까?
      4. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. com 개체의 dll 복사본을 여러 개 가지고 있고 로드되지 않은 dll 복사본에 중단점을 설정하지는 않았습니까?
      5. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. 이전의 3번과 마찬가지로 com이 아닌 개체의 dll 복사본이 여러 개 있지는 않습니까?
      6. MTS 하에서 디버깅을 수행할 때 아래와 같은 추가 유의 사항을 참고하십시오. 기호 정보를 가진 DLL을 MTS 디렉터리에 복사하고 이 디렉터리에서 그 DLL을 MTS 탐색기에 패키지로 복사해야 합니다. 이 방법은 매우 불합리한 것처럼 보이지만 이렇게 하지 않으면 MTS 구성 요소 내에서 기호 디버깅이 작동하지 않습니다. 

        또한, 디버거에서 mtx.exe 복사본을 시작하기 전에 실행 중인 모든 mtx.exe를 종료해야 합니다. mtx.exe를 시작할 때 제대로 실행됩니까 아니면 즉시 종료됩니까? MTS에 의해 기록된 이벤트 로그 메시지를 확인하십시오. 안전하게 처음부터 시작하려면 응용 프로그램을 완전히 삭제한 다음 다시 만들고 구성 요소의 dll 등을 다시 설치합니다.
    4. Internet Information Server(IIS) 하에서 실행하는 ActiveX DLL: IIS는 Windows NT 서비스로 실행되기 때문에 운영 시스템의 일부로 동작하기 위한 사용 권한이 필요합니다. 이를 위해 Windows NT 관리 도구에서 사용자 관리자를 선택합니다. Windows NT Server에서 도메인 사용자 관리자를 사용할 때는 파일 메뉴에서 도메인으로 컴퓨터 이름을 선택해야 합니다. 그런 다음 정책메뉴에서 사용자 권한을 선택합니다. 사용자 권한 정책 대화 상자에서 고급 사용자 권한 보기 확인란을 선택하고 콤보 상자에서 운영 체제의 일부로 동작을 선택합니다. 추가 단추를 누르고 입력란에 "domainxxx\userxxx"를 입력하거나 목록 상자에서 사용자 이름을 선택합니다. 확인을 누르고 나면 올바른 권한이 부여됩니다. Visual C++ 5.0에서 디버깅 세션을 시작하려면 Build 메뉴에서Start DebugAttach to Process를 차례로 선택합니다. Show System Processes 확인란을 선택한 다음 inetinfo를 선택하고 OK를 누릅니다. 이제 ActiveX 구성 요소를 호출할 클라이언트 .htm 또는 .asp 파일을 로드합니다. 앞에서 3단계를 수행했으면 이제 Visual Basic 코드를 단계적으로 실행할 수 있습니다.
Visual C++에서 프로세스 간에 또는 컴퓨터 간에 디버깅을 수행할 수도 있습니다. 디버거에서 실행하는 동안 디버깅 정보를 가진 .dll을 호출하면 자동으로 디버거의 또 다른 인스턴스와 디버깅할 수 있는 소스가 시작됩니다. 

.exe가 크기 또는 속도에 최적화되도록 컴파일될 때는 여러 줄의 불필요한 코드(Dead Code)가 프로젝트 외부에서 컴파일됩니다. 


본 문서의 정보는 다음의 제품에 적용됩니다.
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
키워드: 
kbvbp500 kbvbp600 kbgrpvb kbusage KB166275
반응형

+ Recent posts