기본 콘텐츠로 건너뛰기

[데브피아]몇 가지 자잘한 VC6 팁

여기 저기서 줏어들은 내용들을 토대로 제 나름대로 적용해서 사용해 오던 VC6 용 팁 몇가지를 정리해봤습니다. VC7 이상에서도 (적절하게 변경하면) 사용가능할거라 생각됩니다.

팁 #1. 디버그 Watch 창에서 std::vector 내용 확인하기

STL 를 사용하다보면 어려운 점 중에 하나가 그 내용을 확인하기가 쉽지 않다는 점입니다. 배열을 사용하면 디버그 watch 창에 그
내용물이 보기 쉽게 표시되는데 배열의 STL 대응인 std::vector 를 사용하면 무슨 내용이 vector 저장되어 있는지 디버깅 시 확인하
기가 쉽지 않습니다. 다음과 같이 watch 창에 입력하면 std::vector 의 내용을 확인할 수 있습니다.

[ 테스트 소스 시작 ]

01: // testWatch.cpp : Defines the entry point for the console application.02: // 
03:  
04: #include "stdafx.h" 
05: #include <vector> 
06: #include <string> 
07:  
08: struct Student 
09: { 
10:  std::string name; 
11:  int id; 
12:  
13:  Student(const std::string & _name, const int & _id) : name(_name), id(_id) { } 
14: }; 
15:  
16: int main(int argc, char* argv[]) 
17: { 
18:  std::vector<Student> rgStudent; 
19:  
20:  rgStudent.push_back(Student("Jae", 1)); 
21:  rgStudent.push_back(Student("Mina", 2)); 
22:  
23:  printf("Hello World!\n"); 
24:  return 0; 
25: } 
26:   
[ 테스트 소스 끝 ]

a) VC6 내장 STL (Dinkum???)

" rgStudent.size() " 를 watch 창에 입력하면 벡터의 크기를 알 수 있습니다..

watch 창의 다음칸에 " rgStudent._First,2 " 를 입력하면 (2는 바로 위에서 구한 벡터의 크기) rgStudent 의 내용을 쉽게 확인할 수 있습니다.





b) STLPort 4.6.2

" rgStudent.size() " 를 watch 창에 입력하면 벡터의 크기를 알 수 있습니다.

watch 창의 다음칸에 " rgStudent._M_start,2 " 를 입력하면 (2는 바로 위에서 구한 벡터의 크기) rgStudent 의 내용을 쉽게 확인할 수 있습니다.





팁 #2. AUTOEXP.dat 활용하여 STL 사용 시 디버깅 조금 더 쉽게 하기

이 후 부터는 VC6 이 "C:\Program Files\Microsoft Visual Studio" 에 설치되었다고 가정합니다. 따라서 MSDEV.exe 파일은  "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin" 에 위치하게 됩니다.

VC6의 MSDEV.exe 파일이 있는 폴더에는 AUTOEXP.dat 란 파일이 존재합니다.

AUTOEXP.dat 파일은 툴팁에서나 디버그 Watch 창에서 해당 변수의 내용을 어떻게 표시할 지를 사용자가 결정할 수 있게 해줍니다.
간단하게 예를 들어서 MFC의 CPoint 형 변수를 디버그 Watch 창에 추가하면 오른쪽에 결과로 "{x=100 y=200}" 과 같은 형식으로 표
시가 됩니다. 또는 디버깅 시 해당 변수위에 마우스 커서를 올려놓고 잠시 기다리면 나오는 툴팁에서도 똑같은 결과가 표시됩니
다.
AUTOEXP.dat 파일을 열어보면 기본적으로 " CPoint =x=<x> y=<y> " 라는 아이템이 있습니다. 즉 CPoint 형 변수는 그 구조체(클래스)
의 멤버변수인 x, y 를 각각 x=<x> y=<y>의 식으로 표시하라는 의미입니다. (재미있게도 CSize 에 대해서는 기본적으로 확장이 정
의되어 있지 않습니다. CSize 형의 데이터를 watch 창에 추가한 경우에는 왼쪽의 + 마크를 클릭하여 트리를 확장하여 멤버를 직접 접근함으로써 CSize에 저장된 내용을 볼 수 있습니다.)


다음과 같은 내용을 추가함으로써 STL 사용 시 디버깅이 조금 더 수월해질 수 있습니다.


1) 우선 다음 내용의 부분을 찾아서 주석 처리합니다.

std::basic_string<*>=<_Ptr>



; std::basic_string<*>=<_Ptr>

2) 다음의 내용을 AUTOEXEC.dat 파일의 끝에 추가합니다.

[추가할 내용 시작]

;STL
std::basic_string<*>=strlen=<_Len,d> string=<_Ptr,st>
std::basic_stringstream<*>=strlen=<_Sb.str()._Len,d> strbuf=<_Sb._Pbeg,st>
std::basic_ostringstream<*>=strlen=<_Sb.str()._Len,d> strbuf=<_Sb._Pbeg,st>
std::basic_istringstream<*>=strlen=<_Sb.str()._Len,d> strbuf=<_Sb._Pbeg,st>
std::vector<*>=size=<size(),d> begin=<_First,x> <_First[0]> <_First[1]> <_First[2]> <_First[3]> <_First[4]> <_First[5]> <_First[6]> <_First[7]> <_First[8]> <_First[9]>
std::set<*>=size=<size(),d>
std::list<*>=size=<size(),d>
std::map<*>=size=<size(),d>
std::deque<*>=size=<size(),d>
std::queue<*>=size=<size(),d>

; STLPort
_STL::basic_string<*>=strlen=<size(),d> string=<_M_start,st>
_STL::basic_stringstream<*>=strlen=<_M_buf._M_str.size(),d> strbuf=<_M_buf._M_str._M_start,st>
_STL::basic_ostringstream<*>=strlen=<_M_buf._M_str.size(),d> strbuf=<_M_buf._M_str._M_start,st>
_STL::basic_istringstream<*>=strlen=<_M_buf._M_str.size(),d> strbuf=<_M_buf._M_str._M_start,st>
_STL::vector<*>=size=<size(),d> begin=<_M_start,x> <_M_start[0]> <_M_start[1]> <_M_start[2]> <_M_start[3]> <_M_start[4]> <_M_start[5]> <_M_start[6]> <_M_start[7]> <_M_start[8]> <_M_start[9]>
_STL::set<*>=size=<size(),d>
_STL::list<*>=size=<size(),d>
_STL::map<*>=size=<size(),d>
_STL::deque<*>=size=<size(),d>
_STL::queue<*>=size=<size(),d>
_STL::_DBG_iter<*>=<_M_iterator,x>

; Jae's
tagSIZE =cx=<cx> cy=<cy>

[ExecutionControl]
CString::CString=NoStepInto
CString::~CString=NoStepInto
CString::operator==NoStepInto
operator new=NoStepInto

; STL
std::*=NoStepInto

; STLP
_STL::*=NoStepInto

[추가할 내용 끝]

마지막의 [ExecutionControl] 섹션은 "Step Into (F11)" 명령 시 해당 소스로 들어가는 것을 금지시킬 수 있는 기능입니다. 일반적으로
CString 생성자/소멸자나 대입 연산자의 정의로 step into 할 필요성이 별로 없습니다. 마찬가지로 STL의 소스로 step into 하는 것도
커다란 의미가 없다고 생각합니다. STL의 소스로 step into 하기를 원한다면 해당 사항을 적절하게 제거또는 수정하시면 됩니다.

팁 #3: STLFilt ( http://www.bdsoft.com/tools/stlfilt.html ) 이용하여 STL 관련 warning 또는 에러메세지를 해석할 수 있는 형태로 변환하기.

STL 사용하면서 부딪히는 문제 중의 하나가 STL에 관련되서 발생되는 warning 또는 에러메세지는 거의 해독 불가능하다는 것입니
다. 템플릿 클래스가 중복되어서 사용되기 때문에 거의 3~4줄에 해당하는 메세지가 의미를 해석할 수 없는 형태로 출력됩니다.
STLFilt 라는 프로그램은 이렇게 복잡하게 출력되는 STL 관련 warning 또는 에러 메세지를 비교적 프로그래머가 해석할 수 있는 정
도 수준의 형태로 변환해 줍니다. 그런데 STLFilt 의 저자가 기본적으로 제안하는 방식은 VC6 설치파일의 위치를 이동시키고 제공된 새로운 파일을 사용하여 소스를 컴파일 해야하는 등등의  별로 탐탁치 않은 방법을 사용합니다.  따라서 개인적으로 VC6의 사용자 툴 기능을 이용하는 방법을 선호하며 그렇게 사용하고 있습니다. STLFilt 는 텍스트 프로세싱을 하기 위해서 Perl을 사용하기 때문에 Perl 인터프리터가 설치되어 있어야합니다. 이미 설치되어 있지 않다면 STLFilt 사이트에서 추천한 대로 ActivePerl ( http://www.activestate.com/Products/ActivePerl/ ) 을 다운로드 받아서 설치하여 사용할 수 있습니다.

*** STLFilt 는 " C:\Dev\STLFilt " 에 Perl 인터프리터는 " C:\Perl " 에 설치되었다고 가정합니다.

1) VC6의 사용자 툴을 사용하는 방법은 STLFilt 패키지 중에서 MFiltTool.bat 라는 파일과 STLFilt.pl 파일만 있으면 됩니다. MFiltTool.bat
를 다음과 같이 자신의 폴더 세팅에 따라서 적절하게 수정합니다.

[ MFiltTool.bat 시작 ]

@echo off
rem
rem MFiltTool.bat: Driver for processing a PLG file with STLFilt.pl
rem as an MSVC "Tool" script. See README-VCTool.txt for instructions.

rem (Updated 4/05/2003)

rem ********************************************************************
rem Configure the following variables as appropriate for your system:

rem STLFILT:  Full pathname of the Perl script
rem POPTIONS: Options to Perl interpreter
rem FOPTIONS: Options to Filter (the Decryptor Perl script)
rem
rem The value of the environment variable FOPTS is concatenated onto the
rem value of FOPTIONS. This permits trying out different filtering options
rem without editing this batch file: just set FOPTS to the desired options
rem before running MFilt.BAT.
rem *********************************************************************

set STLFILT=C:\Dev\stlfilt\STLFilt.pl
set POPTIONS=
set FOPTIONS=/plg

rem ********************************************************************

if not "%1" == "" goto filter

echo Usage: mfilttool PLG-filename
echo Filters PLG file through STL Error Decryptor.
echo (to supply Decryptor options, set the FOPTIONS variable to
echo  your "permanent" options, and/or the FOPTS variable in your environment
echo  to "temporary" options.)
echo.
goto done

:filter

C:\Perl\bin\perl.exe %POPTIONS% "%STLFILT%" %FOPTIONS% %FOPTS% < "%1"

:done

[MFiltTool.bat 끝]

2). VC6 의 Tools/Customize 메뉴 선택 후 다이알로그에서 Tools 를 선택한 후 다음과 같이 새로운 사용자 툴을 등록합니다.

Menu Contents: STLFilt
Command: C:\Dev\stlfilt\MFiltTool.BAT
Arguments: $(WkspName).plg
Initial directory: $(WkspDir)
Use Output Window 체크




3) VC6에서 STL 사용하면서 컴파일 시 해석하고자 하는 STL warning 또는 에러메세지가 발생했을 경우 위에서 등록한 Tools/STLFilt
를 선택하면 STL warning 또는 에러메세지가 STLFilt 출력창에 비교적 해석할 수 있을 정도 수준으로 변환된 형태로 출력됩니다.

팁 #4. 툴바 레이아웃 저장/불러오기

VC6을 실행/디버깅 하다보면 툴바의 레이아웃이 제멋대로 이동하여 보기 싫게 되는 경우가 많이 생긴다. 특히 VC6 애드인을 추가
하는 경우 이러한 애드인들은 보통 버튼이 2-3개 밖에 없는 툴바를 추가하는  경우가 많은데 이런 툴바가 한줄 전체를 차지하게
되면 쓸데없이 가시영역을 낭비하게 되면서 슬슬 짜증이 나기 시직한다. 일일이 툴바를 드래그해서 이동하고 재배치한 후 VC6을
종료하면 툴바 레이아웃이 저장되긴 하는데 다시 실행/디버깅 하다보면 특히 VC6을 최소화 시키거나 하면 툴바 레이아웃이 다시
망가져버린다.

(해결책)

VC6 툴바 레이아웃은 레지스트리의 "HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Layout" 에 저장된다. 이러한 사실
을 바탕으로 간단한 배치파일을 작성하여 VC6 실행 시 자동으로 저장되었던 툴바 레이아웃을 강제로 로딩한다.


1) MSDEV.bat 파일을 MSDEV.exe 실행 파일이 있는 폴더에 다음과 같이 작성합니다.

[MSDEV.bat 시작]

@echo off

;
; copy this file into "<<VC_INSTALLATION_PATH>>\Microsoft Visual Studio\Common\MSDev98\Bin"
;
;
;

if "%1"=="/e" goto export
if "%1"=="-e" goto export
if "%1"=="/i" goto import
if "%1"=="-i" goto import

:import_executeVC
cmd /C "%SystemRoot%\regedit.exe" /s TBLayout.reg
cmd /C "msdev.com"
goto end

:import
cmd /C "%SystemRoot%\regedit.exe" /s TBLayout.reg
goto end

:export
cmd /C "copy /Y TBLayout.reg TBLayout.reg.bak"
cmd /C "%SystemRoot%\regedit.exe" /e TBLayout.reg HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Layout
goto end

:end

[MSDEV.bat 끝]

MSDEV.bat /e 또는 -e 옵션은 현재 툴바 레이아웃을 TBLayout.reg 라는 파일로 저장 합니다.
MSDEV.bat /i 또는 -i 옵션은 TBLayout.reg 파일로부터 툴바 레이아웃을 로드합니다.
MSDEV.bat 를 옵션 없이 실행 시키면 TBLayout.reg 파일로부터 툴바 레이아웃을 로드한 후 바로 MSDEV.exe 를 실행시킵니다. (실재
로는 MSDEV.com 파일을 호출함으로써 MSDEV.exe 파일이 실행됩니다.)

2) 시작/프로그램/Microsoft Visual C++ 6.0 에 다음과 같은 단축 아이콘을 추가했습니다.




a) "Load Toolbar Layout"

Target : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\MSDEV.bat" /i
Start in : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin"
Run : Minimized

b) "Save Current Toolbar Layout"

Target : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\MSDEV.bat" /e
Start in : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin"
Run : Minimized

c) Microsoft Visual C++ 6.0 and Load ToolBar Layout

Target : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\MSDEV.bat"
Start in : "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin"
Run : Minimized

3) VC6을 실행시킨 후 툴바를 원하는데로 정돈한 후 "Save Current Toolbar Layout" 단축 아이콘을 실행 시켜서 툴바 레이아웃을 저장
합니다. 이 후부터 "Microsoft Visual C++ 6.0 and Load ToolBar Layout" 단축 아이콘을 통해서 VC6을 실행 시키면 앞서 정돈 된 툴바 레이
아웃으로 VC6이 실행됩니다.


4) VC6이 실행될 때 위에서 언급된 레지스트리 위치에서 툴바 레이아웃을 로드하고 VC6이 종료할 때 같은 장소에 툴바 레이아웃
을 저장합니다. 따라서 VC6이 실행하고 있는 동안에는 "Load Toolbar Layout" 단축아이콘을 통해서 툴바 레이아웃을 로드해도 적용
이 되지 않습니다.  VC6을 종료한 후 단축 아이콘 적용한 후 다시 실행시켜야지만 원하는 툴바 레이아웃을 로드됩니다.

팁 #5: VC6 에서 XP 비주얼 스타일 적용하기

MSDEV.exe 있는 폴더에 첨부된 msdev.exe.manifest 파일을 복사해주면 됩니다.

팁 #6: VC6에서 최신 MSDN 사용하기

최신 버전의 MSDN을 VC6의 내장 도움말(키워드에서 F1 눌렀을 때 자동으로 해당 주제의 도움말이 나타나는 방식)로 사용하는 방법입니다.

레퍼런스 : Integrate the latest MSDN with VC6 and Hook functions of COM (http://www.codeproject.com/macro/VSNetHelp.asp )

(*** 반드시 PSDK가 설치되어 있어야 합니다. ***)


1) 위에 링크된 코드 프로젝의 글에서 VC6용 애드인 파일을 다운로드 받습니다. (Download demo project - 13.3 Kb)

2) 다운로든 받은 파일(VSNetHelp.zip) 의 압축을 풀고 VSNetHelp.dll VC6용 애드인 파일을 "C:\Program Files\Microsoft Visual Studio\Common\MSDev98\AddIn" 폴더에 복사합니다.

3) PSDK가 설치된 폴더의 bin 서브폴더에 있는 "Depeneds.exe" 를 실행시킵니다. VC6에 딸려오는 "Depends.exe" 가 아니라 PSDK에 딸려오는 "Depends.exe" 를 실행시켜야 합니다. 기본 설정으로 PSDK 설치했을 경우 "C:\Program Files\Microsoft SDK\Bin\" 폴더에서 Depends.exe 파일을 찾을 수 있습니다.

4) Dependency Walker가 실행된 후 " Options / Configures External Function Help Collection... " 를 선택하면 나오는 다이알로그 창에서 설최된 최신 버전의 MSDN 도움말을 선택합니다. (MSDN 2.x Default Collection 또는 MSDN 2.x MSDN Quartery Library - XXX 2005 정도를 선택하면 됩니다.)

5) Dependency Walker를 종료합니다.

6) VC6을 실행시킨 후 "Tools"->"Customize"->"Add-ins and Macro Files"->"Browse" 메뉴에서 VSNetHelp.dll 을 선택합니다.

7) 소스 코드에서 F1을 누르면 설치된 최신 MSDN의 도움말을 사용하여 관련 주제를 표시해줍니다.

#6-1: PSDK 2003 년 2월 버전

VC6 에서 사용가능한 가장 최신 PSDK는 2003년 2월 버젼입니다. 이 후에 나온 버젼에서는 새로이 향상된 보안기능이 바이너리에 활성화 되면서 VC6을 더 이상 지원할 수 없게 되었다고 합니다. ( 참고: http://blogs.msdn.com/loripe/archive/2005/05/02/414100.aspx ) 2003/2월 이 후 버전을 사용하여 컴파일 하는 경우 LNK1103 에러가 발생합니다.

2003년 2월 버젼 PSDK는 다음의 링크에서 다운로드 받을 수 있습니다.

http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm

댓글

이 블로그의 인기 게시물

80040154 오류로 인해 CLSID가 {xxxx-...}인 구성 요소의 COM 클래스 팩터리를 검색하지 못했습니다.

원문보기 .NET 으로 만든 응용프로그램에서 com 객체를 호출한 경우 Windows7 64bit 에서 제목과 같은 에러가 발생했다. Win32 COM 과 .NET 프로그램간의 호환성 때문에 생긴 문제였다. 원인은 .NET 실행시 JIT 컴파일러에 의해 최적화된 기계어로 변환되기 때문.. Win32 COM은 컴파일시.. Win32 COM에 맞춰 빌드 속성에서 하위버전으로 맞춰 컴파일을 다시하는 방법도 있지만 메인 프로젝트가 .NET이라면 참조되는 모든 프로젝트를 다 바꿔야할 노릇.. 또 다른 방법은 COM+를 이용하여 독립적으로 만드는 것이다. 분리시키는 방법은 아래 주소해서 확인할 수 있다. http://support.microsoft.com/kb/281335 나의 경우는 Win32 COM DLL을 64비트 .NET 프로그램에서 참조하니 COM 객체를 제대로 호출하지 못하였습니다. 그래서 .NET 프로그램의 Target Machine을 x86으로 설정하니 제대로 COM 객체를 호출하였습니다.

[Pyinstaller] 실행 파일 관리자 권한 획득하기

고객사에서 일부 사용자에게서 프로그램 오류가 발생한다며 아래와 같이 에러 캡처를 보내왔습니다. 프로그램에서 로그를 남기기 위해 로그 파일을 생성하는데 권한의 문제로 로그 파일을 생성하지 못해 프로그램 오류가 발생한 것 같습니다. 처음에는 Python 코드에서 관리자 권한을 요청하는 코드를 넣으려고 했는데, 실제로 Stackoverflow를 찾아보면 이런 내용이 나옵니다. 프로그램이 관리자 권한으로 실행되지 않았다면 관리자 권한으로 다시 프로그램을 실행시키는 코드입니다. import os import sys import win32com.shell.shell as shell ASADMIN = 'asadmin' if sys.argv[-1] != ASADMIN: script = os.path.abspath(sys.argv[0]) params = ' '.join([script] + sys.argv[1:] + [ASADMIN]) shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params) sys.exit(0) 하지만 개인적으로 이런 방식은 마음에 들지 않았고 조금 더 찾아보니 Pyinstaller로 exe 파일을 만들 때 옵션을 설정하여 관리자 권한을 요청하도록 할 수 있다고 합니다. --uac-admin을 옵션에 추가하면 프로그램 실행 시 관리자 권한을 요청할 수 있습니다. pyinstaller.exe --uac-admin sample.py 하지만 안타깝게도 이 방식은 원하는 대로 동작하지 않았습니다. 마지막으로 manifest 파일을 이용하여 시도해보았습니다. spec 파일을 이용하여 pyinstaller로 빌드하면 <실행 파일 이름>.manifest 라는 파일이 생성됩니다. 파일에서 아랫부분을 찾아볼 수 있습니다. <security> <re

초간단 프로그램 락 걸기

프로그램에 락을 걸 일이 생겨났다. 하드웨어 락을 걸면 쉬울텐데 그 정도는 아니고 프로그램의 실행 날짜를 제한 해 달라고 한다. 그래서 파일(license.lic)을 가지고 락을 걸리고 결정을 했다. 요구 사항은 아래와 같다. 1. license.lic 파일이 없으면 프로그램을 실행 할수 없게 한다. 2. 지정한 날짜를 넘어서는 프로그램을 실행 할수 없게 한다. 3. 사용자가 시스템 날짜를 되돌렸을때 인식하여 프로그램을 실행 할수 없게 한다. 음.... 1.번 문제는 사용자가 프로그램을 실행하기 위해서 license.lic 파일을 받아야만 한다. license.lic 파일에는 최근 실행 날짜/종료날짜 이런식으로 적도록 한다.(물론 내용은 암호화 한다.) 최근 실행날짜는 프로그램이 실행때마다 업데이트 하도록 하고 시스템 날짜와 비교하여 시스템 날짜가 최근 실행 날짜보다 이전의 날짜면 시스템 날짜를 되돌렸다고 인식하도록 한다.(3.번 문제 해결) 시스템 날짜와 종료 날짜를 비교하여 시스템 날짜가 종료 날짜를 넘으면 프로그램을 실행 할수 없도록 한다.(2.번 문제 해결)