사용자 삽입 이미지
 내가 구현한 프로그램은 핵심 모듈은  초 당 1000Hz의 샘플링 레이트로 데이터를 처리하는 부분이다.

 이 프로그램을 디버그 모드로 장기 테스트를 돌리면, 꼭 이틀 정도가 지나면... 강제적으로 위 그림과 같이 _CrtDbgBreat(); 에 브레이크 포인트가 걸린다.

위 코드는 _heap_alloc_dbg()의 일부분이다.

이 문제의 근본적인 원인은 바로 if(lRequest == _crtBreakAlloc) 이 부분이다. 그리하여, 디버그 모드에서 NEW를 2^32 - 1회 호출하면, 자동으로 이 곳에 도달하게 되는 것이다.

친절한 구글사마를 통해 알아본 결과, 위와 같은 문제를 해결하는 방법에는 4가지가 있는데... 그 방법은 다음과 같다. (원문을 그대로 붙인다.)

more..


결국 가장 간단한 방법은  VC를 7.0 이상으로 쓰는 것인데... 이상하게도 C++은 아직도 6.0이 가장 편한 것 같다. 왠지 7.0 이상은 화면부터 맘에 안 들어--; (그럼에도 불구하고, C# 할 때는 VS 2005를 잘 쓰고 있다.)
크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/132

Comments

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]

 우연히 웹서핑을 하던 도중, Visual Leak Detector란 녀석을 알게 되었다.
(사실, 제법 이전부터 알고는 있었지만, 쓰지는 않았다.)

사용법은 매우 단순하다. 코드에 #inclue <vld.h>를 추가해주고, 디버그 모드로 돌려보면, Memory Leak이
존재할 경우, 사정없이 뱉어준다.


이 녀석을 이용해, 현재 구현중이던 프로그램에 적용해보니, Memory Leak이 발견되었다는 것이 아닌가?!
허거덩..-_- 분명, MS 자체의 디버그 모드로 돌렸을 때는 발견되지 않았었는데..!!!

"뭐야뭐야! 나같은 천재에게 Memory Leak은 어울리지 않아-ㅁ-;; 분명, Visual Leak Detector의 버그 일거
야..-ㅁ-" 같은 헛소리를 하면서.. 차근차근 Memory Leak이 발생할만한 원인을 탐색하던 바... 이르게 된 곳
은 STL의 ifstream이었다.


난 모든 코드를 배제하고, MFC의 Dialog 기반의 프로젝트를 하나 생성했다. 그리고, 단지 2줄의 코드만 추
가했다.

ifstream fin("sample.txt");
fin.close();

그랬음에도.. 우리의 Visual Leak Detector는 Memory Leak을 찾아냈다. 여기에도 또 문제가 있는 것이,
"sample.txt"란 파일이 존재할 경우에만, Memory Leak을 뱉어냈다. 즉, 존재하지 않는 파일의 경우엔 파일
Open을 해도 Memory Leak을 뱉어내지 않았다.

나는 확인을 위해.. 데브피아에서 질문을 올렸는데..

A님: Visual Leak Detector를 사용해보지는 않았으나 바운스체커도 메모리릭이 발견되네요. stl부분에서

B님:

VS6.0에 포함되어 있는 STL 버전이 상당히 구닥다리 입니다.

딩컴웨어의 구닥다리 버전이 포함되어 있어서 6.0에서는 stl을 사용할때

외부 STL을 사용하곤 했지요..

STL_Port 같은것을 사용하세요..


2003 이상 버전에서 포함되어 있는 STL을 그대로 쓰셔도 상관 없습니다.


친절하게 두 분의 답변이 돌아왔다. 결국엔 Visual Studio 6.0에 포함되어 있는 STL에 문제가 있는 것이다.
난 좀 더 확인을 위해 (왜케 집요해졌는지 모르겠다.) 짧은 영어로 MSDN을 헤맸는데, Visual Studio 6.0에서
STL string으로 Multi-Thread 프로그램을 구현할 경우, Memory Corruption이 발생할 수 있다는 MS의 얘기를
발견할 수 있었다.
MS에서 제시하는 해결책 역시 데브피아에서 B님이 답변해준 것과 비슷하게, Visual Studio 2003 이상 버전
을 쓰거나 STL 3rd party 라이브러리를 쓰라는 얘기였다.

난 이제 껏, STL하면, SGI STL이 전부인줄 알았을 정도로 참으로 무지했다.
알고보니, gcc는 SGI STL을 기반으로 gcc 컴파일러에 맞게 구현해놓은 것을 쓰고 있고, MS는
Dinkumware 사의 STL을 쓰고 있었다. 그리고, Borland C++ Builder는 최근까지 Roguewave의
STL을 쓰다가, STL Port로 넘어갔다.

C++ 표준이 되어버린 STL일지라도 각 회사마다 STL은 조금씩 특징이 있었다.
대표적으로 STL Port와 Dinkumware의 STL의 list<> 클래스의 list 크기를 반환하는 size() 함수를 예로 들
면.. (http://crowmaniac.net/crowmania/ 를 참고한 어느 분의 블로그에서 참고했습니다.)

Dinkumware 사의 STL에서 제공하는 list의 size() 함수는 시간 복잡도가 O(1)이었다.
size_type size() const{   return (_MySize);   }

반면에, STL Port에서 제공하는 list의 size() 함수는 시간 복잡도가 O(n)이었다.
size_type size() const
{
       size_type _result = distance(begin(), end());
       return _result;
}

distance() 함수가 Bidirectional iterator기 때문에 O(n)인 것이다.

잉?! 그럼, 두 말 할 나위 없이, Dinkumware 사의 STL이 좋은 것이냐?
꼭, 그런 것은 아니다..^^

size()를 O(1)으로 구현한 Dinkumware 사의 STL은 태생적으로 O(n)의 splice(끼워넣기)를 가지는 반면에,
STL Port는 O(1)의 splice만 가진다.

다시 얘기하면, size()를 자주 호출해야할 코드에서는 Dinkumware의 STL이 낫고, splice를 자주해야 하는
코드에서는 STL Port가 낫다고 볼 수 있다.

뭐, 난 갠적으로 정렬이 필요하지 않은 데이터의 경운 걍 vector를 쓰고, 정렬이 필요한 경우엔 Hashtable을
구현한 map을 쓰기 때문에-ㅁ-;; list를 잘 쓰지 않는다.

암튼.. 이제 STL Port를 깔러 가야겠다-ㅁ-

크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/117

Comments

  1. 마틴 2007/11/29 11:58

    Visual Leak Detector라.. 좋은거 알았네 ^^*

    perm. |  mod/del. |  reply.
    • NOhungry 2007/11/29 23:09

      Memory Leak은 프로그래머들의 가장 큰 적이지요-ㅁ-

  2. 까막 2007/11/30 11:50

    어머나.. 어느분이 제 글을 참고하셨는지 갑자기 궁금.. 해지네요 :)
    STLPort 괜찮습니다. 씨익.

    Memory Leak을 코드단계에서 방지하는 방법중 하나가 Smart Pointer이지요.
    http://www.boost.org 에서 제공하는 boost::shared_ptr<>을 사용해 보시는 것도 좋을듯 합니다. :)

    perm. |  mod/del. |  reply.
    • NOhungry 2007/11/30 13:56

      오옷.. 안녕하세요.ㅋ

      STLPort 괜찮죠..^^ 근데, 까막님은 STLPort 버전 어떤거 쓰세요? 전 처음에 5.1.4 설치하려고 했더니, 빌드하고 Path를 제대로 설정했음에도 계속 Link Error 뜨고, 그래서..

      다시 4.5.3으로 바꿨답니다-ㅁ-

  3. 원두 2007/11/30 13:33

    Visual Leak Detector~ 괜찮은 녀석이군. 나도 나중에 함 써 봐야지~
    메모리 Leak이 몇개나 나올지... 내심 두렵구먼~ㅋㅋ

    perm. |  mod/del. |  reply.
    • NOhungry 2007/11/30 13:57

      에~ 애시당초 Memory Leak은 코드 단계에서 방지하는게 좋죠. 프로그래머가 메모리 해제를 하는게 아니라, 소멸자가 해주도록 하는 방향으로..^^

      RAII란 개념인데, SmartPointer라고도 하죠.

      사람들이 대부분 boost 라이브러리를 많이 쓰더라구요. 전 그냥, STL에 있는 auto_ptr를 쓰거나, 그냥 구현해서 쓴답니다.ㅋ

  4. 까막 2007/11/30 18:50

    STLPort는 5.1.4(at VC++2003, 2005) 씁니다. :)

    std::auto_ptr도 좋긴한데 컨테이너에 넣을수가 없다는 최대단점이(!!).. ;ㅁ;

    perm. |  mod/del. |  reply.
  5. 우하하 2008/08/07 08:42

    다음 URL을 참고해서 VC6에 있는 STL에 대해서 버그픽스를 해보시죠.
    http://woohaha.egloos.com/790425
    버그픽스한 제 시스템에서는 메모리릭이 발생하지 않는 것으로 봐서 VC6에 들어있는 STL의 버그 때문에 생기는 현상인 듯 싶군요.
    [참조]
    http://www.dinkumware.com/vc_fixes.html
    http://madchick.egloos.com/237931

    perm. |  mod/del. |  reply.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]

우리 회사에서 개발 중인 무선 계측기는 검색 기능을 제공하는데, 검색 방법은 UDP 프로토콜을 이용한 브로드캐스팅이다. 짜증스럽게도, UDP 프로토콜로 브로드캐스팅을 하기 위해서는 IP 대역이 맞아야 한다.

우리의 사랑스런(?) 무선계측기들은 IP가 192로 시작하고... 우리 회사의 PC들은 고정 IP를 사용하는데.. 211로 시작한다. 따라서, 무선계측기를 테스트하려고 하면, 항상 IP를 바꿔주는 노가다가 필요하다. 단지, UDP로 브로드캐스팅을 하기 위해서..-_-

일일이 네트워크 환경 - 설정 - TCP/IP 설정..... 으로 이어지는 귀차니즘을 이기지 못하고, 알아본바.. WMI라는 녀석을 알게 되었다.

WMIWindows Management Instrumentation인데, Windows 기반 운영체제의 management 데이터를 위한 인프라 구조라고 할 수 있다.

쉽게, 예를 들자면.. 내 운영체제의 버전이 얼마인지? 또는 내 컴퓨터의 IP를 변경하고 싶다던지? 내지는 원격으로 컴퓨터에 프로그램을 설치하고 싶다던지... 이 모든 것이 다 WMI로 가능하다는 것이다.

더 상세한 내용은 MSDN을 참고하기로 하고.. 이미 이전에 WMI를 이용해 C#으로 간단히 IP와 서브넷 마스크, 게이트웨이 등을 설정할 수 있는 프로그램을 만든 바가 있어서 C++로도 간단히 1~2시간이면 할 수 있을거라 여겼다.

하지만, Wrapper Class와 많은 예제가 제공되던 C#과는 달리, C++에서는 WMI가 완전히 COM API 레벨에서 해결해야 하고, 내가 원하는 수준의 예제가 없었다. (내가 못 찾은건지도 모른다-ㅁ-)

그러다보니.. 삽질에 삽질을 거듭하다.. 결국 야근까지 하게되며.. 무려 6시간을 잡고 헤맸다.

잡설이 길었는데.. WMI를 이용해 Local PC의 IP를 바꾸는 내용으로 돌아와서...

구현 환경은 Windows XP Professional, Microsoft Visual Studio 6.0 SP6이다.
내 기억이 맞다면, Microsoft Visual Studio 6.0에서 WMI를 구현하기 위해서는 아마도 Microsoft Platform SDK 또는 WMI SDK를 설치해야 하는 것으로 알고 있다.

그리고 코드의 전체적인 흐름은 다음과 같다.

Step 1. COM 라이브러리를 초기화한다.
Step 2. COM Security Level을 설정한다.
Step 3. WMI에 대한 초기 Locator를 획득한다.
Step 4. WMI에 접근한다.
Step 5. Proxy의 Security Level을 설정한다.


여기까지는 사실, WMI를 프로그래밍 하기 위한 준비 단계라 할 수 있다. 이 다음부터는, IP와 서브넷마스크를 설정하기 위한 단계이다.

Step 6. ExecQuery()를 이용해, Class Object Enum을 가져온다.

hr = pServices->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_NetworkAdapterConfiguration"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnum
);

쉽게 설명하면, Win32_NetworkAdapterConfiguration란 클래스로부터 Network Adpater들의 Enum을 가져온다고 볼 수 있다. WMI의 Win32 Class에 대한 보다 상세한 정보는 http://msdn2.microsoft.com/en-us/library/aa394084.aspx 를 참조하기 바란다.

Step 7. Step 6에서 획득한 Network Adapter들 중에서 IPEnabled(IP 변경 가능 속성)이 TRUE인 녀석의 Index를 찾는다.

Step 8. IP와 서브넷마스크의 값을 설정한다.

Step 9. Object Path를 설정한다.
여기서 Object Path에 대해서 설명하자면.. IP와 서브넷을 변경하기 위해 Win32_NetworkAdapterConfiguration 클래스에서 제공하는 MethodEnableStatic이다. 이 Method의 타겟이 바로 Object Path라고 할 수 있다. (EnableStatic의 보다 자세한 내용은 http://msdn2.microsoft.com/en-us/library/aa390383.aspx 를 참조하기 바람)

이 부분이 필요한 이유는 비록 내 PC에서 네트워크 환경에서 보이는 로컬 연결 속성이 하나라고 해서, Network Adapter가 1개가 아니고, 로컬 연결 속성으로 사용되지 못하기 때문에, 눈에 보이지 않는 Network Adapter가 다수 존재한다. 따라서, Step 7도 이러한 이유에서 이다.

결국, EnableStatic의 타켓은 Win32_NetWorkAdapterConfiguration.Index이고, Step 7에서는 이 Index를 찾기 위한 단계였다.

Step 10 ~ Step 14는 앞서 설정한 속성들을 Network Adapter에 반영하기 위한 단계들인데, 여기에 등장하는 함수들은 MSDN을 참고하기 바란다.

다음의 코드는 단순히 기능 구현에 중점을 뒀기 때문에, 코드 최적화에 대해서는 전혀 고려하지 않은 막장 코드이므로, 실제 응용을 위해서, 다듬을 필요가 있다. 

소스코드 다운로드: http://www.nohungry.net/Data/IPHandler.zip

크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/116

Comments

  1. 조해성 2008/03/13 22:40

    좋은 자료 잘 보았습니다.
    다만, 장치의 Index 값을 얻을 때 1을 시작으로 하고 있으나, XP Home Edition 이나 XP Embedded 등의 다른 버전 OS에서는 0부터 시작하는 경우도 있습니다.
    따라서 임의적인 증가 수치를 사용하는 것은 문제 발생의 소지가 있구요. 대신 uint32 Index 멤버를 참조하는 것이 정확합니다.

    perm. |  mod/del. |  reply.
    • NOhungry 2008/03/14 17:36

      그렇군요!

      좋은 지적 감사 드립니다.ㅎ

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]


예전에도 아티클을 올린 적이 있었지만, DirectShow Programming을 Visual Studio 6.0에서 구현한다는 것은 상당히 번거로운 일이다.

MS에서 Visual Studio 6.0을 내놓은 자식 취급하면서 찾아온 일이지만.. 갠적으로 C++ 프로그래밍은 Visual Studio 6.0으로 해야 제 맛이라 생각하는 나에겐 여간 껄쩍찌근한게 아니다.

우습게도 C#때문에 Visual Studio 2005가 상당히 손에 익었음에도 C++ 만큼은 손에 익지 않는다. 문자열들 간의 타입 캐스팅이 까다롭다는 것은 사실 둘째 치고라도, 배경화면을 까맣게 맹글어놓고 쓰는 나에게 2005는 화면을 까맣게 맹글어도 영 아니 이쁘다는 것도 짜증난다-_-

암튼, 예전에 회사일 때문에 Visual Studio 6.0으로 DirectShow를 이용한 프로그램을 구현하다가 갑자기 일이 Drop 된 경우가 있었는데.. 이번에 도현이형의 부탁도 있고, 나도 예전에 하던걸 마무리 지어야 된다는 생각에서 프로그램을 마물했다.

혹시나 다음에도 DirectShow로 프로그래밍해야할지도 모를 기억력이 부족한 날 위해 몇 몇 중요 뽀인뜨를 기록하고자 한다.

1. DirectShow SDK는 반드시 2003년에 배포된 버전을 사용하자. 갠적으로 2월에 배포된걸 썼는데, 아무 문제가 없었다. (그 이후에서는 MS가 더이상 6.0을 내놓은 자식 취급하면서 전혀 고려하지 않고 있다.)

2. 만약, h파일들을 찾을 수 없다는 에러 메시지가 나타난다면?! DXSDK 설치 폴더 아래 Sample/VC++/BaseClasses 경로를 Include 경로에 추가해주자.

3. 반드시 다음 lib 파일들을 순서대로 링크시켜주자! strmiids.lib winmm.lib strmbase.lib quartz.lib
만약, Debug 모드라면 strmbase.lib -> strmbased.lib 로 고쳐주어야 하고, 반드시 Link Incremetally를 체크해주자!
만약, strmiids.lib와 strmbase.lib의 순서가 바뀌면, 중복 정의되었다는 에러메시지를 뱉어낸다.


덧글) 막상 DirectShow로 구현하고 나서, DirectShow SDK에서 제공하는 샘플들을 몇 개 돌려봤다. 그 중 AmCap이란 녀석과 PlayCap이란 녀석 2개가 있었는데.. 영상에 대한 반응속도.. 그러니까 카메라에 대고 손을 흔들었을 때의 반응을 보니, AmCap이 PlayCap보다 더 빠른 것 같았다. 왜 그럴까에 대해서.. 정말 알아보고 싶었지만, 시간 관계상 일단 접었다.. 다음에 기회가 되면 꼭 소스를 분석해봐야겠다..-ㅁ-
크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/99

Comments

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]

소프트웨어 디자인 패턴에 대해 공부하기 위해 웹을 헤매던 중.. Exception Handling에 대한 내용을 다룬 Article을 읽었다. 거기에 소개된 내용이 바로 RAII란 개념이다.

쉽게 얘기하면, Stack-based 변수Heap-based 변수와 관련 있는 얘기다.
다음과 같은 코드를 생각해보자.
<Example #1>
CSomething something("Stack");                                 // Stack-based 변수
CSomething* pSomething = new CSomething("Heap");   // Heap-based 변수

// 생략 ...

delete pSomething;
pSomething = NULL;

<Example#1>에서 알 수 있듯이, Stack-based 변수는 소멸자 해제를 Runtime이 관리해주고, Heap-based 변수는 프로그래머 자신이 관리해야된다. (다 아는 얘기지만.. new를 했으면, delete를 해줘야 하는 법...)

이걸 깜빡하면, 결국 메모리 누수(Memory Leak)이란 재앙을 만나게 된다.

근데, 이렇게 다 아는 얘기를 왜?! 하고 싶은 얘기는 지금 부터다.
학교 숙제를 할 때 우리는 예외 처리(Exception Handling)에 대한 중요성을 소홀히 할 때가 많다.
물론, 조환규 교수님께서는 늘 프로그램의 가장 중요한 덕목은 땐땐함(Robust)이라고 하셨지만..ㅎ 숙제 마감에 시달리게 되다보면, 그걸 지키지 못하는 경우가 허다하다.

<Example #1>을 다음과 같이 수정해보자.
<Example #2>
CSomething something("Stack");                                 // Stack-based 변수
CSomething* pSomething = new CSomething("Heap");   // Heap-based 변수

try{
// 생략 ...
}
catch(int exception_code)
{
     cout << "Exception Occured." << endl;
     delete pSomething;
     pSomething = NULL;
}

delete pSomething;
pSomething = NULL;

자, 예외 처리가 들어가면서, 코드가 뒤죽박죽이 되어버렸다. 동일한 코드가 반복적으로 사용되었고, 예외처리 부분과 자료구조 부분도 섞여버렸다. 이런 부분이 꼭 나중에 문제를 일으키기 쉽다.

깜빡하고, delete를 안해줘서 메모리 누수가 발생하거나, 아니면, 나중에 코드를 유지보수해야할 때도 골치아프게 된다.

이렇게, 골치가 아프게 되는 원인은, Heap-based 변수에 있다. Heap-based 변수는 바로 프로그래머가 관리해줘야 하기 때문이다. 그래서 가급적이면 Heap-based 변수를 사용하지 말자. (포인터를 쓰지 않겠다는 말이냐고?!)

당근, 그건 아니다. 그래서, 필요한 것이 바로 Smart Pointer~!
다음과 같은 코드를 만들어보자.
<Example #3>
class CSomethingPtr
{
public:
CSomethingPtr(CSomething* pSomething);
~CSomethingPtr();

private:
CSomething* m_pSomething;
};

CSomethingPtr::CSomethingPtr(CSomething* pSomething)
: m_pSomething(pSomething)
{
}

CSomethingPtr::~CSomethingPtr()
{
delete pSomething;
pSomething = NULL;
}

그럼, <Example #3>를 이용해 <Example #2>를 수정해보자.
<Example #4>
CSomething something("Stack");                                           // Stack-based 변수
CSomethingPtr pSomethingPtr(new CSomething("Stack"));       // Stack-based 변수

try{
// 생략 ...
}
catch(int exception_code)
{
     cout << "Exception." << endl;
}

이런 식의 기법을 바로 Smart Pointer(포인터처럼 동작하는 객체)라고 한다.
바로 지역객체(Stack-based 변수)를 사용하여 자원을 관리한다고 해서 이를 RAII라고 한다.

RAII에 대해서 공부하면서, 문득 생각난.. 왜 DirectShow SDK에서 Pointer 대신 CComPtr과 같은 형식의 클래스가 많은지 이제 깨달았다. (그 때는 별 생각없이 썼는데.. 돌이켜보면 바로 이런 관점에서 작성한 것이었으리라..)
아무튼, 앞으로도 이런 내용을 보다 열심히 공부할 필요가 있겠다.


보다 자세한 내용은 고형호님의 블로그(http://www.innosigma.com)에 가시면 찾아볼 수 있습니다..^^

크리에이티브 커먼즈 라이센스
Creative Commons License
TAG

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/92

Comments

  1. acaran 2007/07/04 22:45

    저렇게 스마트 포인터를 사용할 경우, 그냥 포인터 참조할때 보다 속도에 있어서 손해볼건 없는가?

    perm. |  mod/del. |  reply.
    • NOhungry 2007/07/05 09:08

      나도 전문을 다 읽어보지 못하여 퍼포먼스에 대한 정확한 판단을 내리긴 힘드네.

      하지만, 이 업계 최고수 중 하나로 불리는 Effective C++의 저자인 스캇 마이어스가 추천하는 기법이니, 퍼포먼스 면에서 크게 차이가 없을거라 보네.

      설사 퍼포먼스 면에서 약간의 손해가 있더라도 예외처리가 많이 포함되어야 하는 다소 큰 규모의 프로젝트에서는 이 방식을 쓰는게 코딩의 효율성 측면에서 좋지 않을까 생각되는구려.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]


회사에서 다가올 프로젝트에 쓰여질 그래프 라이브러리를 선택하기 위해, 여러 그래프 라이브러리를 테스트하던 중, 그 중 ChartFX ClientServer 6.2 버전도 포함되어 있었다.

ChartFX ClientServer 6.2는 Visual Studio 6.0을 지원한다고 되어 있었지만.. 어처구니 없게도 샘플 프로그램이라던지.. User Reference Guide에서도 C#과 VB에 대해서만 설명이 되어있을뿐 구할 수가 없었다.

그래서 몸소 삽질해서 그 방법을 체득하는 수 밖에 없었다.

Step 1. 우선 ChartFX ClientServer 6.2를 설치한다.
Step 2. Visual Studio 6.0에서 임의의 프로젝트를 생성한다. (아래 예제에서는 Dialog Base로 만들었다.)
Step 3. 마우스 오른쪽 버튼을 눌러서, Insert ActiveX Control... 을 누른다.


Step 4. Chart Object를 선택하고, OK 버튼을 누른다.


Step 5. 그럼, 아래 그림과 같이 Chart Object가 삽입되었음을 확인할 수 있다.

Step 6. Class Wizard를 통해 삽입된 Chart Object에 변수를 할당(Add Variables)하고자 하면, 다음과 같은 메시지가 나타나게 된다.


Chart Object가 삽입되었는데.. 이 녀석을 제어하기 위해 C++ Wrapper Class를 만들 것이냐고 묻는 내용이다. 확인을 선택한다.

Step 7. 그러면, 다수의 헤더(.h) 파일과 소스(.cpp) 파일들이 생성될 것이라 보여준다. 클래스 이름과 헤더 파일 이름, 소스 파일 이름은 자신의 구미에 맞게 설정할 수 있다.

Step 8.
아래와 같이 Wrapper Class가 생성된 것을 확인할 수 있다.

이 Wrapper Class를 어떻게 사용하였는지는 첨부된 샘플 코드를 통해 분석하기 바란다.














덧붙이는 글
1. 삽입된 Chart Object에서 마우스 오른쪽 버튼을 클릭하여, properties를 실행하면, 그래프의 여러가지 속성들을 설정할 수 있다. 그 중에 우리가 특히 눈여겨 보아야할 속성들은 다음과 같다.

Gallery : 그래프의 모양에 관한 속성이다. (Bar, Line, Pie 등 십수가지의 그래프 형태가 지원된다.)
NSeries: 서브 그래프의 개수에 관한 속성이다.
NValues: 그래프의 데이터 개수에 관한 속성이다.

나머지 속성들은 한 번씩 바꿔보고, 변화되는 것을 보면 알 수 있다.

2. 함수들의 쓰임새는 대략 C#이나 VB용 Reference Guide를 보면 알 수 있다. 그러나 제일 곤혹스러운 것은 COD_VALUES나 COD_REALTIME같은 미리 정의된 상수들의 값을 알 수 없다는 사실이다. C#이나 VB에서는 이 녀석들을 enum 타입으로 정의한 것 같은데, C++에서는 함수의 파라미터로 long 타입을 받아, 결국 이 enum 타입을 알아내기 위해 C# 프로그램에서 다음과 같은 방법을 써서 알아냈다.

MessageBox.Show(Convert.ToInt32(COD.COD_AddPoints).ToString());

덧붙여, 필요에 의해 내가 알아낸 enum 타입들을 다음과 같이 재정의해서 사용하였다.
#define COD_VALUES 1
#define COD_REALTIME 16
#define COD_ADDPOINTS 128
#define COD_ALLOCHIDDEN 512
#define COD_REMOVE 2048
#define COD_SCROLL_REGEND 8192

#define CHART_TYPE_NOLEGINVALIDATE 8

#define REALTIMESETTING_STYLE_LOOPPOS 1
#define REALTIMESETTING_STYLE_NOWAITARROW 2

샘플프로그램 다운로드 - 귀차니즘에 의해, 주석이 별로 없지만.. 이해하시는데는 큰 무리가 없을 겁니다. 그리고, Trail 버전으로 테스트한 것이라 배포가 불가능하여, 샘플 프로그램 자체는 실행되지 않습니다. 단지, 코드 참조만으로 사용하시기 바랍니다.

ChartFX에 대한 보다 많은 정보:
http://www.softwarefx.co.kr

크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/90

Comments

  1. acaran 2007/06/28 23:05

    흐음.. 언제나 신기하는걸 하는구려~ 또 한수 배우고 가오~

    perm. |  mod/del. |  reply.
    • NOhungry 2007/06/29 09:28

      ㅎㅎ 신기하기는.. 그나저나 우리 언제 한 번 보는거요? 같은 서울 땅에 살면서 너무 보기 힘든 것 아닌가?

  2. 2007/07/02 19:50

    마침 유용한 팁이구려..
    생물과 노가다를 이것으로 줄일수 있을 듯.. ㅎㅎ ^^

    perm. |  mod/del. |  reply.
    • NOhungry 2007/07/03 12:14

      역시 생물과의 포스란?ㄷㄷㄷ 그나저나 그래프를 그려야 하나?ㅎ 그럼 갠적으로 ProEssential도 괜찮다~ 자세한건 갠적으로 물어보도록.ㅋ

  3. 비밀방문자 2009/05/22 16:45

    관리자만 볼 수 있는 댓글입니다.

    perm. |  mod/del. |  reply.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]

                                            [고뇌하는 자의 슬프고도 아름다운 뒷모습]

근 이번 주 초부터 DirectShow 때문에 머리에 쥐가 내렸다.
첨에 아무 생각없이 Visual Studio 2005를 기반으로 DirectShow 일을 진행했다.

#1. 왜 내 허락도 없이 그랬니?
첨엔 Visual Studio 2005를 기반으로 DirectShow 프로그래밍을 했다.
분명, 내 기억이 맞다면, DirectShow로 프로그래밍을 하려면.. DirectX SDK를 깔면 되었는데...
DirectX SDK 9.0c를 깔았음에도 불구하고.. Compile 조차 안되는게 아닌가?!!!!

첨엔 DirectX를 지우고 다시 깔아도 봤다.. 그런데 알고보니...
DirectX SDK 8.1 이후 버젼부터는 DirectShow SDK가 Microsoft Platform SDK로 포함되었단다..
"왜!! 내 허락도 없이 그냥 바꾸냐고!!!"

교훈: 항상 최신 정보에 익숙하도록 하자.. 그러나, 그러기엔 최신 정보는 너무나 빨리 쏟아진다.

#2. 왜왜왜!!!!
한참 Visual Studio 2005에서 지시 받은 대로 DirectShow Wrapper Library를 구현하고 있었다.
부장님 왈, "Visual Studio 6.0에 Compatible하게 맹글어."
"헉!!!!-ㅁ-"..

지금까지 하던 모든 행위들을 접고... 다시 시작했다.
Visual Studio 6.0으로 예제프로그램부터 돌려봤다. 아.. 아니나다를까 무수하게 쏟아지는... 컴파일
에러들.. 분명! 2005랑 똑같은 헤더 파일들을 include하고 Lib 파일들을 link 했음에도...ㅠㅠ

#3. 나를 위한 해결책들... 그리고 누군가를 위해서도...
예전에 내가 포스팅해둔 C#에서 Cross Thread 문제를 해결하는 방법을.. 그 후로 5개월 가량 지난 시점에서 내가 다시 만나게 되었다. 그러나.. 나의 이 한심한 기억 용량은 해결책을 이미 지워버린지 오래였다. 난 그 때 내가 그 때의 귀차니즘을 이겨내고 포스팅을 해둔 내가 얼마나 고마웠는지 모른다.

그래서 지금 이렇게 해결책을 다시금 쓴다.

(1) Tools - Option - Directory - Include에 젤 상위부터...
DirectX SDK의 include 경로, Platform SDK의 include 경로, Platform SDK의 Common 경로, Platform SDK의 Baseclass 경로를 추가한다. 그 이후에 원래부터 있던 include 경로들을 써준다. 꼭꼭!
(주: Platform SDK의 Common과 Baseclass의 경로는 Platform SDK의 버젼마다 조금씩 다르겠지만, Samples - Multimedia - DirectShow 아래에 존재한다. 참고로 난 Microsoft Platform SDK for Windows Server 2003 R2 버젼을 사용했다. Windows Server 2003 R2라고 하지만 XP Professional에서도 잘 돌아간다.)

(2) Tools - Option - Directory - Lib에 젤 상위부터...
DirectX SDK의 Lib 경로, Platform SDK의 Lib 경로를 추가해준다.

(3) 추가해야할 Include 파일들...
필히 다음과 같은 순서대로 Include 하자.
atlbase.h, windows.h, dshow.h, strsafe.h, iostream.h : 참고로 이 헤더 파일 순서는 DirectShow Sample들 중 PlayCap을 기준으로 쓴 것이다. 하지만, 대략 위와 같은 순서가 맞다.

(4) 추가해야할 Lib 파일들...
잡다한 것은 지워도 좋다.
하지만 필히 다음과 같은 순서대로.. "strmiids.h, strmbase.lib, ole32.lib, uuid.lib, gdi32.lib"

(5) CoInitializeEX Error 문제는...
Project - Setting - C/C++ - Prepeocessor Definitions에 _WIN32_DCOM를 추가해주면 해결 가능하다.

(6) strmiids.lib(strmiids.obj) : fatal error LNK1103: debugging information corrupt; recompile module
이 문제는 사실 상 6.0에선 해결이 불가능하다고 한다. 뭐 꼼수가 있다고 하는데.. 매우 복잡한 관계로 해결이 힘들고, 이는 Visual Studio 7.0 이상.. (다시말하면 Visual Studio .NET 2003 이상)에선 괜찮다고 한다.

해결방법은.. Release 모드로 하면 된다는 것.. Debugging 하기 힘들다는 단점이 있지만.. 어쩔 수 없지 않은가...-ㅁ-

(7) 추가적인 문제...
Visual Studio 6.0에서 DWORD_PTR, LONG_PTR과 같은 타입을 찾을 수 없다고 나올 때.. 에러나는 헤더 파일을 열어 각각을 DWORD*, LONG* 로 바꾼 후, 저장하면 해결된다.-ㅁ-;;
크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/84

  1. Subject : 시작부터 난관. DirectX SDK 컴파일 삽질

    Tracked from Sylphid Wave 2007/06/18 02:31 del.

    2007.06.16 #1 DirectShow를 쓰기 위한 윈도 프로그래밍에서 dshow.h를 include하게 되는 데, 이 파일은 DirectX 9.0c SDK에 포함되어 있지 않다. 그걸 모른채 설치한 디렉토리 내의 Include, Lib를 열심히 Visual Stu..

Comments

  1. acaran 2007/05/25 20:36

    학생, 그래도 온종일 프로그래밍으로만 머리를 쓸수 있다는건 행복한 일이네-_-

    난 요즘 프로그래밍 작업만 하고 싶은데, 정작 해야할건 그게 아닌게 더 많아서 괴롭소-_-

    perm. |  mod/del. |  reply.
  2. noname 2007/06/16 02:27

    #1에 대해서 감사합니다. 한참 찾다가 아마 이렇게 된 거 아닌가? 하고 마지막 쇄기를 박으려는 참에 검색하다가 이곳에서 해답을 찾고 갑니다.

    perm. |  mod/del. |  reply.
  3. semi 2007/06/16 16:38

    저 뒷모습 아름답네요...ㅎㅎ

    perm. |  mod/del. |  reply.
    • NOhungry 2007/06/18 15:53

      어라~?ㅎ
      부장님께 해외로 어학연수 갔다는 소식은 들었습니다만..
      어떻게 잘 지내고 계신지 모르겠네요..^^

      날씨도 더운데 건강 조심하시고, 네이티브 스피커가 되시길
      바래요.ㅎ

  4. wafe 2007/06/18 13:40

    트랙백이 잘 안돼서 수동 트랙백입니다. ^^;

    http://wafe.kr/entry/DirectX-SDK-DirectShow-Platform-SDK

    perm. |  mod/del. |  reply.
    • NOhungry 2007/06/18 15:52

      찾아주셔서 감사합니다..^^
      저는 트랙백이 날아가더군요.ㅎ 그래서 날렸습니당.

  5. elkiss 2007/10/10 10:25

    전에 위내용 퍼간사람입니다. 아무말없이 퍼가서 죄송합니다.
    어디에 멘트를 남겨야할지 몰라서요.
    앞으로도 종종들르겠습니다. 좋은내용감사합니다.

    perm. |  mod/del. |  reply.
    • NOhungry 2007/10/10 22:21

      아.. 그 분 이셨구나.

      글 내용은 퍼가는건 괜찮습니다만.. 제 사진이 떠서 깜짝 놀랐었죠. (물론, 얼굴은 나오지 않지만-ㅁ-)

      암튼, 방문해주셔서 감사합니다^^

  6. KID 2007/10/16 20:02

    헛.. 나도 예전에 할땐 잘 됬던거 같은데..
    #1과 같은 이유로.. 완전 우울해하고 있다가.. 검색했는데..-_-;;;
    니 블로그가 나와서 놀랬다..
    암튼 뭐.. 나도 해결했다. 쿠쿡..

    perm. |  mod/del. |  reply.
  7. 마틴 2009/06/13 11:10

    DirectX SDK 관련 검색하다가 우연히 들렀다 갑니다... 라고 답글 쓰려는데,
    위너 테익스 잇 올이라는 블로그 이름이 눈에 띄어,
    히바히바가 예전에 이 이름을 썼었지 하고 있었는데,
    글쓴이가 노헝그리라... 그때까지만해도 참 신기하다고 생각했는데,
    답글들을 보니......

    용민아... 오래간만이다. ^^*

    perm. |  mod/del. |  reply.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]

요점만 얘기하자면, 우리는 윈도우즈에서 메시지 핸들링을 하기 위해 윈도우 프로시저(콜백 함수)를 쓰곤 합니당.  

일반적으로 이 윈도우 프로시저를 이용해 메시지를 처리하는 스타일에는 다음과 같은 것들이 있져.


이 방법을 쓰는 사람은 극히 많지는 않겠지만(책의 예제를 따라하는 경우 정도?), 콜백 함수 내에서 쓸데 없는 변수 선언으로 인한 스택의 낭비.. (위의 예 같은 경우엔 메시지의 개수가 극히 작지만, 메시지의 개수가 늘어나면 그만큼 리소스가 더 낭비되는...), 그리고 일관성이 떨어져 가독성에도 방해가 되죠.

이 방법은 윈도우 프로시저를 가볍게 했지만, 호출 함수의 일관성이 떨어집니다. 다시 말하면, 프로젝트마다 각기 다른 함수가 만들어지겠죠. 예를 OnSize 함수의 경우, 때에 따라서 파라미터로 LPARAM만 필요할 수도 있고, HWND도 필요할 수가 있습니다.

그럼 이제 설명하고자 하는 메시지 크래커~!

매우 짧아진 윈도우 프로시저, 각각의 메시지 핸들러는 항상 동일한 형식만으로 사용되죠. 그리고 윈도우 프로시저 내에서 동일한 매크로를 이용하기 때문에 가독성도 좋아집니다.

하지만 메시지 크래커도 굳이 단점을 찾자면,
첫째, HANDLE_MSG 매크로를 사용하기 위해 항상 windows.h를 include 해야 한다.
둘재, windows.h로부터 함수 원형을 복사해서 써야한다는 점입니다. (귀차니즘..-ㅁ-)


그래도, 비효율적이고 가독성이 나빠지는 것보단 낫다는 생각이 듭니다.

그럼, 사용법은?

1. windows.h 를 include 합니다.
2. 윈도우 프로시저에 HANDLE_MSG 매크로를 추가합니다.
3. windows.h 파일을 열어 ctrl + f를 이용해 메시지(EX: WM_CLOSE)를 찾아, 함수 원형을 찾습니다.

4. 주석으로 처리된 함수 원형 부분 중 Cls_를 뺀 나머지 부분을 복사해서 소스코드에 함수 정의부와
선언부에 붙여넣기를 해서 씁니다.

5. OnClose() 함수 내에 처리하고자 하는 루틴을 추가합니다.

덧 1.) 메시지 크래커에 관한 더 많은 내용은 "김정훈 저, [TCP/IP 소켓 프로그래밍]"과 웹 검색을 통해 찾을 수 있습니다.-ㅁ-;

크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/74

Comments

  1. acaran 2007/04/18 22:19

    항상 자네한테 많이 배우는구려~ 난 프로그래밍이 뭔지 점차 잊어가고 있소 ㄷㄷㄷ-_-

    perm. |  mod/del. |  reply.
  2. NOhungry 2007/04/20 12:49

    acaran// 어이쿠, A+ 클럽이 낳은 희대의 천재 프로그래머인 자네가 별 겸손한 소리를 다하는구려-ㅁ-

    perm. |  mod/del. |  reply.

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]


이 코드를 사용하기 위해서는... 다음과 같은 헤더파일들을 include 해주어야 한다.
#include <windows.h>
#include <IPHlpApi.h>

또한, IPHIpApi.lib 파일을 찾아 링크를 걸어줘야 함..

예제 코드 보기...

크리에이티브 커먼즈 라이센스
Creative Commons License

Trackback

Trackback Address :: http://www.nohungry.net/tt1/trackback/50

Comments

What's on your mind?

댓글 입력 폼
[로그인][오픈아이디란?]