'MFC 뜯어보기'에 해당되는 글 51건

  1. 2002.08.09 #50. Serialization과 관련된 MFC의 3대 매크로 함수
  2. 2002.08.01 #49. CImage 클래스
  3. 2002.07.24 #48. Serialization이 가능하도록 CObject 클래스 상속 (원제: .NET에서의 CObject 클래스 상속)
  4. 2002.07.19 #47. Managed Extensions for C++의 새로운 문법들
  5. 2002.07.18 #46. Managed Extensions
  6. 2002.07.01 #45. 어플리케이션 디버깅 (Quick Watch, Watch)
  7. 2002.07.01 #44. 어플리케이션 디버깅 (Break Point)
  8. 2002.07.01 #43. 어플리케이션 디버깅 (Call Stack)
  9. 2002.06.25 #42. 서브 시스템의 비밀
  10. 2002.06.25 #39. 콘솔 어플리케이션에서의 MFC 사용
  11. 2002.06.20 #41. Windows NT에서의 디버그
  12. 2002.06.20 #40. MFC에서 콘솔 명령어 처리하기
  13. 2002.06.16 #38. 일관성있는 클래스/리소스 배치
  14. 2002.06.16 #37. 왜 데이터 타입 클래스를 만들때 CObject에서 상속받는가?
  15. 2002.06.16 #36. _T("") 매크로에 대하여
  16. 2002.06.13 #35. Microsoft Windows 정보 대화 상자 사용하기
  17. 2002.06.11 #34. MDI vs. SDI
  18. 2002.06.08 #33. HTTP 프로토콜로부터 HTML 파일 가져오기
  19. 2002.06.08 #32. Windows 공용 DLL에서의 데이터 타입
  20. 2002.06.08 #31. MFC 전용 확장 DLL의 작성
  21. 2002.06.04 #30. 클래스에 대한 정보를 프로그램상에서 활용하기
  22. 2002.05.23 #29. 메시지 스트림 가로채기
  23. 2002.05.17 #28. Dynamic Link Library의 사용법
  24. 2002.05.15 #27. CObArray 클래스
  25. 2002.05.10 #26. WYSIWIG (What You See Is What You Get)의 구현
  26. 2002.05.08 #25. 폰트 빨리 다듬어놓기
  27. 2002.05.06 #24. Seriailization (직렬화) 란? (2nd.)
  28. 2002.05.03 #23. 파일 시스템에 대한 정보...
  29. 2002.05.02 #22. Seriailization (직렬화) 란? (1st.) (4)
  30. 2002.04.30 #21. DLL에 대한 의문점들...
Visual C++2002. 8. 9. 21:20

Serialization을 구현하기 위하여 우선 가장 기초가 되어야할 사항은 새로운 클래스를 반드시 CObject 클래스로부터 상속받아야 하는 점입니다. 하지만, 이것이 다는 아니며 약간의 작업이 더 필요하다는 것은 잘 아실 것입니다.

어떤 목적의 클래스인지에 따라서 적절한 매크로 함수를 사용해야 할 것입니다. 그래서, 세 가지 종류로 구분이 되어있습니다.

  1. IMPLEMENT_DYNAMIC(), DECLARE_DYNAMIC(): CRuntimeClass를 통한 런타임 클래스 정보를 사용할 수 있도록 필요한 선언을 매크로 함수 한 줄로서 자동으로 추가할 수 있도록 만들어줍니다. DECLARE_DYNAMIC(현재 클래스 이름): 이것은 클래스의 선언부 (헤더 파일)에서 직접 써주시면 자동으로 관련된 내용을 클래스에 선언해줍니다. IMPLEMENT_DYNAMIC(현재 클래스 이름, 상위 클래스 이름): 이것은 클래스의 소스 코드 부분 (CPP 파일)의 상단부에 기재하여 주시면 됩니다.
  2. IMPLEMENT_DYNCREATE(), DECLARE_DYNCREATE() : 런타임 정보와 동적 개체 생성, Assert/Valid 등을 지원합니다. 사용 방법은 역시 동일합니다.
  3. IMPLEMENT_SERIAL(), DECLARE_SERIAL(): CObject 클래스에서 사용할 수 있는 모든것을 가능하도록 지원합니다. 동적 개체 생성, 직렬화 등등이 있겠군요. 사용 방법은 역시 동일합니다.  
Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 8. 1. 19:02

Windows 기반에서 웹 그래픽을 처리하기 위해서는 이전까지는 JPEG나 GIF 이미지의 Static Library 또는 관련 DLL들을 얻어서 써야 하는 매우 번거로운 작업을 해야만 했습니다. 하지만, MFC 7.0에서는 이러한 수고스러움을 덜어주기 위하여 새로운 클래스를 도입하게 되었는데, 바로 CImage 클래스입니다.

CImage 클래스는 CBitmap 클래스의 확장 개념입니다. 기존의 비트맵 이미지 객체로도 손쉽게 불러올 수 있음은 물론이고 기본적인 수준의 GIF, JPEG, PNG, BMP 이미지를 사용할 수 있으므로 공들여서 웹 그래픽 작업을 번거롭게 하는 일은 없어졌습니다.

여러분은 이미지를 불러들이기 위하여 두 가지 함수를 사용하실 수 있습니다. Load()와 LoadFromResource()라는 함수입니다. Load() 함수는 파일 경로명을 지정하거나 IStream 인터페이스의 포인터 객체를 얻는 방법이 있습니다. 대개의 경우는 파일 경로명을 사용하겠지요. LoadFromResource()는 리소스의 이름 데이터나 리소스 ID를 지정할 수 있습니다.

이렇게 불러들인 이미지는 기존의 CBitmap 클래스처럼 사용하시면 됩니다. 이미지를 출력하기 원하는 DC에 뿌려주기만 하면 됩니다. 비트맵 핸들을 얻어야할 필요가 있다면 연산자 오버로딩이 되어져 있기 때문에 그냥 HBITMAP에 대입해서 쓰면 됩니다.

또한, 알파 블렌딩과 같은 고급 그래픽 효과도 사용할 수 있으니 참고하시기 바랍니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 24. 13:41

Visual C++ .NET, 즉 MFC 7.0에서는 이전 버전인 MFC 6.2보다 편리하게 변경된 사항이 몇 가지가 더 있습니다. 그 중에 하나가 CObject 클래스에서의 직접 상속입니다. 물론 이전에도 아래와 같은 절차를 통하여 상속받는 것을 지원하였지만 .NET 버전에 들어와서부터는 좀 더 처리가 간결해졌다는 뜻입니다.

MFC 클래스를 작성할 때에 클래스 작성 마법사는 상속 가능한 클래스 리스트를 보여줍니다. 이 때에 CObject를 포함한 다수의 새로운 클래스를 제공합니다.

여러분은 여기서 CObject로 상속을 받아서 몇 가지의 작업을 더해주면 CObject와 동일한 기능을 수행하는 또 하나의 여러분만의 새로운 데이터 클래스를 생성할 수 있습니다.

이전에도 작성했었던 방법이지만 MFC 7.0에서도 그대로 사용할 수 있습니다. 아니, 약간 더 구체적으로 정보를 더 알려드리도록 하겠습니다. 클래스의 사용 용도에 따라서 여러분은 선언의 수준을 달리할 수 있습니다.

* DECLARE_DYNAMIC(class_name) 및 IMPLEMENT_DYNAMIC(class_name, base_class_name) : CRuntimeClass* 구조체로 조사가 가능한 일반적인 형태의 런타임 클래스로 만드는데에 필요한 약간의 데이터를 더 포함합니다. #DEFINE 선언이기 때문에, 프리프로세서가 컴파일 직전에 실제 코드로 변환하여 처리하도록 되어있습니다.

DECLARE_DYNAMIC() 선언은 클래스의 선언부에 직접 사용하시면 됩니다. 단 주의하실 점은 DECLARE_DYNAMIC() 선언 그 자체가 액세스 권한 적용 대상이 아니라는 점입니다. 즉, 아래와 같은 선언을 할 경우 컴파일 에러가 발생할 수 있습니다.

    class CExample : public CObject

    {

    public:

      DECLARE_DYNAMIC(CExample)

      CExample();

      virtual ~CExample();

    };

위와 같은 코딩을 올바르게 고치는 방법은, DECLARE_DYNAMIC() 선언을 public: 영역 밖에서 코딩해주는 것입니다.

그리고, DECLARE_DYNAMIC() 선언으로 끝나면 안되며, DECLARE_DYNAMIC()과 연관되는 멤버 함수의 선언을 위하여 IMPLEMENT_DYNAMIC()을 소스 코드 파일 (.cpp)의 프리프로세서 선언문 바로 아래에 넣으셔야 합니다.

* DECLARE_DYNCREATE(class_name) 및 IMPLEMENT_DYNCREATE(class_name, base_class_name) : 이 매크로는 앞서 거론한 DECLARE_DYNAMIC()과 IMPLEMENT_DYNAMIC()의 내용을 포함함과 동시에, CDocTemplate와 같은 클래스에서의 동적 생성 프로세스를 지원하도록 해줍니다.

기본적인 사용 방법은 위와 같습니다. 하지만, 위의 선언을 이미 하였을 경우 그 선언 대신 사용해야 합니다. 그렇지 않으면 컴파일 시 중복 선언 에러를 발생하게 됩니다. 또한 최소한 1개 이상의 기본 생성자가 필요합니다.

* DECLARE_SERIAL(class_name) 및 IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) : 이 매크로는 앞서 거론한 DECLARE_DYNCREATE() 및 IMPLEMENT_DYNCREATE()의 내용을 포함함과 동시에, 직렬화 프로세싱을 지원하도록 해줍니다. 이 선언이 이루어져야 올바르게 Serialize(CArchive& ar) 함수를 재정의할 수 있습니다. wSchema에는 여러분이 임의의 버전을 입력하도록 되어있습니다. 대개 0에서부터 시작하며 프로그램의 메이저 버전을 올릴 때에 같이 올리곤 합니다.

역시 사용법은 같습니다. 중복 선언에 유의할 것과, 최소 1개 이상의 기본 생성자가 요구됨을 주의하면 됩니다.

다음 Chapter에서는 이렇게 선언한 매크로를 어떻게 사용할 수 있는지를 알아보겠습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 19. 19:11

여러분은 Managed Extensions for C++ 프로젝트로 콘솔 프로그램을 작성하기 시작하였을 때 전에는 볼 수 없었던 새로운 키워드와 새로운 객체를 보실 수 있습니다.

우선 오늘은 새로운 키워드에 대해서 알아보도록 할 까 합니다.

1. #using 전처리기 구문

#using은 .NET 프레임 워크의 컴파일러만이 유일하게 감지해내는 전처리기 구문입니다. 이것은 #include와 유사한 성격을 띄지만 좀 더 유연하고 포괄적인 내용입니다.

#using은 *.h 파일과 같은 순수 소스 코드를 불러들이기 위한 것이 아니라 미리 컴파일된 닷넷 프레임워크 DLL을 직접 불러다 쓰거나, 아니면 기존에 누군가가, 혹은 자신이 생성했었던 프레임워크 호환 DLL을 불러다 쓸 때에 사용하는 구문입니다.

이 DLL은 닷넷 개발 툴에서만 사용이 가능하며, 다른 델파이와 같은 개발툴에서는 호환되지 않는 형식의 이진수 체계를 사용합니다. /clr 컴파일러 옵션을 더하고 나서 여러분은 코드의 맨 위나 stdafx.h에 이와 같은 선언을 더해줄 수 있습니다.

#using <mscorlib.dll>

이는 가장 핵심적인 닷넷의 기능을 축약해 담은 내용이 컴파일된 DLL을 로드하겠다는 의미입니다. 실제로 mscorlib.dll 파일은 존재하는 파일입니다.

2. 네임스페이스 객체와 namespace 키워드

네임스페이스라는 객체는 닷넷의 유일무이한 트레이드마크입니다. 네임스페이스 그 자체는 별 의미가 없으며 단지 클래스나 또 다른 네임 스페이스를 포함하기 위한 기능을 가질 뿐입니다.

이 네임스페이스는 파일 시스템의 디렉터리 구조와도 같아서, 클래스 이름이 동일하더라도 네임스페이스의 위치가 다르면 완전히 다른 클래스로 분리가 됩니다. 이에 따라서 클래스에서도 전역 클래스와 로컬 클래스로 다시 구분되어졌습니다.

이 네임스페이스 객체를 생성하기 위해서 여러분은 단지 namespcae 이름 {으로 선언을 시작해서 }; 로 선언을 끝내기만 하면 됩니다.

3. 네임스페이스 객체에 접근하는 방법은?

네임스페이스를 별도로 객체로 선언하여 접근한다는 생각을 하셨다면 착각하셨습니다. 올바르게 액세스하기 위해서 반드시 :: (스코프 연산자)를 사용해야 합니다. 별도의 선언 없이는 네임스페이스 내부의 클래스도 :: (스코프 연산자)로 접근해야 합니다.

4. __gc 키워드

__gc가 의미하는 것은 Garbage Collected를 뜻합니다. 하지만 길게 생각할 필요는 없으며 __gc로 선언되는 것들은 모두 닷넷 프레임워크 수중안에서 관리가 이루어지므로 사용자가 수동으로 delete 키워드를 사용해서 제거할 필요는 없습니다. 이 키워드를 사용할 수 있는 대상의 제한은 없습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 18. 21:15

[시작하기 전에]

본 코너는 타 코너보다 늦게 시작하였지만 꾸준히 관심을 가져주시고 읽어주셔서 어느덧 40회 이상의 글 게재 횟수를 기록하게 되었습니다. 본 코너는 방학 중에도 꾸준히 업데이트가 될 것이며, 앞으로도 이곳에서 유용하고 깊이있는 Windows 프로그래밍 정보를 게재하기 위하여 2차 개정안을 시행합니다. 다른 개정 사항은 없으며 아래 사항 한 가지가 있습니다.

* Chapter #46 이후에 기준이 될 주 개발 도구는 Microsoft Visual C++ .NET입니다. 따라서, 기존의 MFC 라이브러리 4.2에 없었던 새로운 클래스나 새로운 기능들이 언급이 될 수도 있습니다.

Visual Studio .NET으로 프로그램을 작성하다보면 전에 보지 못했었던 C++의 새로운 프로젝트 옵션 하나가 보일 것입니다. 바로, Managed Extension for Visual C++이라는 것입니다.

이 Managed Extensions의 특징은 "관리된다"라는 점에 있습니다. 구체적으로 말하자면 다른 언어와의 호환성을 위하여 설계된 CLI (Common Language Infrastructure) 규격에 의거하여 프로그램을 최적화한다는 점입니다. 이렇게 최적화시킨 프로그램은 .NET Framework에서의 사용이 훨씬 간편하고 유연합니다.

기존의 수많은 어플리케이션들이 .NET Framework라는 견인차에 의해서 재사용이 가능한지는 .NET Framework가 발매되기 시작하면서부터 시비거리가 되어왔던 사안입니다. 하지만, Visual Studio .NET에서 그 시비의 종결점을 찾았습니다. 바로 Managed Extensions인 것입니다.

실제로, 관리되는 코드를 사용해야 하는 이유 네 가지를 들 수 있습니다.

첫 번째, 관리되지 않는 기존의 프로그램을 관리 가능한 상태로 변경하여 닷넷 프레임워크 및 인프라와 잘 궁합이 맞는 프로그램으로의 마이그레이션을 하기 위함입니다. 물론, 기존의 기능들을 거의 변경할 필요 없이 언제든지 닷넷 프레임워크만의 기능들을 가져다 쓸 수 있습니다.

두 번째, 다른 .NET 호환 언어로 여러분의 프로젝트 내에있는 클래스나 멤버 함수들을 사용할 수 있습니다. 쉬운 예로 미리 작성해 두었던 기존의 클래스를 Visual Basic .NET이 경유 참조하여 값을 가져다 쓴다거나, Visual C# .NET이 경유 참조하여 값을 가져다 쓴다거나, 혹은 ASP.NET, GTK# (MONO 프로젝트의 독자적인 언어)과 같은 언어등에서도 얼마든지 가져다 쓸 수 있습니다.

세 번째, 이와는 반대로 여러분의 프로젝트가 다른 언어로 작성된 프로젝트의 것을 그대로 참조할 수도 있습니다.

네 번째, 관리됨의 여부에 따라서 완벽히 분리된 두 개의 코드를 하나의 EXE 파일안에 담을 수 있습니다. 다시 말해서, 관리가 되는 코드로 작성을 하였든 그렇지 않았든 그 여부와는 관계없이 프로그램이 알아서 영역을 설정하고 자동으로 변수들을 참조할 수 있도록 해준다는 것입니다.

이 Managed Extensions는 Visual Studio 내의 모든 언어가 다 사용할 수 있습니다. Visual C++ .NET, Visual Basic .NET, Visual C# .NET, Visual J#.NET 등등이 있겠지요.

Managed Extensions를 사용하여 언어를 한데 묶을 수 있습니다. 이는 곧 다른 언어로의 포팅 작업 없이도 닷넷 프레임 워크안에서 프로그램 끼리의 데이터 공유가 매우 편리하고 용이하다는 것을 반증하기도 합니다.

실제로 Managed Extension을 추가하는 방법은 프로젝트 설정에서 할 수 있습니다. 프로젝트 설정에서 Managed Extension을 사용하겠다고 여부를 설정하면 컴파일러는 이 여부를 확인하고 자동으로 컴파일할 때에 Managed Extension에 필요한 참조와 라이브러리, DLL을 추가하여 컴파일을 시작할 것입니다.

자세한 정보는 Visual Studio .NET 설명서를 통하여 보실 수 있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 1. 17:55

이전 Chapter에서 언급했었던 Break Point를 응용할 수 있는 툴입니다.

Quick Watch의 용도는 어떤 변수의 값이 특정 코드에 의하여 올바르게 입력이 되었는지 조회하여 볼 수 있는 도구입니다. 이 도구를 사용하여 여러분이 작성한 코드가 올바르게 동작하였는지 확인해 볼 수 있습니다.

Quick Watch는 디버그 도구 모음중에서 찾아볼 수 있습니다. 별도의 대화 상자가 나타나는데, Expression에서 원하는 변수명이나 변수가 클래스인 경우 빠르게 접근해갈 수 있는 수식을 입력할 수도 있습니다. 변수의 입력 조건은 제한이 없습니다. 즉, 지역/전역의 구분이 없이 직접 존재하는 변수명만 입력하면 됩니다.

그리고 지속적으로 조사할 변수일 경우, 하단의 Watch 프레임으로 항목을 드래그해서 등록시킬 수 있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 1. 17:44

여러분이 프로그램을 작성할 때에 여러분이 작성하기는 했지만 제대로 수행이 되는지가 의심스러운 부분이 생기는 곳이 있습니다. 혹은, 남이 작성한 클래스나 함수가 올바르게 동작이 되는지 테스트 해보아야 할 때가 있습니다. 이럴 때 여러분은 어떻게 하시겠습니까?

이 Chapter에서 Break Point에 대해서 알고 난 다음 부터는 달리 고민하실 필요 없습니다. 의심스러운 줄에 단지 F9키를 눌러서 Break Point를 걸면 됩니다.

이렇게 Break Point가 걸린 부분을 디버그 모드로 컴파일하고 나서 어떤 기능을 수행하도록 프로그램에게 요청하면 프로그램은 자동으로 Halt 상태로 전환이 되어 Visual Studio의 디버거에 의해서 컨트롤될 수 있도록 바뀝니다.

이 상태에서 여러분은 이전 Chapter인 Call Stack, 다음 Chapter에서 언급하게 될 Quick Watch나 Watch View등 강력한 도구를 자유자재로 사용하실 수 있습니다.

ps (2006年 12月 16日) - Visual C++의 Break Point 작동 원리에 대한 블로그 글도 같이 보시면 좋아요 :-)

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 7. 1. 17:35

MFC용 어플리케이션을 작성하다보면, 이따금씩 Debug Assertion Failed라는 대화 상자와 쉽게 마주치곤 합니다. 이런 대화 상자들이 생기는 원인은 간단한 경우일 수도 있지만 매우 복잡한 경우가 될 수도 있습니다.

문제가 있는 코드를 일일이 눈으로 훑어보면서 찾아내는 작업도 디버깅입니다. 하지만, 이것은 프로그램의 규모가 커지면 커질 수록 부적절한 방법이 됩니다. 이런 부적절하고 비 효율적인 디버깅은 별 쓸모가 없습니다.

프로그램의 어떤 기능이 수행되기 위해서 수행되어진 내역들을 차근차근히 모아놓고 있는 스택 스토리지가 디버그하는 도중에 자동 생성되어 알아서 동작하게 됩니다. 이 스택의 이름은 호출 스택 (Call Stack)이라고 합니다.

이 호출 스택 내역을 조회해보면 어떤 부분에서 문제가 발생하게 되었는지 단번에 파악할 수가 있습니다.

호출 스택에 내역을 저장하고 조회하기 위해서는 디버그 모드로 프로젝트를 컴파일해야 합니다. MFC 완벽 가이드를 구매하면서 받으셨던 부록 CD의 디버깅 편에 대한 예제가 담긴 프로젝트를 열고 컴파일하십시오.

특정 부분에서 "Debug Assertion Failed"라는 대화 상자가 나타날 것입니다. 여기서, "Retry"을 선택하여 디버그를 시작하십시오. 어떤 부분에서 문제가 생겼음을 정확히 알려줄 것입니다. 하지만, 여러분은 이곳에서 무엇을 잘못 작성한 것인지 알 길이 없습니다. 즉, 별로 도움이 되지 않는 정보라는 점이죠. 하지만, 포기하지 마시고, 디버그 도구 모음에 표시된 아이콘 들 중에서 "Call Stack" 항목을 선택하십시오. (아이콘 위에 잠시 포인터를 대면 툴팁 설명이 나타나는데 이 설명의 이름이 "Call Stack"인 항목을 선택하십시오.) 그러면 자그마한 팝업창과 함께 리스트가 나타납니다. 아래로 갈 수록 먼저 수행되어진 기능들이며, 맨 위의 부분이 문제가 생긴 부분입니다.

여러분이 수행한 기능은 대개 2~3단계 뒷쪽에 기록되어져 있습니다. 여러분이 작성한 클래스의 이름이 등록된 항목을 더블 클릭하십시오. 무엇이 문제인지 확인하실 수 있습니다. 이제, 디버그 도구 모음에서 디버그 중단 아이콘을 클릭하여 다시 개발자 환경으로 돌아오신 다음 문제가 생긴 코드를 고쳐서 다시 빌드하십시오.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 25. 21:37

Windows 기반의 어플리케이션들은 일반적으로 Win32 커널이 띄워져있는 상태에서 수행되도록 설계가 되어있습니다. 만일, 순수한 16비트 상태의 Native MS-DOS나 MS-DOS와 호환이 가능한 FreeDOS나 DR-DOS, 혹은 OS/2 콘솔 등에서 Windows 기반의 어플리케이션을 수행하려고 하였을 때에 여러분은 다음과 같은 에러 메시지를 접할 수 있습니다.

This program cannot be run in DOS mode.

이러한 에러 메시지를 접할 수 있는 이유는 매우 당연한 사실입니다. 하지만, 이 에러 메시지를 그냥 무시하고 지나치지 맙시다.

Windows 95 이상의 배포 패키지의 설치 부트 스트랩 파일들을 살펴봅시다. Windows 95, 98, Me에서 수행되는 것은 물론이거니와 Windows 3.1, MS-DOS에서도 수행이 됩니다. 이것이 가능한 이유가 무엇일까요? MS사만의 편법? 아니면 MS사만의 기술적 노하우? 아닙니다.

의외로 간단한 비밀이 있습니다. 바로 서브 시스템이라고 하는 부분인데, 서브 시스템은 현재 컴퓨터 시스템에 수행중인 운영 체제나 환경에 따라서 프로그램을 구동시켜주는 부분입니다.

일반적으로 Windows 어플리케이션들은 32비트 기반의 Windows 환경이나 16비트 환경이지만 32비트 DLL을 사용할 수 있는 환경이 갖추어진 상태 (Windows 3.1 시스템에 Win32s 패키지를 설치한 경우...)에서 수행되도록 설계되어있습니다.

하지만 특정 프로그램에 의하여 서브 시스템을 조작한 상태에서 어떤 어플리케이션을 수행하게 되면 그 어플리케이션에 별도의 기능이 포함되어져 있을 경우 그 기능으로 수행이 됩니다. 좀 더 쉬운 말로 하자면, Windows 프로그램이 서브 시스템 조작 트랩에 의하여 MS-DOS창에서 수행되는 프로그램으로 전환되는 것이 가능하다는 점입니다.

이에 관련된 예제를 게시해놓았습니다. 잘 검토하여 보시고 분석해 보시기 바랍니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 25. 21:31

일반적으로 콘솔 어플리케이션상에서는 MFC 컴포넌트 및 클래스를 사용할 수 없는 것으로 알고 있었습니다. 하지만, 콘솔에서도 MFC를 얼마든지 사용할 수가 있습니다.

콘솔에서 MFC를 사용할 수 있도록 해주는 방법은 두 가지가 있습니다.

  • 처음부터 MFC 타입 콘솔 프로젝트로 시작한다.
  • 보통의 콘솔 프로젝트에서 MFC 라이브러리를 사용하도록 지정함과 동시에 #include로 필요한 MFC 헤더 파일들을 추가한다.

이 Chapter에서는 2번 방법을 중점으로 하고 시작하도록 하겠습니다.

우선, 예전처럼 우리는 콘솔 프로젝트를 새로 하나 만들어보겠습니다. 그냥 만들던대로 만드십시오. 그러면, 새로운 웍스페이스가 하나 나타나고 좌측의 프로젝트 윈도우에는 Globals 폴더가 나타날 것입니다.

프로젝트가 생성되면, Alt + F7키를 눌러 프로젝트 셋팅 대화 상자를 띄우세요. 그러면, Microsoft Foundation Classes에 대해서 묻고 있는 리스트 박스가 맨 첫 번째 항목으로 보입니다. 여기서, 여러분은 나타나는 세 가지 항목중에 "Use MFC in a shared DLL"을 선택하고 "OK"을 눌러서 이 대화 상자를 종료하시면 됩니다.

이제 여기에 단지 MFC 관련 헤더 파일들을 끼워넣어주는 일만이 남게 되었습니다. 아래는 MFC 관련 내용을 수록하고 있는 헤더 파일들입니다. 원하는 헤더 파일을 알맞게 삽입하시는 것이 컴파일된 바이너리 파일의 용량을 줄여주는 길입니다.

    #include <afx.h> // 가장 기초적인 MFC 요소들.

    #include <afxwin.h> // 윈도우 클래스들.

    #include <afxext.h> // 확장 클래스들.

    #include <afxdtctl.h> // 윈도우 컨트롤 클래스들.

    #include <afxcmn.h> // 윈도우 공용 컨트롤 클래스들.

    #include <afxinet.h> // 인터넷 기능 클래스들.  

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 20. 16:56

Visual C++ 6.0에서는 기본적으로 디버그 모드로 프로젝트를 빌드하게금 설계가 되어있습니다. 하지만, 이러한 디버그 모드는 정말 완벽하게 제 기능을 다 하고 있지는 않습니다. 당장은 체감할 수 없을것이지만 좀 더 큰 프로그램이나 좀 더 깊숙한 어플리케이션을 작성하다보면 디버그 모드가 완벽하지 않다라는 것을 쉽게 접할 수가 있게 됩니다.

무엇이 문제이길래 디버그가 완벽하게 동작하지 않는 다는 것일까요? 바로 디버그 심볼의 유무 때문입니다. 디버그 심볼은 디버그를 하는데에 있어서 정확히 디버그를 할 수 있도록 도와주는 유용한 수단입니다. 특히 이 디버그 심볼들은 Windows NT 환경 (Windows NT 4.0 SP6, Windows 2000 SP2, Windows XP SP1, Windows .NET Servers 등등...)에서 어플리케이션을 작성할 때에는 절대적인 위력을 발휘합니다.

실제로 여러분이 프로그램을 디버그 모드로 빌드하고 디버그 상태로 프로그램을 수행하고 난 다음 종료시켜서 Output에 출력된 메시지들을 읽어보시면 다음과 같은 에러 메시지를 찾아볼 수 있습니다.

    Loaded symbols for 'C:\WINDOWS\SYSTEM\MFCO42D.DLL'

    Loaded 'C:\WINDOWS\SYSTEM\USER32.DLL', no matching symbolic information found.

    Loaded 'C:\WINDOWS\SYSTEM\ADVAPI32.DLL', no matching symbolic information found.

    Loaded 'C:\WINDOWS\SYSTEM\GDI32.DLL', no matching symbolic information found.

    Loaded 'C:\WINDOWS\SYSTEM\KERNEL32.DLL', no matching symbolic information found.

    <이하 생략>

여기서 no matching symbolic information found. 라고 출력된 해당 DLL 파일은 디버그 심볼이 설치되지 않았기 때문입니다.

그렇다면 이러한 디버그 심볼들을 어디에서 설치할 수 있을까요? 여러분이 Visual Studio 6.x 제품의 CD-ROM들 중에서 찾아보실 수 있는 CD 중 Visual Studio 6.0 둘 째 CD가 있습니다. 이 CD안에는 이러한 디버그 심볼들을 포함하여 Visual Studio 6.0을 완전하게 만들어주는 MS사의 툴킷이나 서드 파티 회사들의 유용한 유틸리티들이 포함되어져 있습니다.

그리고 당장 디버그 심볼을 설치할 수 있는 방법은, Visual Studio 6.0 프로그램 그룹에서 Microsoft Visual Studio 6.0 Tools의 Windows NT Debug Symbol Setup이라는 아이콘을 클릭함으로서 설치할 수 있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 20. 16:45

예전의 DOS 프로그램에서는 다음과 같은 함수들을 사용하여 MS-DOS나 Windows의 셸 커맨드를 처리하곤 하였습니다.

int main(int argc, char** argv);

하지만, Windows용 MFC 어플리케이션에서는 일단 기본적으로는 이러한 내용들을 쉽게 처리해주는 기능을 제한적으로만 CCommandLine이라는 클래스를 통하여 처리를 합니다. 하지만 이 클래스로 처리할 수 있는 파라메터는 MFC 어플리케이션과 직접 연결된 기능들, 그러니까 인쇄 기능이나 미리보기 기능, 파일 오픈 등의 기능외에는 다른 것들은 수용하질 못합니다. 그러면, 사용자 정의한 스위치들은 어떻게 처리하는 게 좋을까요?

Windows 전역 변수 중에 (::라는 스코프 연산자를 입력해보십시오.) __argc와 __argv라는 것 두 개가 있습니다. 네, 바로 파라메터죠.

이 파라메터들은 어플리케이션이 처음 수행될 때에 셸로부터 입력받아진 명령들을 고스란히 담아서 저장했다가 어플리케이션이 끝날때까지 보존하고 있습니다. 다시 말하자면, 이 데이터들은 언제 어느때건 사용할 수가 있다는 것입니다.

여러분은 이 데이터들을 CString이나 LPCTSTR과 같은 문자열 버퍼에 복사본을 만든뒤에 그대로 사용하실 수 있습니다. 다음이 그런 예제가 될 수 있을 것입니다.

    CString strParam = __argv[1];

    if(strParam == "/install") AfxMessageBox("/install 발견.");

    if(strParam == "/uninstall") AfxMessageBox("/uninstall 발견.");

    if(strParam == "/run") AfxMessageBox("/run 발견.");

    if(strParam == "/pause") AfxMessageBox("/pause 발견.");

    if(strParam == "/resume") AfxMessageBox("/resume 발견.");

    if(strParam == "/stop") AfxMessageBox("/stop 발견.");

* 참고 : 파라메터임을 나타내기 위하여 일반적으로 '/', '-' 또는 '--'와 같은 구분 기호를 사용해줍니다. 이것은 파일 경로 지정과의 혼동을 막기 위한 하나의 약속같은 것이지요.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 16. 17:47

프로젝트의 규모가 커지고 복합적인 규모로 발전될 수록 각종 리소스나 클래스 파일들의 크기도 점점 방대해지게 됩니다. 하지만, 이러한 것들을 보기좋고 일관성있게 카테고리별로 배치하고 싶다면 어떻게 하는 것이 좋을까요? 바로 "폴더"입니다.

프로젝트 내에서의 폴더 개념은 프로젝트 파일 내에서만 인식할 수 있는 카테고리 구분자입니다. 실존하는 디렉터리 타입의 폴더와는 개념이 다르죠.

프로젝트 윈도우 (좌측의..)에서 새로운 폴더를 만들기 위해서는 오른쪽 버튼으로 폴더를 만들 위치의 바로 윗 항목을 클릭한 다음 "New Folder"를 눌러서 생성할 수 있습니다. 그 다음, 만든 폴더에다가 원하는 클래스를 드래그해서 원하는 폴더까지 끈 후 드롭하면 보기좋게 배치가 됩니다.

프로젝트 윈도우에서는 최상위 항목을 제외한 기타 모든 항목들에 대해서 종속적인 위치를 가지는 폴더를 생성할 수가 있습니다. 즉, 리소스 뷰, 파일 뷰, 클래스 뷰에서 폴더를 쉽게 생성할 수가 있다는 것입니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 16. 01:00

중요하게 읽고 알아두셔야 할 Chapter라고 생각이 됩니다.

매번 어떤 새로운 데이터 클래스를 작성할 때마다 항상 CObject로부터 상속을 받아서 데이터 클래스를 작성해왔습니다. 하지만, 왜 꼭 이렇게 해줘야하는것인가요?

MFC의 구조성을 활용한 아주 좋은 프로그래밍 방법중에 하나라는 사실을 이 Chapter를 통하여 알아가시기 바랍니다.

실제로 MFC로 작성된 프로그램은 표준적인 파일 입/출력을 개별적으로 처리하지 않습니다. 모두 직렬화 (Serialization)이라는 함수 안에 몰아서 처리하는 경우가 대부분입니다. 왜일까요?

프로그램에서 "파일"의 "저장"을 선택해서 저장이 될 수 있는 경우는 직렬화 함수를 제외하고는 없습니다. 다시 말해서, 개별적으로 파일 입출력을 구현하려면 별도의 메뉴를 또 만들어야 한다거나, 수작업으로 특정 위치에서 불러들이게금 해줘야합니다. 즉, 훨씬 불편하다는 이야기죠.

그렇다면 이런 불편함을 겪지 않기 위해서는 직렬화 함수를 사용해야 할텐데, 어떻게 사용할까요? 네. 바로, CObject로부터 상속받아오는 것입니다.

CObject로부터 여러분이 새로운 데이터 클래스를 상속받아오면 몇 가지 정의만으로 충분히 파일의 저장과 열기가 자동으로 이루어지도록 구성할 수 있습니다.

파일 처리의 용이성 다음으로 중요한 이유는 다양한 클래스와의 호환성입니다. CObject는 거의 모든 MFC 클래스의 가장 높은 선조격인 클래스입니다. 이런 선조 클래스를 기반으로 작성된 수많은 클래스들과 당연히도 호환이 됨은 물론 아주 좋은 성능을 보여주게 되어있습니다. 그런 예로, CObList가 있겠지요.

CObject로 클래스를 상속받아서 새 데이터 클래스를 만드는 결정적인 이유는 다름이 아니라 손쉽고 빠른 파일 처리를 위해서라는 점입니다. 그외에, 실제로 CObject로부터 얻게 되는 이점을 따지자면 상당히 많습니다. 나중에 다시 설명하도록 하지요.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 16. 00:49

클래스 위저드나 기타의 MFC용 내부 유틸리티로 CString 변수를 선언하고 나면 항상 초기화 선언에 _T("")라는 명령어가 포함되어있는것을 보아왔습니다. 하지만, 정확히 이것이 무엇인지 개념이 아리송해서 모르고 지나가기가 쉽습니다만, 확실히 정리하죠.

일단 _T("")와 같이 세미콜론이 없는 상태에서 종결되는 구문들이 MFC에서는 다수 존재합니다. 이러한 구문들은 모두 매크로 구문이라고 부르고 있는 것들이며, 몇 줄의 코드나 복잡한 함수식을 간단한 매크로 구문 하나로 압축해놓은 것이 일반적입니다.

이런 매크로 함수들이 리턴해주는 값들은 클래스보다도 주로 Win32 환경에서 쓰이는 데이터타입들을 리턴해주게 됩니다. 예를 들면, 핸들 값이나 LPCTSTR, LPVOID 값들이 그런 것들이죠.

그렇다면, _T("")의 실제 리턴값은 무엇일까요? 바로, 아무것도 들어있지 않은 NULL 상태의 LPCTSTR 변수값입니다. 즉, 초기화를 의미하는 내용이죠.

그러면 CString에서 이 값을 어떤 과정을 통해서 받아들이게 되는지는 자동으로 계산이 나오게 됩니다. 네, 그렇습니다. 바로 연산자 오버로딩에 의해서 처리되죠. CString 선언을 찾아보면 = (Equal) 연산자 오버로딩이 LPCTSTR 또는 CString을 처리하도록 서술되어있습니다.

결국은 아무 값도 없는 LPCTSTR을 CString에 던져준다는 것이 됩니다.

이 Chapter에서 알아두셔야 할 점은 초기화 방법이 때로는 매크로 함수에 의해서 이루어지기도 할 수 있음입니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 13. 18:50

실제로 Microsoft Windows 운영 체제를 구성하고 있는 컴포넌트 프로그램들의 정보 대화 상자를 살펴보면 공통적인 모습을 갖추고 프로그램의 이름과 제작자 정보들을 보여줍니다. 이러한 대화 상자는 어떻게 실행이 되어지게 되는 걸까요?

이 대화 상자 역시도, 글꼴 지정 대화 상자나 파일 작업 대화 상자와 같이 공용 대화 상자의 일종입니다. Windows 운영 체제의 버전은 물론 프로그램의 버전을 같이 표시해 줍니다. 하지만 한 가지 주의해야 할 점은, 이 대화 상자를 사용하여 표시되는 정보는 Microsoft가 소유권을 가지고 있는 것으로 표시가 됨에 유의해야 합니다.

스코프 연산자 (::)로 전역 API 함수들을 리스팅해보면 다음과 같은 꼴의 함수를 찾아보실 수 있습니다.

int ShellAbout(HWND hWnd, LPCTSTR szApp, LPCTSTR szOtherStuff, HICON hIcon);

각 파라메터들에 대해서 설명하겠습니다.

  • HWND hWnd : 모달 윈도우가 띄워질 부모 윈도우의 핸들을 받습니다.
  • LPCTSTR szApp : 제품의 이름이나 프로그램의 제목을 사용합니다.
  • LPCTSTR szOtherStuff : 부가 정보 및 덧말을 넣을 때 사용합니다.
  • HICON hIcon : 프로그램을 상징하는 아이콘의 핸들을 받습니다.

리턴값의 구분에 대해서 설명하겠습니다.

  • 만약 올바르게 창이 띄워지면 TRUE (Win32)를 리턴합니다.
  • 그렇지 않다면 FALSE (Win32)를 리턴합니다.

각 파라메터를 지정할 때에는 아래와 같이 지정하는 것이 일반적입니다. 참고로, 이 Chapter에서 사용될 프로젝트명이 CommonAbout이라고 가정하고 설명을 드리겠습니다.

* HWND hWnd

표준 MFC 프로젝트로 프로그램을 작성하였을 때에는 분명히 어플리케이션 클래스가 존재합니다. 여기서는 CCommonAboutApp 클래스이겠군요. 이 클래스의 멤버 변수 중에는 m_pMainWnd라는 변수가 있습니다. 이것은 어플리케이션을 연결하는 메인 프레임 윈도우에 대한 접근 변수입니다. 즉, 본 프로젝트에서의 CMainFrame 클래스에 연결시킨 것이죠. 또한 CMainFrame 클래스는 본 어플리케이션에서 가장 최상위 부모창에 해당하게 됩니다.

이 함수의 첫 번째 파라메터는 이 CMainFrame과 연결된 부모창의 핸들값을 요구하고 있습니다. 그렇다면 어떻게 이 핸들을 얻어낼 수 있을까요? CMainFrame 클래스의 멤버 함수 중에 GetSafeHwnd()라는 함수가 있습니다. 여러분은 이 함수의 리턴값을 첫 번째 파라메터에다가 직접 기입하시면 됩니다.

* LPCTSTR szApp, LPCTSTR szOtherStuff

원하는 대로 입력하시면 됩니다. 이 두개의 파라메터 모두 _T("") 와 같이 공백을 줄 수 있습니다.

* HICON hIcon

역시 API 함수 중에 LoadIcon이라는 전역 API 함수가 존재합니다. 리소스 ID를 입력받는 버전의 함수 정의에 맞게 파라메터를 준비하여 주시면 됩니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 11. 16:52

요 근래에는 수업 시간에 MDI (Multi Document Interface)에 대해서 실습해 보고 있습니다. 이제까지는 쭉 SDI (Single Document Interface)를 기반으로 작성해 나갔었던 프로그램이 대다수였습니다만, 앞으로 개발하게 될 상용 어플리케이션이나 보편적인 에디터들은 특수한 경우가 아니고서는 대개 MDI로 처리합니다.

MDI와 SDI는 그 모양새와 확장성에서 큰 차이가 드러납니다. 하지만, 프로그래밍 방법이나 클래스의 설정에 있어서도 차이가 있을까요? 아닙니다. SDI 시절 때 프로그래밍하던 방법을 MDI와서도 그대로 쓰십시오. 아무런 문제가 되지 않습니다.

다만, 메인 프레임 윈도우 밑에 딸려있는 자식 윈도우들을 일괄적으로 컨트롤 (Batch Control)하기 위해서 CChildFrame이라는 클래스의 쓰임새를 알아두기만 하면 어려울 것이 하나도 없습니다.

MDI 기반으로 어플리케이션을 작성할 경우, 실제로 SDI때에는 보이지 않았던 몇 가지 항목들이 더 들어가있습니다. 하지만, 어렵게 생각하실 필요는 전혀 없습니다. MDI에서 이상해질 수 있는 인터페이스를 고쳐주기 위하여 등록된 약간의 리소스와 차일드 윈도우들을 띄워줄 수 있는 CChildFrame 클래스의 추가가 전부이니까요.

일단, MDI 기반의 어플리케이션에서는 메인 프레임 아이콘과 도큐먼트 아이콘 두 개로 분리되어 리소스에 저장되어있습니다. 왜냐하면, MDI의 경우 SDI처럼 메인 프레임이 직접 뷰와 도큐먼트를 관리하지 않고 다만 차일드 윈도우들의 디스플레이 영역으로서만 역할을 하기때문이죠. 실질적으로는 차일드 윈도우들이 뷰와 도큐먼트 클래스를 점유하고 있는 것입니다. 그렇기 때문에 차일드 윈도우에 표시해줄 아이콘이 필요한 것이죠.

두 번째로, MDI 기반의 어플리케이션에서는 메뉴 리소스가 두 개가 포함되었습니다. 하나는 차일드 윈도우가 하나 이상 띄워져있을 때의 메인 프레임에 표시될 메뉴이며, 또 하나는 차일드 윈도우가 띄워져있지 않을 때의 빈 메인 프레임 창에서 표시될 메뉴입니다. 이 두 메뉴의 차이는 크게 다르지 않습니다. 뷰/도큐먼트 및 차일드 윈도우에 대한 옵션 설정 메뉴의 유무의 차이입니다.

실제로 수업에서 언급하게 될 클래스는 다름아닌 CChildFrame이란 클래스때문입니다. 이 클래스를 가지고서 여러분은 마음대로, 원하는대로 자유롭게 차일드 윈도우들을 일괄 컨트롤할 수가 있습니다.

이 CChildFrame 클래스는 결국 CMainFrame 클래스와 아주 유사한 꼴입니다. 다만, 윈도우를 로드할 때 차일드 스타일이 미리 적용된 상태에서 로딩이 된다는 점과, 개별적인 프로세스로서 취급되지는 않는 다는 것, 메인 프레임에 종속적이어서 메인 프레임의 실행과 종료에 따라서 띄워진 모든 차일드 프레임 윈도우에도 같은 영향을 준다는 점이 다릅니다.  

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 8. 12:09

이번 Chapter는 MFC 수준에서 쉽고 간편하게 인터넷에 있는 HTML 파일들을 다운로드해오는 방법을 알려드리도록 하겠습니다. 새로운 클래스 두 가지를 알아두셔야 할 필요가 있는데요.

바로, CInternetSession 클래스와 CInternetFile 클래스입니다. 이 두 클래스는 그리 어렵지 않으면서도 친근하게 사용할 수 있는 활용성높은 클래스입니다.

아주 간단한 HTML 파일 액세스 예제를 살펴보도록 합시다.

    CInternetSession isSession;

    CInternetFile* ifFile = NULL; // 포인터일 경우 초기화해야겠죠?

    ifFile = (CInternetFile*)isSession.OpenURL("http://www.naver.com");

위의 세 줄의 코딩은 해당 URL에 액세스할 수 있도록 핸들을 얻어오는 기능을 해줍니다. 이제 남은 것은 실제로 버퍼를 셋팅해서 EOF 시그널 (End Of File Signal)이 검출될 때까지 버퍼로 데이터들을 가져오는 것입니다. 참고로, 한번에 얼마만큼의 바이트를 읽어낼 것인지를 셋팅해 줄 필요가 있습니다.

    ifFile->SetReadBufferSize(4096);

    CString strBuffer;

    for(;;)

    {

      if(!ifFile->ReadString(strBuffer))

        break;

    }

이렇게 얻어진 버퍼는 원하는 대로 다루실 수 있습니다. 특히 CString으로 버퍼를 얻었으니 더욱 간편하겠지요?

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 8. 11:59

일반적으로 공용될 Win32 바이너리 타입의 DLL들은 다른 언어와의 호환성을 위하여 가급적이면 리턴 타입을 Windows가 인지할 수 있는 형태로 컨버젼하여 줄 것을 Microsoft사에서 권장하고 있습니다. 하지만, 어떤것이 Windows에서 인지할 수 있는 것이고 아닌것이고 라는 점을 알아내기가 어려울 것입니다. 실제로, DLL에서 권장되는 데이터 타입들은 주로 핸들을 제외한 32비트형 데이터 타입들이 있으며, ANSI C에서의 데이터 타입들도 권장됩니다.

MSDN 라이브러리나 프로그래밍 바이블 서적을 보면 굉장히 많은 데이터 타입들을 찾아볼 수가 있습니다. 이것들은 모두 ANSI C의 데이터 타입들을 기반으로 하여 재정의된 별명들입니다. 예를 들면 LP라는 키워드가 붙게되는 32비트 데이터 타입들의 경우 Long Pointer를 의미하는 포인터 기호가 붙어있습니다.

다른 언어들도 Win32의 데이터 처리 타입을 기반으로 해서 DLL을 받아들일 수 있도록 설계된 것이므로 충분히 데이터 타입을 어떻게 처리해야 할 것이며 어떻게 언어에 맞게 수용시킬 수 있을지 자체적인 코딩에 의하여 완성되도록 되어있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 8. 11:52

실제로 MFC 어플리케이션을 작성하는 데에 있어서 표준 DLL 보다는 MFC 익스텐션 (확장) DLL이 더 많이 쓰여집니다. 그리고 만들기에도 더 간단하고 유용합니다.

MFC DLL 프로젝트로 DLL을 작성할 경우 여러분은 종전의 MFC용 클래스들을 무리하지 않고 편리하게 DLL로 관리할 수가 있습니다. 예를 들면, CObject로부터 상속받아온 클래스를 사용자 정의해서 DLL로 빼내서 관리할 수 있습니다.

여러분이 실제로 MFC 익스텐션 DLL을 만들 때에 DLL 소스 코드에서 클래스의 정의를 하여줄 때에 단지 AFX_EXT_CLASS 매크로 키워드만을 더해주면 완성됩니다.

클래스명을 CExampleTest라고 정의한 경우 MFC 전용 확장 DLL에 알맞게 선언해 주는 방법은 다음과 같습니다. 이 클래스가 CDialog로 부터 상속을 받았다고도 가정하겠습니다.

class AFX_EXT_CLASS CExampleTest: public CDialog { ... }

이렇게 정의해놓으면 나중에 DLL을 빌드하고 나서 DLL을 사용하게 될 메인 어플리케이션의 프로젝트 디렉터리의 DEBUG 디렉터리에 *.LIB 과 *.DLL 파일을 복사하신 후 원하는 대로 링크해서 쓰시면 됩니다. 기존의 링크 방법을 지원합니다. (암시적/명시적)

참고로 이렇게 만들어진 DLL은 특별히 프로토 타입을 셋팅한다든지 할 필요는 없으며 보통때 사용하던 클래스처럼 연결해서 써주면 정상적으로 동작하게 되어있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 6. 4. 17:04

보통 클래스는 클래스 그 자체로서만 쓰였을 뿐 별도로 정보를 빼낸다든지, 클래스가 차지하는 메모리 점유율이라든지 하는 등의 어려운 내용들은 아주 알기가 어려웠었습니다. MFC 이전까지만 해도. 하지만, 지금 제가 알려드리는 이 팁은 당장은 아니어도 여러모로 나중에 큰 도움이 될 것입니다.

구조체중에 CRuntimeClass 라는 구조체를 알고 계십니까? 그런데 이상한 게 하나 있죠? 접두사가 분명히 C~ 인데, 왜 구조체냐구요? 실제로 MFC 헤더 선언을 찾아보시면 클래스가 아닌 구조체로 CRuntimeClass가 쓰여져 있습니다.

이 구조체는 CObject와 짝을 이루면서 같이 다니는 파트너라고 할 수 있습니다. 즉, CObject 그 자신은 물론이거니와 그 하위의 수많은 클래스들과 당연히 호환되겠지요.

이 CRuntimeClass가 담게되는 정보는 의외로 알기 어려운 정보들입니다. 실제로, 여러분이 프로그램 소스에서만 등장하는 클래스명을 런타임상에서 따로 빼내오기라는 것은 굉장히 골치아픈일일 겁니다. 하지만, 이 CRuntimeClass를 잘 활용하시면 비단 클래스명뿐만 아니라 클래스에 대한 실행중의 런타임 정보를 다 얻을 수 있습니다.

실제로 어떻게 CRuntimeClass를 사용할 수 있는지 예제를 한 번 봅시다. 이 예제 코드에서는, 현재 아래의 예제 코드가 입력된 위치의 클래스명을 얻어내는 기능을 합니다. 여기서의 프로젝트명은 Amazing이라고 합시다.

    CRuntimeClass* rtciInfo;

    rtciInfo = this->GetRuntimeClass();

    AfxMessageBox(rtciInfo->m_lpszClassName);

만약 위의 코드를 CAmazingView에서 입력했다고 가정합시다. 그러면, 여러분은 CAmazingView의 기능 어딘가에서 CAmazingView라는 내용을 출력하는 메시지 박스를 만날 수 있습니다.

또, 만약 위의 코드를 CAmazingDoc에서 입력했다고 가정합시다. 그러면, 여러분은 CAmazingDoc의 기능 어딘가에서 CAmazingDoc라는 내용을 출력하는 메시지 박스를 만날 수 있습니다.

어떻습니까? 단 세 라인만으로 쉽게 클래스 이름을 얻어내었습니다! 그리고 꼭 클래스명이 아니어도 다른 멤버 변수들을 보시면 좀 더 구체적인 정보들을 활용하실 수가 있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 23. 14:28

이미 두 번 이상 메시지 스트림을 가로채는 방법을 강좌에서 설명하였었습니다만, 아직도 이해가 잘 안간다고 느껴지는 분들이 계실법도 해서 여기에 추가 설명을 더합니다.

Windows는 어플리케이션이나 프로세스마다 각각의 개별적인 메시지 큐를 둠으로서 능동적으로 메시지 프로세싱을 구현하도록 설계되었습니다. 이것은 이전의 DOS식의 단방향 런타임 (Single Runtime)과는 대조적인 면입니다.

이런 메시지들은 본래 메시지 큐를 통하여 조건 처리가 되어야 함이 정상이지만 특수한 경우 메시지를 메시지 큐에 들여보내기 전에 빼돌려야 하는 상황이 발생하게 됩니다.

이를 위해서 미리 준비된 오버라이드용 함수가 하나 있습니다. PreTranslateMessage()라는 것으로, 파라메터로는 메시지 태그 구조체가 주어지게 됩니다. 가로챌 메시지 스트림의 양이 많다면 조건문이 길어지게 될 것이며, 간단한 트릭의 수준이라면 조건문이 짧습니다.

간단하게 몇몇의 메시지 가로채기를 구현하고자 한다면 if/else 조건문을, 다량의 메시지 가로채기를 구현하고자 한다면 switch 조건문을 응용하는 것이 좋을 듯 합니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 17. 16:26

어제 DLL에 대해서 처음 만드는 강좌를 하였을 때 아마도 대부분은 감을 잡지 못하고 우왕좌왕하셨을 분들이 많으리라고 예상이 됩니다. DLL이라고 하는 것이 뭐에 써먹는 물건인지 다들 알고 있지만 막상 작성하려고 보니 그 내용이 쉽지가 않아서 걱정을 하시는 것 같습니다. 그래서 DLL을 작성하는데에 있어서 가지게 될 수 있는 의문점을 풀어보고자 합니다.

DLL이라고 하는 것은 그 자체가 Windows에서 다루는 EXE 바이너리와 그 모양새가 닮았습니다. 사실 어떤 프로그래밍 언어이든 어떤 저작 툴이든 EXE 파일은 EXE 파일일 뿐입니다. 그와 마찬가지로 DLL 파일이 어디서 제작되든 어떻게 만들어지는 DLL일 뿐입니다. 어차피 바이너리는 Windows 형식이기 때문에 Windows에서 사용할 수 있는 바이너리 조회 명령어면 다 먹히게 되는겁니다.

DLL을 작성하는데에 있어서 염두해 두실 것은 외부에서 DLL을 액세스할 수 있도록 길문을 틔어줘야만 한다는 것을 잊으면 안됩니다. 그렇지 않는다면 DLL 자체에서밖에는 사용이 안됩니다. 또 한가지는, 다른 언어에서 사용할 수 있도록 하기 위하여 함수 매개변수상에서는 가급적이면 클래스 데이터 형식 말고 ANSI-C 또는 ANSI-C++ 규격에 따르는 데이터 형식을 선언해 주는 것이 좋습니다. 클래스 데이터 형식을 인지하지 못하는 언어가 많기 때문에 특별히 유의해야 하는 것입니다. 그러나 DLL 내부용이라면 상관없습니다.

실제로 여러분은 외부에서 액세스할 수 있도록 길문을 틔워주고픈 함수의 Define (정의) 앞에다가 이렇게만 붙여주면 됩니다.

    extern "C" __declspec(dllimport) 리턴형 함수명(매개 변수, ...);

    extern "C" __declspec(dllexport) 리턴형 함수명(매개 변수, ...);

첫 번째 구문은 DLL을 사용하고자 하는 부분에 지정해주면 되는 것입니다.

두 번째 구문은 접근을 허용해 줄 부분에 지정해 주면 되는 것입니다.

실제로 DLL을 처리하는 설정은 어떻게 해주면 좋을까요? 그것은 여러분의 아이디어를 활용하여 암시적/명시적 연결 중 편리한 것으로 택하여 작성하기만 하면 됩니다. 일반적으로 암시적 연결 방법이 간단한 편입니다. 암시적 연결 방법의 경우 단순히 프로토타입만을 지정해 줌으로서 즉시 사용할 수 있도록 완성됩니다. 명시적 연결 방법의 경우 예외 처리 (Exception)를 사용자 정의할 수 있어서 나름대로 각광을 받는 방법이기는 합니다만 손수 해주어야 할 부분이 많은 편입니다.  

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 15. 17:03

MFC에서 자료를 담는 클래스 중에는 실제로 그 클래스들의 배열을 만든 배열 클래스가 별도록 존재합니다. 그런 배열 클래스들의 기초 템플릿 (형식)이 되는 클래스가 바로 CObArray 클래스입니다. 이 CObArray 클래스를 쓸 줄 알게 되면 나머지는 그 자료형의 특성을 잘 파악하여 CObArray에 사용했던 그대로 이용하면 됩니다.

  • int CObArray::GetSize() const; : 해당 배열에 담겨진 데이터 버퍼들의 수를 구합니다. 예를 들어 5개 배열이 포함되어있으면 여기서는 4를 출력하는데, 리턴되는 정수값은 0부터 시작되는 값입니다.
  • int CObArray::GetUpperBound() const; : 해당 배열의 가장 마지막 배열 번호를 구합니다. 이 함수의 리턴값 역시도 0 기반의 정수값이며, 만약 리턴값이 -1이면 해당 배열 객체에 아무런 내용이 없음을 의미합니다.
  • void CObArray::SetSize(int nNewSize, int nGrowBy = -1); : 해당 배열에 최대로 저장될 수 있는 배열의 갯수를 수동으로 지정합니다. 첫 번째 파라미터는 갯수를 이야기하며, 두 번째 파라미터는 몇 번째 배열부터 자동으로 작업이 이루어질지를 결정하는 부분으로 생략하면 처음부터 데이터가 등록되도록 수행됩니다. 또한 예외 처리를 위하여 throw(CMemoryException); 으로 예외 사항을 던질 수 있습니다.
  • void CObArray::FreeExtra(); : 사용하지 않는 소모되는 나머지 버퍼들을 모두 해제시켜 메모리를 절약할 수 있는 함수입니다.
  • void CObArray::RemoveAll(); : 배열 전체의 데이터를 한 꺼번에 날려버릴 때 사용합니다. 신중을 기해서 사용해야만 합니다.
  • CObject* CObArray::GetAt(int nIndex) const; : nIndex 번째 배열로부터 값을 추출해 옵니다. 리턴형은 CObject* 형으로 배열이 담고 있을 데이터 형이 어떤 것인지에 따라서 다음과 같이 달라지게 됩니다.
    • BYTE CByteArray::GetAt(int nIndex) const;
    • DWORD CDWordArray::GetAt(int nIndex) const;
    • void* CPtrArray::GetAt(int nIndex) const;
    • CString CStringArray::GetAt(int nIndex) const;
    • UINT CUIntArray::GetAt(int nIndex) const;
    • WORD CWordArray::GetAt(int nIndex) const;
  • void CObArray::SetAt(int nIndex, CObject* newElement); : nIndex 번째 배열에 CObject* newElement 데이터를 직접 대입합니다. 어떤 데이터형을 담는 배열인지에 따라서 다음과 같이 달라지게 됩니다.
    • void CByteArray::SetAt(int nIndex, BYTE newElement);
    • void CDWordArray::SetAt(int nIndex, DWORD newElement);
    • void CPtrArray::SetAt(int nIndex, void* newElement);
    • void CStringArray::SetAt(int nIndex, LPCTSTR newElement);
    • void CUIntArray::SetAt(int nIndex, UINT newElement);
    • void CWordArray::SetAt(int nIndex, WORD newElement);
  • CObject*& operator[](int nIndex);
  • CObject* operator[](int nIndex) const; : 이것은 연산자 오버로딩으로서 CStringArray의 사용 예제를 들어서 설명해 보도록 하겠습니다.

    CStringArray m_strADatas;

    m_strADatas.SetSize(50);

    for(int i=0; i<50; i++)

    {

      switch(i)

      {

      case 0:

        m_strADatas[i].Format("This is an example how to use CStringArray Object. And It is %dst element.", i);

        break;

      case 1:

        m_strADatas[i].Format("This is an example how to use CStringArray Object. And It is %dnd elements.", i);

        break;

      case 2:

        m_strADatas[i].Format("This is an example how to use CStringArray Object. And It is %drd elements.", i);

        break;

      default:

        m_strADatas[i].Format("This is an example how to use CStringArray Object. And It is %dth elements.", i);

        break;

      }

    }


이와 같은 Array 클래스 외에도 리스트 클래스등이 있는데 그것은 다음 강좌에서 설명하겠습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 10. 16:47

Windows가 나름대로의 비난을 받아오기는 하였지만 사용자나 개발자를 위하여 편리한 기능을 제공한 부분만큼은 비난할 수가 없을 것입니다. 그런 대표적인 예로 WYSIWIG (What You See Is What You Get), 즉 보이는 그대로 얻을 수 있다라는 말을 알아둘 필요가 있을 것입니다.

WYSIWIG을 위해서 동원된 개념들은 굉장히 많이 있습니다. 기존의 비트맵 폰트에서 트루 타입 폰트로, 기존의 비트맵 이미지에서 벡터 이미지로, 통일된 단일 장치에서의 맵핑 모드 전환 등등... 셀 수 없이 많이 있을 것입니다.

실제로 MFC 프로그래밍을 하면 WYSIWIG의 참된 면모를 맛볼 수가 있습니다. 근간에 강좌했던 Device Context에서의 맵핑 모드 (그리기 단위) 변경을 이용하여 해상도와 무관한 출력을 보여주는 것을 확인하였습니다.

실제로 맵핑 모드라고 하는 것은 굉장히 어려운 그래픽 개념 중에 하나이기 때문에 굉장히 생소하거나 쉽게 이해하기가 어려울 수도 있겠지만 그 나름대로의 독창적인 원리가 있다고 생각하시면 쉽습니다.

맵핑 모드를 변경함을 이르는 것은 곧 지도에서의 축도를 가리키는 이야기입니다. 쉬운 예제를 들어, 1:1000 비율의 지도에서의 5cm와 실사의 5cm는 분명히 다른 것입니다. 하지만 이것을 동일 단위로 맞추어 주는 것이 바로 맵핑 모드의 기초 개요입니다. 화면과 프린터사이의 관계를 알아볼까요?

모니터와 프린터는 Windows에서는 닮은꼴의 Device Context를 사용합니다. 실제로, 모니터 또는 프린터의 컬러 프로필 파일을 서로 공유할 수 있으며 전문적인 그래픽 편집가들은 최상의 컬러 프로필 파일을 프린터와 모니터 양쪽에서 공유해서 사용하도록 설정하고 작업을 합니다. 이런 것이 가능한 이유는 양쪽 장치 모두 닮은꼴의 Device Context를 사용하기 때문입니다. 컬러 프로필이라고 하는 것에 대해서는 후단락에서 설명하겠습니다.

여하간, 이러한 형태로 모니터와 프린터는 닮은꼴의 Device Context를 사용하고 있기에 모니터 DC나 프린터 DC나 수행 가능한 작업은 같다라는 의미입니다. 하지만, 문제점이 있습니다.

모니터의 해상도는 평균 1024 * 768 수준입니다. 하지만 프린터의 해상도는 이보다 배를 초과할 수도 있으며 모니터와 비교가 안되는 해상도를 지닙니다. 이로 인해서 데이터를 전송받아서 표현할 때 모니터에서의 픽셀 사이즈와 프린터에서의 픽셀 사이즈는 해상도 차이 때문에 완전히 다른 크기로 보여지게 됩니다. 이것을 통하여 알 수 있는 점은, 픽셀이라는 단위가 가변적인 단위라는 것입니다.

그렇다면 이 문제를 해결하기 위해서는 어떻게 해야 할까요? 다른 것은 없습니다. 모니터 DC쪽에 픽셀 말고 다른 고정적인 또는 불변적인 단위를 사용하도록 하면 될 것입니다. 예를 들면, 인치나, 피트, 센티미터와 같은 것들이 있겠죠.

모니터 DC에 지정함으로서 프린터 DC에도 자동적으로 지정이 가능한 것은 실제로 MFC에서 미리 코딩해 놓은 부분입니다. 즉, 프로그래머는 뷰 클래스의 OnDraw(CDC* pDC)에서 맵핑 모드만을 변경해 주면 되는 것입니다.

맵핑 모드를 변경한다는 것의 결론은 불변인 고정 단위로서 데이터를 표현한다는 데에 있습니다. 또한, 그 단위에 알맞는 좌표 체계를 사용하고 있다는 점에 그 특징이 있습니다.

그리고 아까전에 언급하였던 컬러 프로필이라는 것에 대해서 설명드리겠습니다.

컬러 프로필이라는 것은 일반적으로 모니터나 프린터 드라이버 디스켓 또는 CD-ROM에 포함되어있는 것으로 좀 더 실사와 가까운 색감을 표현하기 위한 색상 데이터 베이스라고 할 수 있습니다.

컬러 프로필은 해당 장치의 성능과 조율을 이루면서 최적화가 되어있어야 제 구실을 합니다. 만약 올바르지 않거나 전혀 연관성이 없는 컬러 프로필을 적용시킨다면 이는 컬러 프로필을 적용시키지 않은것 보다 훨씬 못할 수도 있음을 주의해야 합니다.

모니터 및 그래픽 카드에 적용할 컬러 프로필을 설정할 수 있는 곳은 디스플레이 속성에서의 고급 설정에서 "색 관리" 탭을 선택하면 추가/제거 할 수 있습니다. 여기서 컬러 프로필을 다중으로 사용할 수도 있습니다.

프린터에 적용할 컬러 프로필은 적용할 프린터의 등록 정보 부분에서 찾을 수가 있습니다. 역시 "색 관리" 탭을 선택하면 나타나게 됩니다.

컬러 프로필을 전문적으로 관리하는 프로그램은 Adobe Photoshop의 응용프로그램으로 설치되는 컬러 프로필 에이전트로, 전문적인 컬러 프로필을 설정할 수 있습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 8. 16:50

폰트 객체 하나를 쓸려고 LOGFONT를 사용하여 일일이 A부터 Z까지 속성을 다 지정해줘야 했던 귀찮은 점을 해결하는 방법이 없을까 하고 고민하시는 분들이 계신 것 같아서 팁으로 올립니다.

보통 LOGFONT 구조체나 CFont 클래스를 사용해서 폰트를 지정해왔습니다만 여간 불편한게 아니죠. 이럴 때에 빨리 써먹을 수 있는 CFont 클래스의 멤버 함수가 있는데 CreatePointFont() 라는 함수가 있습니다. 함수 사양을 살펴보도록 하지요.

BOOL CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL);

일단 리턴은 불리언 타입이니까 void처럼 그냥 쓰시면 되구요 Exception 처리를 위해서 조건문이나 조건식을 사용하셔도 됩니다. 하지만 일반적으로 폰트 생성에 실패할 일은 드무니까 신경 안쓰셔도 됩니다.

주어진 파라메터들을 보면 이렇습니다.

    int nPointSize : 글꼴의 크기를 지정합니다. (단위 : 포인트, pt)

    LPCTSTR lpszFaceName : 글꼴의 이름을 지정합니다. (유니코드 문자 사용 가능)

    CDC *pDC : 로직 유닛을 변경하고자 하는 DC의 주소값을 던져주면 되고 단순한 글꼴 생성이라면 이 파라메터를 NULL로 설정하든지 그냥 생략하든지 상관없습니다.

이렇게해서 만들어진 폰트를 로그 폰트로 추출해 낼때는 어떤 멤버 함수를 사용할까요? 바로, GetLogFont()입니다. 함수 사양을 살펴보도록 하지요.

    int GetLogFont(LOGFONT* pLogFont);

    • LOGFONT* pLogFont : 값이 저장될 로그폰트 구조체의 주소값을 던져주면 됩니다.

리턴값이 int이므로 역시 void처럼 사용하되 예외 처리를 하고 싶다면 다음 사항에 유의하십시오.

  • 올바르게 변환이 되었으면 0을 내보냅니다.
  • 그렇지 않을 경우 0이외의 아무값이나 내보냅니다.

이렇게 해서 구해진 로그폰트 구조체를 가지고 테스트를 해보면 아주 만족스러운 결과를 얻을 수 있을 것입니다. 빠른 폰트 생성을 위한 요령이니 앞으로도 많이 활용하시기 바랍니다. 또한 이런 일련의 팁을 함수화시켜서 클래스 갤러리에 등록시켜놓는것도 유용한 방법일 것입니다.

좀 더 응용한다면 이런 방법 대신 CFontDialog라는 Windows 공용 대화 상자 클래스를 사용해서 받아내면 더 유용할 것입니다.  

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 6. 16:58

어떤 뷰를 사용하느냐에 따라서 프로젝트에 생성되는 Document 클래스에서의 직렬화 방법이 모두 달라지게 되어있습니다. 각 뷰마다의 특성을 최대한 잘 살린 직렬화 방법을 이용하여 최적화된 파일 스토리지 또는 파일 로드 코드를 완성할 수 있도록 해줍니다.

CView나 CScrollView와 같은 경우 모두 Device Context를 사용하게 되어있습니다. 이런 뷰에서의 직렬화 방법은 가장 손쉬운 편집 방법을 제공하여 줍니다. 또한 직렬화의 의미를 가장 확실히 알 수 있는 뷰이기도 합니다.

이와 같은 뷰에서는 오버라이드된 직렬화 함수에 다음과 같은 조건문이 서술되어있습니다.

    if(ar.IsStoring())

    {

    // Add storing code here

    }

    else

    {

    // Add loading code here

    }

직렬화 함수에 주어진 파라메터로서는 CArchive &ar 이라는 것이 있는데 이것을 사용하여 직접 직렬화를 하게 되어있습니다. 그렇다면, 실제로 여기에 어떤 직렬화 구문을 사용해야 하는지 알아보겠습니다.

CArvhice 클래스의 연산자 오버로딩 중에는 <<와 >>같은 연산자를 사용하도록 되어있습니다. 이것은 데이터 스트림을 가리키는 연산자로서 이전에 TC++에서 cout에서 사용되어졌던 것입니다. 그 때 사용했던 기억을 되살리면 쉽게 사용이 가능합니다.

예를 들어 도큐먼트 클래스에 저장된 좌표 변수가 존재한다고 하였을 때 저장 과정시 사용되는 직렬화 코드는 다음과 같습니다.

ar<<m_nPointData;

그리고 이것은 다시 아래처럼 로딩이 가능합니다.

ar>>m_nPointData;

즉, 데이터 스트림을 어떻게 흘려보내느냐에 따라서 직렬화의 의미가 달라지게 되는 것입니다. 가장 이해하기가 편리하고 수월한 직렬화 구문이라고 할 수 있겠습니다.

실제로 적용된 조건문을 살펴보도록 합시다.

    if(ar.IsStoring())

    {

    // Add storing code here.

    ar<<m_nPointData;

    }

    else

    {

    // Add loading code here.

    ar>>m_nPointData;

    }

참고로 이러한 직렬화 과정은 파일 처리에서 가장 중요한 부분이며 이것만 완성해주면 실제로 파일 다이얼로그를 띄워준다거나 하는 사용자 정의 프로그래밍 과정이 특별하지 아니한 경우에는 전혀 필요없게 됩니다.

다음 강좌에서는 CEditView와 같은 텍스트 전용 처리 뷰에서의 직렬화에 대한 내용을 다루겠습니다.  

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 3. 17:06

어떤 운영 체제를 사용하든 해당 운영 체제는 그 운영 체제의 내부 커널이나 핵심 서비스들이 하드 디스크를 인지할 수 있도록 일종의 공간을 제공해줘야 합니다. Microsoft Windows, Linux Kernel 2.4.x, Solaris, BSD Family 등등 모두 이들은 각자의 고유 파티션을 가지고 있습니다. 그 중 Microsoft Windows의 파일 시스템에 대하여 알아보기로 하겠습니다.

Windows에서 지원하는 파일 시스템은 이런 것들이 있습니다.

File Allocation Table (이하 FAT) : 이것은 MS-DOS적부터 전승되어오던 파일 시스템으로 Codename:Memphis때 부터 클러스터 사이즈 및 안정성/보안 개선을 위해 새롭게 32비트 버전 FAT를 재 발매하였습니다.

1바이트 부터 2056MB 미만인 하드 디스크 또는 논리적/물리적 파티션 (디스크를 포함하여)들에 적용되는 FAT 시스템은 16비트 버전의 것으로서 폭넓은 호환성을 제공합니다. FAT16의 경우 이미 다른 운영 체제들에서도 (리눅스, 유닉스, 솔라리스, 매킨토시, ...) 쉽게 인지할 수 있을 만큼 널리 알려져 있습니다.

그리고 FAT32가 적용되는 하드디스크 범위는 2056MB 이상 2056GB 이하의 하드디스크입니다. FAT32도 빠르게 다른 운영 체제들에서 지원하기 시작하여 이제는 FAT 시스템에 대해서는 완벽하게 공유를 할 수 있을 정도가 되었습니다.

이러한 FAT 파일 시스템은 이제 더 개발되지는 않을 것입니다. 왜냐하면, Microsoft가 근간에 Codename:Whistler를 내놓았을 때 부터 본격적으로 Windows 9x (Windows 95, 98, Me)에 대해서는 더 이상 개발하지 않겠다는 의사를 밝혀왔습니다. 이것은 FAT 파일 시스템에 대한 지원도 더 이상은 하지 않겠다라는 의미와 같습니다.

이를 대신하여 근간에 새로이 각광받고 있는 파일 시스템이 있습니다. 바로 New Technology File System (이하 NTFS)입니다.

현재 NTFS 파일 시스템의 버전은 5.0입니다. Windows의 메이저 버전에 맞추어서 같이 개발이 되어왔었습니다. 하지만 아직까지도 NTFS 파일 시스템에 변화가 없는 것을 보면 메이저 업그레이드는 단 한 번도 이루어지지 않았다는 의미와 같습니다.

Windows 2000에서 두 부류로 갈라져서 클라이언트용 Windows 2000의 후속 버전은 Codename:Whistler (Windows XP)로, Server Family는 Codename:Whistler Server (Windows.NET Server Family)로 개발되었으나 실제로 빌드를 확인해 보면 5.0에서 5.1로 마이너 업그레이드된 수준입니다. 곧 NTFS 파일 시스템의 버전도 아직은 5.0이라는 의미입니다.

iexbeta.com과 같은 사이트에서 들려오는 소식에 의하면 Windows 로드맵에 Codename:Longhorn과 Codename:Blackcomb이 새로이 개발됨과 동시에 NTFS 파일 시스템에 대해서도 메이저 업그레이드가 이루어질 것이라고 알려지고 있습니다.

이 NTFS 파일 시스템은 실제로 FAT16/32 파일 시스템에서의 Raw Data 부분은 100% 호환이 됩니다. 하지만, NTFS 고유의 압축, 색인화, 접근 권한등의 제어가 추가된 것이라고 할 수 있습니다. NTFS가 지원하는 파일 시스템의 용량 제한은 구체적으로 언급되지 않습니다. NTFS가 처음부터 단일 하드디스크 용으로 개발된 것이 아니었고 RAID (디스크 어레이라고도 부름)용으로 개발된 것이어서 굉장히 스케일이 큰 파일 시스템입니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Visual C++2002. 5. 2. 17:08

Microsoft Foundation Classes (Application Frameworks, 이하 AFX) 기반으로 작성된 프로그램들은 파일을 저장하고 읽을 때에는 다른 함수들을 별도로 쓰지는 않습니다. 실제로 프로젝트를 열어서 CDocument에 관한 파일 저장 구문은 아무것도 보이지 않습니다. 다만 CDocument 클래스의 멤버 함수인 CDocument::Serialize(CArchive &ar) 외에는 없습니다.

이 함수가 하는 일은 파일을 읽고 쓰고 하는 기능 외에는 없습니다. 어차피 제대로된 직렬화를 대행하는 곳은 다른 어느곳도 아닌 직속 상위 클래스인 CDocument 클래스입니다. 직렬화의 원리에 대해서 설명을 드리겠습니다.

직렬화라는 말 자체가 직렬로 데이터를 처리한다라는 의미를 가진다는 것을 눈치가 빠르다면 쉽게 알아챌 수 있습니다. 데이터를 직렬로 정렬하여 일괄적으로 처리하는 방법입니다. 직렬화된 데이터를 어느 방향으로 (어느 데이터 흐름으로) 흘러서 처리할 거냐는 것이 파일 열기/쓰기의 결정 방법입니다.

직렬화 코딩 시 파일을 열 때와 파일을 저장할 때가 if/else 문으로 구분되어져 처리됩니다. 뷰가 어떤 뷰인지에 따라서 이 직렬화 함수 조건 처리 인터페이스가 달라지게 됩니다. Device Context를 이용해야 하는 어플리케이션일 경우 DC에 그려진 도형 변수들에 대하여 직렬화를 적용시키면 될 것이고 CEditView나 CRichEditView와 같은 텍스트를 취급하는 뷰에서는 직렬화에 대해서 전혀 건드릴 것은 없습니다. 다만, CRichEditView와 같은 경우 직렬화 방법에 대해서 생성자나 직렬화 함수 자체에서 다음 코드를 사용하여 RTF 문서를 처리할 지 텍스트 문서를 처리할 지 지정할 수 있습니다.

CRichEditDoc::m_bRTF = FALSE; // 텍스트로서 직렬화 작업을 한다.

CRichEditDoc::m_bRTF = TRUE; // RTF로서 직렬화 작업을 한다. (기본값)

직렬화를 위해서 따로 작성된 파일 처리 클래스가 있습니다. 이것은 기존의 FILE 구조체나 Win32 파일 핸들러나 CFile 클래스와는 그 의미가 다릅니다.

CArchive 클래스는 어떤 클래스로부터 상속되어진 것이 아닌 그 자체의 클래스일 뿐입니다. 비록 이 클래스가 직렬화 작업때에만 쓰여지는 것은 아니지만 일반적인 경우 직렬화에서 응용됩니다.

CArchive 클래스의 매력적인 특징 중에 하나는 읽어오거나 저장할 파일의 데이터 타입을 자기 스스로가 인지할 수 있다는 것입니다. 예를 들면 처리하고자 하는 파일이 바이너리인가, 텍스트 (스트링)인가를 구분할 수 있습니다.

완벽 가이드에서 네트워크 어플리케이션 작업 예제를 보면 실제로 파일을 네트워크 상에서 주고받을 때 이 CArchive나 이 클래스 밑으로 파생된 전용 클래스들을 이용하게 됩니다. 그 이유는 위에서 언급했던 파일 구분 능력덕인데 네트워크를 조금 더 공부해보면 왜 위에서 언급하였던 구분 능력이 필수적인가를 알 수 있을 것입니다.

이 직렬화를 구체적으로 알아나가기 위해서는 기존의 파일 처리 방법을 잘 인지하고 계셔야 할 것입니다. 또한, Windows의 경우 그 나름대로의 파일 시스템 (FAT (File Allocation Table), NTFS (New Technology File System), NFS (Network File System))의 구조를 잘 파악함은 물론 파일 액세스 법칙 및 우선 순위에 대한 개념을 습득해야 합니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

  1. 좋은 정보 감사합니다...

    덕분에 직렬화의 의미를 알수 있었네요~~^^

    2009.01.06 13:34 [ ADDR : EDIT/ DEL : REPLY ]
  2. 좋은 정보 ㄱㅅ

    2010.03.19 17:04 [ ADDR : EDIT/ DEL : REPLY ]

Visual C++2002. 4. 30. 16:51

아직 DLL에 대해서도 배우지도 않았건만 벌써 DLL을 언급하냐고 하실지도 모르겠습니다. 하지만 나중에 DLL을 사용하실 때에 혼란을 방지하기 위해서 이곳에 미리 게재합니다.

DLL이라고 함은 동적 연결 라이브러리 (Dynamic Link Library)를 가리키는 용어입니다. 이것은 32비트 Windows 및 향후 64비트 Windows에서 가장 잘 돌아가는 공유 라이브러리 시스템입니다.

실제로 여러분이 Windows 프로그래밍을 하다가 보면 프로젝트 규모가 어마어마해집니다. 그런 파일들을 한꺼번에 EXE 프로세스 안에다가 다 집어넣으시겠습니까? 그렇게되면 사용자들로부터 엄청난 원성을 듣게 될지도 모릅니다.

프로그램의 각 카테고리별로 기능을 분류하여 DLL 파일로 가볍고 유연하게 만들어주면 EXE 파일 자체의 용량도 크게 줄어서 1회에 필요한 메모리 분량을 대폭 줄일 수가 있습니다. DLL은 필요할 때, 그러니까 EXE에서 DLL 호출 코드에 도착했을 때에만 불러들여지며 DLL이 필요없다는 시점에서 DLL 로드가 해제되어 메모리 여유 공간을 살립니다.

하지만 지나치게 많은 DLL 파일이 난무할 경우 프로그래머 입장에서는 굉장히 다루기가 곤란한 프로그램이 되어버립니다. 왜냐하면, 해당 DLL을 호출하는 코드의 상세 구문을 알기 위하여 해당 DLL 프로젝트를 또 열어야 하니까요. 또한 디버그 과정도 훨씬 복잡하고 비효율적으로 변모합니다. 이것은 프로그래밍의 능률을 떨어뜨리게되는 요인의 하나에 속합니다.

DLL은 너무 자제해서도, 너무 남용해서도 안됩니다. 무엇이든 적당히 해야 좋은 것이지 좋다고 해서 너무 남용하면 생각지 못한 곳에서 문제가 발생하게 되는 것입니다.

그렇다면 DLL과 EXE파일의 차이가 무엇인지 알아보겠습니다.

AFX (Application Frame Works, MFC) 상에서 작성된 DLL 파일은 실제 EXE파일과 그 구성요소가 동일하지만 초기에 제공되는 클래스나 설정의 차이외에는 없습니다. 심지어는 리소스 (버전 테이블, 대화 상자, 웨이브 데이터, 웹 도큐먼트 등등...)도 그대로 사용이 가능합니다. 프로그래밍도 EXE에서 하시던 그대로 하시면 됩니다. 즉, 차이가 거의 없다는 것을 의미합니다.

하지만 특수한 경우의 DLL이 존재한다는 것을 기억하시기 바랍니다.

  • 유형 1; 16비트 DLL - 예전에 Windows 3.x, Windows for Workgroups 3.x, Windows NT 3.x 상에서 쓰여지던 아주 원시적이고 기초적인 수준의 DLL 파일들입니다. 이것들은 Windows 9x 상에서는 어느정도 호환성을 보장하지만 Windows NT 계열 (Windows NT, 2000, XP, .NET, ...)에서는 전혀 사용할 수 없습니다. 또한 이런 16비트 DLL을 사용하는 것은 프로그래밍에도 도움이 안될뿐더러 생산된 산물역시도 비효율적입니다.
  • 유형 2; 다른 언어가 생성한 Windows용 DLL - 다른 언어가 생성한 Windows용 DLL은 Windows에서 인지할 수 있는 DLL입니다만 MFC에서는 인지하지 못하는 DLL입니다. 또 그 반대로 MFC에서 생성한 DLL은 Windows에서 인지할 수 있는 DLL입니다만 다른 언어에서는 인지하지못하는 DLL입니다.

Windows 프로그래머가 이런 점에 대하여 깊숙히 고려할 필요는 없지만, 이렇게 특수한 DLL이 있다는 것만 아시기 바랍니다.

DLL 작성법은 MFC 완벽 가이드에도 잘 설명이 되어있으니 실제 강의에서 강의받기 전에 먼저 읽어보고 넘어가시는 게 더 유용할 것이라고 봅니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요