GSI

MFC에서 타이머 사용하기 위한 방법입니다.

가끔 사용하다 보면 어떤건지 헷갈릴 때가 있습니다.

그래서 정리한 내용 입니다.


※ 메시지 맵에 아래 내용을 등록 합니다.

BEGIN_MESSAGE_MAP(CGroupChatWindow, CDialog)

...

ON_WM_TIMER()

...

END_MESSAGE_MAP()


※ 헤더파일에 함수를 선언 합니다.

afx_msg void OnTimer(UINT nIDEvent);


※ 함수는 아래와 같이 생성합니다.

void CTest::OnTimer(UINT nIDEvent)

{

    switch(nIDEvent)

    {

        case 1:

    // 내용을 여기 추가

            break;

    }


    //KillTimer(1); // 필요하면 이걸 사용해서 타이머 종료


}


※ 타이머 시작

SetTimer(1, 1000, NULL); // 이벤트 아이디 1, 1000ms(1초)


-- 이상 입니다. --


Posted by gsi
:

stdafx.h 파일에 

#import "C:\Program Files\Common Files\System\ado\msado15.dll" rename("EOF", "EndOfFile") no_namespace

이 구문을 추가 한다.



Posted by gsi
:


MFC의 Dialog 베이스를 사용해서 폼을 하나 제작합니다.
그리고 picture Box 를 하나 제작한 후에 CxImage를 사용해서 png 파일을 하나 로드 한후에
picture Box에 SetBitmap 를 하고 나서 이걸 다른 형태로 테스트를 진행해 봤습니다.

기본 코드는 아래와 같아요.

// CxImage 객체 생성
m_pImage = new CxImage("D:\\Test.png", CXIMAGE_FORMAT_PNG);

// PictureBox 컨트롤에 CxImage 이미지 연동
m_pic.SetBitmap( m_pImage->MakeBitmap() );

이렇게 하고 나서 실행 하고, 종료 하게 되면 크게 문제는 안되는듯 하다.

이걸 다른 형태로 테스트를 해봤다.
타이머를 통해서 CxImage 객체 두개의 Bitmap를 m_pic(PictureBox) 컨트롤에 SetBitmap를 반복해서 처리해봤다.

void CPngToBitmapDlg::OnTimer(UINT nIDEvent)
{
 static bool bFirst = false;
 static HBITMAP hBitmap = NULL;

 if( bFirst == false )
 { 
  hBitmap = m_pic.SetBitmap( m_pImage2->MakeBitmap() );
 }
 else
 {
  hBitmap = m_pic.SetBitmap( m_pImage->MakeBitmap() );
 }

 ::DeleteObject( hBitmap );

 //
 bFirst = !bFirst;

 m_loopCount++;
 UpdateData(false);
 

 CDialog::OnTimer(nIDEvent);
}

위의 붉은색 코드를 하지 않고 계속해서 SetBitmap을 하게 되면
페이지파일(PF)가 계속 증가 하는 것을 볼 수 있다.

앞으로 코드 구현을 할때 하나 하나 단위테스트를 통해서 반복적인 메모리 및 GDI 사용량 등을
체크 하고 좀 안정성 있는 프로그램을 하도록 해야 할거 같다.

Posted by gsi
:


한동안 포스트를 못했다.
삶이 너무 바쁘게 돌아 가다 보니

이 포스트를 한건건 소스를 공개 하는건 아니다.
하지만 몇가지 경우에 대해서 공론화를 하기 위해서다.
물론 여기에 있어서 지원을 받고 싶거나, 질문을 주시면 성심 성의껏 도와줄 의양은 있어요 ^^

ActiveX를 이용해서 웹에서 실행 파일을 제어 하기 위해서
최근에 작업을 했다.

기존에 크게 문제시 되었던 부분이 아니라서 개발 일정을 짦게 잡았던게 화근이였다. -.-

참.. 쉽게 해결되지 않는게 프로그램의 일이란걸 세삼 느꼈다.

.Net 2003으로 ActiveX를 개발을 하였다.
아주 기본으로 해서 메소드를 정의 하고 웹에 붙였다.

로컬에서는 아주 잘 되었고 그래서 웹 서버에 올려서 테스트 하면 잘 되겠지
싶었다.
웹 서버에 올리고 노란바가 정상적으로 나왔다.
그래서 이제 되겠거니 했지만.
ActiveX의 메소드가 웹에서 인식이 되지 않아서 메소드 정의가 없다는 오류가 나왔다.
IE 6.0, 8.0 모두 그런 현상이 발생 하였다.

그래서 보안 탭의 신뢰할 수 있는 사이트에 넣고 하니
제대로 될때도 있었지만.
안될때가 더 많았고 안되는 pc가 더 많았다.

근데 또 이상한건 신뢰할 수 있는 사이트에 웹 주소를 넣고 나서는
ACtiveX의 버젼을 올려서 배포를 해도 노란바가 아예 뜨지를 않았다.
하지만 구동은 정상적으로 업데이트 된게 실행이 되는 상태였다.

근데 그것도 이상하게 메소드가 없는 오류가 나올때가 있었다.

여러가지를 테스트해본 결과 IObjectSafety 인가 그 인터페이스 추가에서 문제가 나왔던거 같다.
이 코드를 적용하는데 있어서 helper.h, cpp 파일을 추가 하고 Ctrl.cpp에 추가 하고 하는 과정에서
오류가 있었던거 같다.

이제는 어려 곳의 컴퓨터에서 실행을 해봤지만 잘 되는거 같다.

ActiveX에서 많이 어려움을 가지는 초보 개발자가 있다면
언제든 쪽지 및 네이트온 추가를 통해서 질문해 주시기 바랍니다.
프로그래머는 항상 자료를 공유 하고 많이 나누면서 서로 발전해야 한다고 생각해요

그럼 오늘도 해결 안되는 문제를 안고 씨름 하는 많은 개발자들 화이팅 ^^
Posted by gsi
:


VS2003에서 InitializeCriticalSectionAndSpinCount 함수를 사용할려고 적용을 해보면
아래와 같은 컴파일 오류가 생긴다.

...\lock.cpp(50): error C3861: 'InitializeCriticalSectionAndSpinCount': 인수 종속성을 조회해도 식별자를 찾을 수 없습니다.

이런 경우는 window.h 이전에 _WIN32_WINNT의 디파인된 내용이 잘못되서 그런거 같다.

mfc의 경우 stdafx.h의 상단에 보면
#ifndef _WIN32_WINNT  // Windows NT 4 이후 버전에서만 기능을 사용할 수 있습니다.
#define _WIN32_WINNT 0x400   // Windows 98과 Windows 2000 이후 버전에 맞도록 적합한 값으로 변경해 주십시오.
#endif 

이란 부분에 있다.

여기서 0x400 부분을 0x403으로 수정해 주면 해결이 된다.
Posted by gsi
:

특정 폴더를 기준으로 하위 폴더를 찾아 내는 코드 입니다.
그리고 그 폴더 내용을 xml 형태로 만들어 주는 코드도 포함되어 있습니다.
xml 데이터로 만들어진 내용은 CEdit 컨트롤에 표시되며, 그 내용을
저장할 수 있습니다.


관련 소스 :



.

Posted by gsi
:

MFC에서 xml 데이터를 읽어 들이는 예제입니다.
아래의 내용을 계층구조를 통해서 읽어 들이게 됩니다.
자세한 소스는 소스 코드를 참조 하세요.
  - XmlParser.h, cpp

[xml 샘플]

<?xml version="1.0" encoding="EUC-KR"?>

<PATHS>
 <PATH NAME="Install Files">
  <PATH NAME="Dev">
  </PATH>
  <PATH NAME="Dev2">
  </PATH>
  <PATH NAME="Dev3">
   <PATH NAME="Dev3_a">
   </PATH>
   <PATH NAME="Dev3_b">
    <PATH NAME="Dev3_b_a">
    </PATH>
    <PATH NAME="Dev3_b_b"/>
   </PATH>
  </PATH>
 </PATH>
 <PATH NAME="temp">
  <PATH NAME="temp_a"/>
  <PATH NAME="temp_b">
   <PATH NAME="temp_b_a">
   </PATH>
   <PATH NAME="temp_b_b">
    <PATH NAME="temp_b_c"/>
   </PATH>
  </PATH>
 </PATH>
</PATHS>

계층 구조를 읽어 들이는 코드 (재귀호출)

1. 초기화 및 도입부

 ///
 MSXML2::IXMLDOMNodePtr nodeList = m_pDoc->selectSingleNode( Token.c_str() );
 _bstr_t bsElements("PATHS");

 if ( nodeList )
  FindName( nodeList->GetchildNodes() );

 nodeList.Release();

2. 재귀호출 부분

int tabCount = 0;

HRESULT CXmlParser::FindName( MSXML2::IXMLDOMNodeListPtr& lparam )
{
 long elementCount = lparam->Getlength();
 for( int i = 0; i < elementCount; i++ )
 {
  MSXML2::IXMLDOMElementPtr Element = lparam->nextNode();
  if( Element == NULL )
   break;

  _bstr_t bsNodename = Element->GetnodeName();
  _bstr_t bsElement("PATH");
  if( bsNodename == bsElement )
  {
   _bstr_t bsname("NAME");
   _variant_t varElementName = Element->getAttribute(bsname);

   // 해당하는 엘러먼트 Name의 이름 == 폴더 이름을 의미한다.
   CString strName;
   strName.Format( "%S", varElementName.bstrVal );    

   // 탭 카운터를 통한 출력
   CString strTabMergy;
   for( int tc = 0; tc < tabCount; tc++ )
   {
    strTabMergy += "\t";
   }
   strTabMergy += strName;
   TRACE( "%s\n", (LPSTR)(LPCSTR)strTabMergy);

   MSXML2::IXMLDOMNodeListPtr childElementlist = Element->GetchildNodes();
   if( childElementlist )
   {
    tabCount++;
    FindName( childElementlist );
   }
  }

  Element.Release();
 }

 tabCount--;
 lparam.Release();

 return S_OK;
}

아래의 콘솔 화면 내용입니다.

사용자 삽입 이미지


소스 코드 :


.

Posted by gsi
:

사용자 삽입 이미지

메모리 DC를 활용한 스크롤바의 Ruler 샘플입니다.
기존의 다른 다이얼로그에 포함시켜서 한 것보다 더 자연스럽네요.
그리고 스크롤 이동시에 잔상이 남지 않아서 더 좋은거 같습니다.

작업한 부분
1. 메모리 DC를 생성
2. 메모리 DC에 해당 Ruler의 크기 정보를 넣어서 미리 다 그려놓는다.
3. 스크롤 이동할때 마다 OnDraw()가 호출되고 그 내부에서 스크롤 포지션 값을 사용해서
    BitBlt 해서 처리 한다.
4. 잔상 효과는 OnHScroll(), OnVScroll()를 오버라이드 해서 Invalidate()를 해줘야 됩니다.

실행 파일 :


.
관련 파일 :


.
Posted by gsi
:

MFC의 UI를 배치 해보고, Winform의 UI배치를 보면 확연히 차이가 나는걸 확인할 수 있습니다.
그중에 가장 좋은건 아무래도 컨트롤 간의 도킹(?) 같은 기능이라고 보여 집니다.
아래의 이미지와 같이 컨트롤을 이동할때 마다 왼쪽, 오른쪽, 위, 아래, 그리고 중앙 에 대해서 실시간적으로 위치를 보정해 주는 기능이 정말 편하다고 생각 됩니다.
사용자 삽입 이미지

이번 툴의 샘플은 위와 같은 기능이 뷰에서도 많이 사용되게 되는데요.
가장 많이 사용되는 건 아무래도 스냅 기능이 아닐까 생각 됩니다.
해당 스냅의 간격에 맞춰서 객체를 이동시키는 방법 입니다.

스냅 구현
스냅을 구현할때 전 아래의 공식을 사용했습니다.

void CDataBox::MoveSnap( CPoint& pos )
{
 if( _bEnableSnap )
 {
  pos.x = pos.x - ( pos.x % _snapValue );
  pos.y = pos.y - ( pos.y % _snapValue );
 }
}
간단하게 설명을 하면 _snapValue가 스냅의 값이며, pos는 현재 위치를 담는 변수 입니다.
% 연산자를 사용해서 해당 스냅 간격에 대한 나머지를 구해서 현재 포지션에서 빼주는 방법으로 처리했습니다.

스냅을 처리하다 보면 현재 객체의 포지션값을 스냅으로 처리 하게 되면 제대로 동작하지 않습니다.
객체의 값은 항상 스냅이 적용되지 않은 값을 가지고 있어야 한다고 보여집니다.

화면에 보여질때 스냅의 처리를 통해서 보여지는게 조금더 유연하다고 생각 됩니다.

객체 도킹
객체의 도킹은 마우스로 이동할때마다 처리 해야 합니다.
다시 말해서 선택된 객체와 선택되지 않은 객체 간의 검사를 말합니다.
현재 객체의 위치와 다른 객체의 위치를 검사해서 도킹의 리미트 값의 범위 안에 들어왔을때
현재 객체를 대상 객체의 위치로 보정해 주는 방법 입니다.
여기에 더 해서 도킹이 이루어질 대상 객체와의 라인을 그려 주면 더 좋을듯 합니다.
사용자 삽입 이미지

위와 같이 해당 객체의 상태에서 파란선이 나오면서 객체가 같은 Y 축의 위치로 보정 됩니다.

이 소스는 조금 정리가 더 되어도 좋다고 생각 됩니다.
DataBox의 객체 관리 클래스에서 도킹을 담당하지만,
이것을 도킹 관련 클래스를 하나 두어서 작업 하는게 더 좋다고 보여 지네요..

관련 샘플 :


.

Posted by gsi
:

x, y 의 포인터 배열을 폴리라인이 형성되어 있을때
그 라인에 대한 옵셋값을 사용해서 포인터를 찍는 샘플 코드 입니다.

사용자 삽입 이미지
















확대를 하면 아래와 같은 포인터가 생성되는걸 확인할 수 있습니다.
Left, Right 키를 통해서 옵셋 값을 늘리고 줄이고 할 수 있습니다.
사용자 삽입 이미지


실행 파일 :


.
관련 코드 :


.
Posted by gsi
:

사용자 삽입 이미지

그레이 스케일로 표현해주는 코드가 일부 들어가 있는 소스입니다.
MFC DLL 형태로 제작되어 있으며, 바로 이전의 게시물과 거의 동일한 구조입니다.
몇가지 단위 테스트를 위해서 제작된 샘플 프로젝트입니다.

관련 소스 :


.
Posted by gsi
:

사용자 삽입 이미지

MFC DLL : 한장의 이미지를 보여 주는 dll 파일입니다.
                현재 jpg의 파일만 인코딩이 가능합니다.
                (이 부분은 확장자를 사용해서 처리 하시면 됩니다. 아직 그건 추가 하지 않았네요. )

사용시에는 아래의 코드를 이용 하시면 됩니다.

 CDlgImage dlg( "E:\\Gsi_Project\\정상옥_프로젝트\\Project\\2008_06_23_LAM_ModuleTest\\bin\\blue.jpg" );
 dlg.DoModal();

이외의 생성자 인자로서는 해당 width, height를 입력해줄 수 있으며,
내부 코드에서는 해당 다이얼로그에 맞도록 리셈플링 처리가 되어 있습니다.


실행파일 :



.

프로젝트 파일 :


.

Posted by gsi
:

헤더 파일에 추가하세요.

#ifndef _MEMDC_H_
#define _MEMDC_H_

//////////////////////////////////////////////////
// CMemDC - memory DC
//
// Author: Keith Rule
// Email:  keithr@europa.com
// Copyright 1996-1999, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History - 10/3/97 Fixed scrolling bug.
//                   Added print support. - KR
//
//           11/3/99 Fixed most common complaint. Added
//                   background color fill. - KR
//
//           11/3/99 Added support for mapping modes other than
//                   MM_TEXT as suggested by Lee Sang Hun. - KR
//
// This class implements a memory Device Context which allows
// flicker free drawing.

class CMemDC : public CDC {
protected:
 CBitmap  m_bitmap;       // Offscreen bitmap
 CBitmap* m_oldBitmap;    // bitmap originally found in CMemDC
 CDC*     m_pDC;          // Saves CDC passed in constructor
 CRect    m_rect;         // Rectangle of drawing area.
 BOOL     m_bMemDC;       // TRUE if CDC really is a Memory DC.

 void Construct(CDC* pDC)
 {
  ASSERT(pDC != NULL);

  // Some initialization
  m_pDC = pDC;
  m_oldBitmap = NULL;
  m_bMemDC = !pDC->IsPrinting();

  if (m_bMemDC) {
   // Create a Memory DC
   CreateCompatibleDC(pDC);
   pDC->LPtoDP(&m_rect);

   m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
   m_oldBitmap = SelectObject(&m_bitmap);

   SetMapMode(pDC->GetMapMode());
   pDC->DPtoLP(&m_rect);
   SetWindowOrg(m_rect.left, m_rect.top);
  } else {
   // Make a copy of the relevent parts of the current DC for printing
   m_bPrinting = pDC->m_bPrinting;
   m_hDC       = pDC->m_hDC;
   m_hAttribDC = pDC->m_hAttribDC;
  }

  // Fill background
  FillSolidRect(m_rect, pDC->GetBkColor());
 }

 // TRK begin
public:
 CMemDC(CDC* pDC                  ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }
 CMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect           ; Construct(pDC); }
 // TRK end

 virtual ~CMemDC()
 {       
  if (m_bMemDC) {
   // Copy the offscreen bitmap onto the screen.
   m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
    this, m_rect.left, m_rect.top, SRCCOPY);           

   //Swap back the original bitmap.
   SelectObject(m_oldBitmap);       
  } else {
   // All we need to do is replace the DC with an illegal value,
   // this keeps us from accidently deleting the handles associated with
   // the CDC that was passed to the constructor.           
   m_hDC = m_hAttribDC = NULL;
  }   
 }

 // Allow usage as a pointer   
 CMemDC* operator->()
 {
  return this;
 }   

 // Allow usage as a pointer   
 operator CMemDC*()
 {
  return this;
 }
};


#endif

Posted by gsi
:

헤더 선언 및 라이브러리 추가

#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

GDI+ 초기화
 // Initialize GDI+.
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

GDI+ 객체 삭제
 GdiplusShutdown(gdiplusToken);

Posted by gsi
:

void CGDITestView::OnLButtonDown(UINT nFlags, CPoint point)
{
 SetCapture();

 m_oldPoint = point;

 CView::OnLButtonDown(nFlags, point);
}

void CGDITestView::OnLButtonUp(UINT nFlags, CPoint point)
{
 ReleaseCapture();

 CView::OnLButtonUp(nFlags, point);
}

void CGDITestView::OnMouseMove(UINT nFlags, CPoint point)
{
 if( GetCapture() == this )
 {
  m_realPos += (point - m_oldPoint);
  m_oldPoint = point;

  Invalidate();
 }

 CView::OnMouseMove(nFlags, point);
}

Posted by gsi
: