2008년 11월 27일 목요일

CallBack Function (콜백 함수)

■ CallBack Function (콜백 함수)




1. 존재의 목적   - 프로그램이 실행되는 동안 지속적으로 수행해야 할 작업이 있을 때.
   - callback 함수를 호출한 쪽의 데이터를 callback 함수가 위치한 곳에서 사용해야 할 때.
  

2. 의미   - 운영체제가 API함수를 제공하는 것과 달리, 응용프로그램이 callback 함수를 제공한다.
   - 특정 조권을 만족 하였을 때 운영체제가 호출한다.
   - callback 함수는 오직 운영체제가 호출하며, 응용프로그램이 직접 callback 함수를 호출하지 못한다.
   - callback 함수마다 정해진 함수 원형이 있다.

   ※ 조권이 있을 때 윈도우 메시지를 호출 하기 보다 callback 함수를 호출 하는 이유?
      -  윈도우 메시지는(WM_TIMER. 등등) 메시지 마다 우선순위가 있어서 실행 순서에 밀려 늦게 호출 될수 있음.
      -  callback 함수는 조권이 발생 하였을 때 바로 실행됨.


3. 대표적인 callback 함수    운영체제가 callback 함수를 호출 할 수 있도록 callback 함수를 등록 해주는 함수가 존재한다.
   즉, 응용프로그램은 callback 함수를 윈도우 시스템에 알린다.
   
    - ::SetTimer(hWnd, 2, 5000, NULL);
                VOID CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime);
                조권 : 지정해준 시간마다 callback 함수 호출

    - ::EnumWindows(WINDENUMPROC lpEnumFunc, LPARAM lParam);
                 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
                 조권 : 최상위 모든 윈도우 검색, 그 핸들을 callback 함수로 전달
                          모든 윈도우를 다 찾거나, callback 함수가 FALSE를 리턴할때까지 호출됨.

    - ::윈도우 등록 및 생성
                 LRESULT CALLBACK WndProc(...)
                 조권 : 메인윈도우가 메시지를 받았을 때


4. callback 함수와 Thread 의 이해
   - callback 함수를 호출할 조권을 만족하는지 지속적으로 검사하는 과정이 필요하다.
     이러한 경우 보통 별도의 Thread 를 이용한다.
   - 즉, Main Thread 와 자식 Thread 는 비동기(Asynchronous) 작업을 수행할 때, 비동기 작업이 완료 되었음을을
     알리기 위한 방법으로 callback 함수(callback 매커니즘) 을 이용한다.






     ※ callback 매커니즘
           
<그림 2>는 전형적인 콜백 메커니즘을 보여주고 있다. 콜백 메커니즘의 순서로써 (1) 호출자는 콜백 메서드의 참조(함수 포인터)를 매개 변수로 하여 피호출 메서드를 호출한다(2) 피호출 메서드는 매개 변수로 전달된 콜백 메서드에 대한 참조를 필드와 같은 곳에 기록해 둔다.(3) 이제 콜백을 수행할 어떤 조건(이 조건은 다양할 수 있다)이 만족되면 ...(4) 기록해 둔 콜백 메서드 참조를 이용하여 콜백 메서드를 호출하게 된다.
물론 모든 콜백이 <그림 2>와 같은 순서를 따르는 것은 아니지만 많은 경우 이와 같은 시나리오를 따르는 것이 일반적이다. 콜백을 수행할 조건을 만족하는지 지속적으로 검사하는 과정이 필요하기 때문에 별도의 스레드를 이용하는 경우가 대부분이며, 콜백 메서드를 호출하는 스레드 역시 조건을 검사하는 스레드이기 때문에 콜백 메서드는 서로 다른 스레드에서 호출되는 것이 일반적이다. 이렇게 다중 스레드를 사용하기 때문에 비동기(asynchronous) 작업을 수행할 때 비동기 작업이 완료되었음을 알리기 위한 방법으로 콜백 메커니즘이 많이 사용되곤 한다.

출처 : http://imaso.co.kr/?doc=bbs/gnuboard.php&bo_table=article&wr_id=29268







   - callback 함수는 불려지는 쪽에서 부르는 쪽의 데이터를 참조 하거나 핸들링 하는 함수이다.
    다시 말해서 불려지는 쪽에서 부르는 쪽으 DATA를 참조하기 위한 교량 역할을 하는 함수가 callback 함수이다.




cf). callback 함수가 있다는 것을 알고 있었고, thread 가 있다는 것도 알고 간단한 사용법도 알았다.
    그런데 커다란 프로그램 에서는 정말... 복잡하지만 그 존재의 목적 대로 사용하고 있었다.
    이해가 안갔는데...  조금 정리가 되가는 것 같다.
    다음과 같은 경우이다.

1. Main Thread 에서  자료를 읽어 오는데 시간이 너무 오래 걸리는 거야...
   그래!! thread 를 이용하자!!

2. 생성한 Thread 에서 자료를 검색 해야 하는데 자료 검색 함수(메소드) 들이 MainThread 에 있는 거야...
3. 또 검색한 자료 값을 저장해야 하는데 그 변수 또한 Main Thread 에 있어.  Main Thread 와 자식 thread 간에는
   독립된 Stack 메모리를 사용하니까 변수를 고유 할 수 없고,
4. 그렇다고 전역변수를 사용하자니... 전역 변수의 사용은 지양해야해!!
5. Thread 에서 검색과정중 발생한 이벤트 역시 Main Thread 에 넘겨주고 싶어. 발생한 이벤트 마다
   Main Thread 가 다른 작업을 해주어야 하거든.
6. 그렇다고 Thread 에서 Main Thread 로 ::SendMessage() 함수를 사용 할 수는 없고,
   ::PostSendMessage() 는 안전하지 않으니 조금 사용하기가 그래.

7. callback 함수를 사용하자!!!
   callback 함수는 callback 함수가 불려지는 쪽(Thread)의 데이터를 callback 함수가 있는 곳(Main Thread)에서
   사용할 수가 있거든.




##

2008년 11월 25일 화요일

MFC 프로그램 구성 클래스간 상호 참조

■ MFC 프로그램 구성 클래스간 상호 참조




1. View → Document
  [ SDI 프로젝트 ]
    - GetDocument() 함수 사용
   
cf). GetDocument()는 CView 클래스의 멤버 함수

CDocument *CView::GetDocument();


      Document 의 인스턴스는 여러개 일 수 있기 때문에 CView 클래스 에서만(CView 파생 클래스 포함)
    사용할 수 있다.
                                                    ※ CView 클래스에서 파생된 클래스

cf). 하나의 Document 에 여러개의 View가 연결되어 있을 경우(분할 윈도우) 클래스 위자드는 하나의 View만
     자동적으로 GetDocument 함수를 재정의 해준다.
      나머지 View 에서도 GetDocument 를 사용하기 위해 직접 코딩 해주어야 한다.
     물론 함수 선언과 정의는 클래스 위자드가 만들어준 것을 그대로 사용하면 된다.

ChRmtEvwrDoc* GetDocument() const;

ChRmtEvwrDoc* CInforFormView::GetDocument() const
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(ChRmtEvwrDoc)));
    return (ChRmtEvwrDoc*)m_pDocument;
}



2. Document 얻기  [ SDI 프로젝트 ]
      CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
      CTestDoc *pDoc = (CTestDoc *)pFrame->GetActiveDocument();
      CTestDoc *pDoc = ((CMainFrame *)AfxGetMainWnd())->GetActiveDocument();




3. MainFrame 얻기   - ::AfxGetMainWnd()

CMainFrame *pMainFrame;
pMainFrame = reinterpret_cast<CMainFrame *>(::AfxGetMainWnd());


4. APP 얻기
   - ::AfxGetApp()
            CTestApp *pApp = (CtestApp *) AfxGetApp();


5. 현재 활성화된 View 얻기
   - CFrameWnd::GetActiveView();




MDI 프로젝트에서
1. ChildFrame
      CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
      CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
      CChildFrame *pChild = ((CMainFrame *)AfxGetMainWnd())->GetActiveFrame();


2. Document      CMainFrame *pFrame = (CMainFrame)AfxGetMainWnd();
      CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
      CMdiTestDoc *pDoc = (CMdiTestDoc *)pChild->GetActiveDocument();
      CMdiTestDoc *pDoc =
               (((CMainFrame *)AfxGetMainWnd())->GetActiveFrame())->GetActiveDocument();

3. View      CCainFrame *pFrame = (CMainFrame)AfxGetMainWnd();
      CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
      CMdiTestView *pView = (CMdiTestDoc *)pChild->GetActiveView();
      CMdiTestView *pView =
              (((CMainFrame *)AfxGetMainWnd())->GetActiveFrame())->GetActiveView();

2008년 11월 24일 월요일

[ListCtrl] 헤더의 컬럼(Column) 개수 얻기 및 삭제

■ ListCtrl (리스트 컨트롤) 헤더의 컬럼(Column) 개수 얻기 및 삭제




1. 리스트 컨트롤 헤더의 컬럼 개수 얻기   a. 헤더의 인스턴스 포인터를 얻어온다.
         헤더는 CHeaderCtrl 클래스로 관리가 된다.
   b. CHeaderCtrl 포인터로 멤버 함수인 GetItemCount() 함수를 호출한다.
         GetItemCount() 함수는 헤더의 컬럼 개수를 리턴한다.




CListCtrl   &ctrlList = GetListCtrl();/*< 동적 리스트 컨트롤 핸들 */
CHeaderCtrl *pHeaderCtrl;       /*< 리스트 컨트롤 헤더 인스턴스의 포인터 */

pHeaderCtrl = ctrlList.GetHeaderCtrl();
nCount = pHeaderCtrl->GetItemCount();
if (-1 == nCount)
{
    AfxMessageBox(_T("Header Column not exist"));
    return;
}





2. 헤더의 컬럼 삭제    - 헤더 컬럼의 삭제는 아래 함수를 이용한다.
      GetListCtrl().DeleteColumn(헤더컬럼 인덱스);
 
    - 주의할 점      헤더의 컬럼 개수를 얻어와 컬럼을 삭제하는 코드를 아래와 같이 작성하였다.
      즉, 헤더 컬럼의 개수를 얻고 0 부터 개수(개수-1) 만큼 for() 반복문을 돌면서 삭제 하려 하였다.


CListCtrl   &ctrlList = GetListCtrl();
CHeaderCtrl *pHeaderCtrl;            

pHeaderCtrl = ctrlList.GetHeaderCtrl();
nCount = pHeaderCtrl->GetItemCount();
if (-1 == nCount)
{
    AfxMessageBox(_T("Header Column not exist"));
    return;
}
else if (0 < nCount)
{
     ctrlList.DeleteAllItems();
     for (INT i = 0; i < nCount; i++)
        ctrlList.DeleteColumn(i);}





   ※ 삭제중인 모습
                                  

                                      첫 컬럼은 제대로 지워진다.

                                              두번째 삭제 과정중, 두번째 컬럼 대신에 세번째 컬럼이 지워졌다.


                        ctrlList.DeleteColumn(i);
                       이 부분에서 DeleteColumn(i) 함수가 호출 되어 컬럼을 삭제 하려고 할 때,
                      그 전에 지워진 컬럼 때문에 i 번째 컬럼이 의도한 컬럼의 인덱스가 되지 않는다.






else if (0 < nCount)
{
     ctrlList.DeleteAllItems();
     for (INT i = 0; i < nCount; i++)
        
ctrlList.DeleteColumn(0);}



             DeleteColumn(0) 으로 하여서 매번 for()문을 돌때마다
             첫번째 컬럼이 삭제하게 하였다. 모든 컬럼이 삭제 된다.



##

2008년 11월 22일 토요일

[VS 6] Class View 가 제대로 보이지 않을 때


 때때로 문제가 생겨서 Class View 가 잘못된 정보를 보여주거나 아예 나타나지 않을 때가 있다.
이는 Visual C++ 프로젝트 내 소스가 파일을 분석하고 기록하던 중 오류가 발생 했기 때문.

 프로젝트 폴더 내에 "[프로젝트 이름].ncb" 파일을 삭제하면 된다.

윈도우 최대 및 최대 크기 설정 - WM_GETMINMAXINFO


■ 윈도우 최대 및 최소 크기 설정 - WM_GETMINMAXINFO


1. WM_GETMINMAXINFO  - 윈도우의 크기(SIze) 나 위치(Position) 이 변경되었을때 윈도우에 보내지는 메시지
  - 윈도우의 최대, 최소 크기 및 위치를 설정할 수 있다.


2. MINMAXINFO structure
  - 윈도우의 최대 최소 크기 및 위치, 윈도우의 변경되는 크기에 대한 정보를 담은 구조체

Syntax
typedef struct {
    POINT ptReserved;
    POINT ptMaxSize;
    POINT ptMaxPosition;
    POINT ptMinTrackSize;
    POINT ptMaxTrackSize;
} MINMAXINFO;



Member
 - ptReserved       : 예약된 값, 사용되지 않는다.
 - ptMaxSize        : 윈도우의 최대 가로길이와 세로 길이를 POINT 형식의 값으로 저장한다. (POINT.x  POINT.y)
                            이 값은 주 모니터에 의존 된 값이며, 최상위 윈도우를 위한 값이다.
 - ptMaxPosition   : 최대화된 윈도우의 x,y축 위치(POSITION) 값이다. (POINT.x  POINT.y)
 - ptMinTrackSize : 윈도우의 크기가 변경될 때 최소의 크기를 명시한다.
                            이 값은 프로그램적으로 얻어진다.
                            System metrcs SM_CXMINTRACK and SM_CYMINTRACK. 으로부터
 - ptMaxTrackSize : 윈도우의 크기가 변경될 때 최대의 크기를 명시한다.
                            이 값은 virtual screen 과 프로그램 적으로 얻어진다.
                           System metrics  SM_CXMAXTRACK and SM_CYMAXTRACK. 으로부터


Remark - 여러개의 모니터를 사용할 경우, 주 모니터에 대한 값 ptMaxSize, ptMaxPosition 에 사용된다.


Structure Information
          Header                                    Declared in Winuser.h, include Windows.h
          Minimum operating systems     Windows 95, Windows NT 3.1



3. 예제

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
    lpMMI->ptMinTrackSize.x = 400;
    lpMMI->ptMinTrackSize.y = 800;


    CFrameWnd::OnGetMinMaxInfo(lpMMI);
}





cf) 분할 윈도우를 사용하였을 경우
    CMainFrame 의 크기 제한은 위와 같은 방법으로 할 수 있지만
    각각의 분할윈도우의 크기 제한, 즉 splitter bar 의 위치는 다른 방법을 사용하여 제한 해야 함.

2008년 11월 21일 금요일

사용하지 않는 함수 매개변수에 대한 경고 없애기

사용하지 않는 함수 매개변수에 대한 경고 없애기



 Visual Studio 에서는 프로젝트 환경 설정에 "경고 수준" 이라는 항목이 있다.
컴파일러의 코드에 대한 엄격도를 설정 하는 것인데 경고 수준이 높을 수록
명확한 코드를 사용해야 한다.


- 기본적으로 생성되는 프로젝트의 경고 수준 : 수준3(/W3)


- 좀더 세밀한 프로그래밍을 위해 "수준4" 를 한다면 MFC가 만들어준 코드에서도 경고 메시지가 발생한다.
  즉, 사용하지 않는 함수의 매개변수에 대한 경고 이다.


경고 없애는 법
1. 매개변수를 지운다.
void CMyView::OnMouseMove( UINT, CPoint point)



2. 매개변수를 주석 처리한다.

void CMyView::OnMouseMove( UINT /*nFlags*/, CPoint point)


3. UNUSED_ALWAYS 매크로를 사용한다.

void CMyView::OnMouseMove( UINT nFlags, CPoint point)
{
    UNUSED_ALWAYS(nFlags)

    ...
}

4. UNREFERENCED_PARAMETER 매크로를 사용한다.

void CMyView::OnMouseMove( UINT nFlags, CPoint point)
{
    UNREFERENCED_PARAMETER(nFlags)

    ...
}

2008년 11월 18일 화요일

최초 윈도우 크기

최초 윈도우 크기,



1. 윈도우의 가장 기본 틀이 되는 CMainFram 에서 정해 준다.   CMainFram 클래스 중에서도 PreCreateWindow() 함수에서 작업해 준다.

   PreCreateWindow()    :    윈도우가 생성되기 전 호출되는 함수
     - Parameter cs 에는 생성되는 윈도우의 정보를 담고 있는 구조체 이다.
     - cs 구조체 멤버 중에서 cx, cy 는 각각 메인 윈도우 가로, 세로 길이를 나타낸다.  

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;

    cs.cx = 1000;                           /*< 메인 윈도우의 가로 길이 */
    cs.cy = 700;                            /*< 메인 윈도우의 세로 길이 */
   
    return TRUE;
}





2. CWinApp 의 파생 클래스에서 윈도우 크기 조정   MFC 응용프로그램은 CWinApp 클래스을 기반 클래스로 고유의 파생 클래스를 만든다.
  InitInstance() 함수는 응용프로그램 관련 윈도우 생성 및 초기화 작업을 한다.
  m_pMainWnd 변수의 SetWindowPos() 함수로 윈도우 크기를 조정해 줄수도 있다.
 
  - CMainFrame 에서 윈도우 크기를 정하는 것과 차이점
    생성되는 윈도우의 크기는 CMainFrame 에서 PreCreateWindow() 함수 안에서 결정 된다.
    생성된 윈도우를 SetWindowsPos() 함수를 이용해서 지정해준 값 만큼 크기를 조정해서 보여는 것이다.
    SetWindowPos() 함수의 두번째, 세번째 인수는 출력 윈도우의 위치이고,
    네번째, 다섯번째 인수는 각각 x축, y축 으로의 길이 이다.

m_pMainWnd->SetWindowPos(NULL, 10106006000);



 

                    ※ 원래 윈도우의 크기를 줄여서 보여주는 것이기 때문에 스크롤이 생긴다.



3. 윈도우 크기 고정
  CMainFrame 클래스에서 PreCreateWindow() 함수가 기본적으로 설정 하는 윈도우 스타일은


cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE | WS_THICKFRAME
           | WS_SYSMENU | WS_MINIMIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZE;

  여기서 WS_THICKFRAME 스타일을 제거하면 처음 생긴 윈도우의 크기를 조절할 수 없다. 즉, 크기 고정


 cs.style &= ~WS_THICKFRAME;



##

2008년 11월 17일 월요일

[ListCtrl] 선택한 아이템 얻기 - 1 (LVN_CLICK)

ListCtrl (리스트 컨트롤) 선택한 아이템 얻기



 너무 어렵게 생각했나...
예전에 책에서 배웠던 방법으로 LVN_ITEMCHANGED 이벤트로 얻으려 했으나
이 이벤트는 다루기가 조금 까다롭다..

LVN_CLICK 메시지를 사용하였다.


1. LVN_CLICK 이용   : 컨트롤을 마우스 왼쪽 버튼으로 클릭 했을 때 발생

void
 ChRmtEvwrView::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
     LPNMITEMACTIVATE pNMItemActivate
                           = reinterpret_cast<LPNMITEMACTIVATE(pNMHDR);
     /*< 선택한 아이템의 인덱스를 얻는다. */     nSelectItemIndex = pNMItemActivate->iItem;
     ...    
}



pNMItemActivate 포인터 변수에 마우스로 선택한 아이템에 대한 정보가 들어 있다.



※ 주의

1. 리스트 컨트롤에 정의된 헤더 이외의 영역에 마우스 클릭을 했을 경우
     (아래 사진의 "원본" 오른쪽 공간을 마우스 왼쪽 버튼으로 클릭한 경우)
   - 리스트 컨트롤이 있는 뷰의 크기를 조정할 수 있다면  리스트 컨트롤에서 설정한 헤더 이외의 공간이
    생긴다. 이때 이곳에 마우스 왼쪽 버튼을 클릭 하게 되면 pNMItemActivate->iItem; 값에는
    -1의 값을 갖는다.




※ 참조


NMITEMACTIVATE Structure





Contains information about an LVN_ITEMACTIVATE notification message.

Syntax

typedef struct tagNMITEMACTIVATE {
    NMHDR hdr;
    int iItem;
    int iSubItem;
    UINT uNewState;
    UINT uOldState;
    UINT uChanged;
    POINT ptAction;
    LPARAM lParam;
    UINT uKeyFlags;
} NMITEMACTIVATE, *LPNMITEMACTIVATE;

Members



hdr
NMHDR structure that contains information about this notification message.
iItem
Index of the list-view item. If the item index is not used for the notification, this member will contain -1.
iSubItem
One-based index of the subitem. If the subitem index is not used for the notification or the notification does not apply to a subitem, this member will contain zero.
uNewState
New item state. This member is zero for notification messages that do not use it.
uOldState
Old item state. This member is zero for notification messages that do not use it.
uChanged
Set of flags that indicate the item attributes that have changed. This member is zero for notifications that do not use it. Otherwise, it can have the same values as the mask member of the LVITEM structure.
ptAction
POINT structure that indicates the location at which the event occurred. This member is undefined for notification messages that do not use it.
lParam
Application-defined value of the item. This member is undefined for notification messages that do not use it.
uKeyFlags
Modifier keys that were pressed at the time of the activation. This member contains zero or a combination of the following flags:

LVKF_ALT
The key is pressed.
LVKF_CONTROL
The key is pressed.
LVKF_SHIFT
The key is pressed.

Structure Information















Minimum DLL Versioncomctl32.dll version 4.71 or later
Headercommctrl.h
Minimum operating systemsWindows 2000, Windows NT 4.0 with Internet Explorer 4.0, Windows 98, Windows 95 with Internet Explorer 4.0






##

2008년 11월 16일 일요일

[ListCtrl] 확장 속성

ListCtrl (리스트 컨트롤) 확장 속성




LVS_EX_FULLROWSELECT       : 아이템을 선택할 때 한 줄 전체를 반전시킨다.
LVS_EX_GRIDLINES                 : 각 아이템에 경계선을 그려준다.
LVS_EX_CHECKBOXES            : 각 아이템에 Check Box를 표시해 준다.
LVS_EX_HEADERDRAGDROP     : 컬럼 헤더를 드래그 함으로써 컬럼의 순서를 바꿀 수 있게 해준다.




1. 리스트 아이템 선택시 포터스 표시 - LVS_EX_FULLROWSELECT

   - 기본적으로 리스트 아이템의 제일 왼쪽 헤더의 아이템을 클릭해야 포커스가 표시 된다.






옵션 한줄!!
LVS_EX_FULLROWSELECTex). GetListCtrl().SetExtendedStyle(LVS_EX_FULLROWSELECT);



2. 리스트 아이템 경계선 - LVS_EX_GRIDLINES
                               적용 전


                               적용 후

GetListCtrl().SetExtendedStyle(LVS_EX_GRIDLINES);






※ 위에서 적용 하고자 하는 속성을 함께 줄 때

GetListCtrl().SetExtendedStyle(LVS_EX_GRIDLINES);
GetListCtrl().SetExtendedStyle(LVS_EX_FULLROWSELECT);

이렇게 하나씩 적용 하려고 하면 제일 마지막에 선언한 문장만 적용이 된다.
한꺼번에 해줄려면 속성을 '|' 연산자로 묶어 주자.

GetListCtrl().SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);


##

2008년 11월 13일 목요일

MFC 시간 제어, DWORD -> time_t -> CTime() COleDateTime() 사용


MFC 시간 제어, DWORD -> time_t -> CTime() COleDateTime() 사용



 어떤 파일의 시간 정보를 얻어왔다.
해당 API 함수는 시간 정보를 DWORD 값으로 리턴 하고 있었다.
시간 정보를 얻었다는 기쁨에 값을 받았는데
음... 이걸 어떻게 변환해 줘야 하지??

CTime, COIeDateTime 클래스가 있다는 것을 알았지만
이 클래스의 객체를 생성해서 현재 시간을 얻어오고... 그런 작업밖에 안해본 지라
두 클래스는 제쳐두고 변환하려 애썼다.

c 라이브러리인 struct tm 구조체로 변환해서...
해결하긴 했지만 C++/MFC 적으로 해결하지 못해 찝찝했다.

오늘도 2시간 고생하다가... 알았냈다.
CTime, COleDateTime 클래스 생성자 인수로 time_t 형을 파라미터로 받는다. -_-;;;



                time_t longtime;
                //tm pTm;                
                longtime = (time_t)(pevlr->TimeGenerated); 

                //if (localtime_s(&pTm, &longtime)) {
                //    AfxMessageBox(_T("error"));
                // }


                COleDateTime oleTime(longtime);
                CTime ctime(longtime);
               

                INT nYear, nMonth, nDay;
                INT nHour, nMin, nSec;

                
/*
                nYear = oleTime.GetYear();
                nMonth = oleTime.GetMonth();
                nDay = oleTime.GetDay();
                nHour = oleTime.GetHour();
                nMin = oleTime.GetMinute();
                nSec = oleTime.GetSecond();
                */

                nYear = ctime.GetYear();
                nMonth = ctime.GetMonth();
                nMonth = ctime.GetMonth();
                nDay = ctime.GetDay();
                nHour = ctime.GetHour();
                nMin = ctime.GetMinute();
                nSec = ctime.GetSecond();
                TRACE1("%d-", nYear);
                TRACE1("%d-", nMonth);
                TRACE1("%d  ", nDay);
                TRACE1("%d:", nHour);
                TRACE1("%d:", nMin);
                TRACE1("%d\n", nSec);




##


[TreeCtrl] - LV_ITEM 구조체, 멤버 함수

TreeCtrl (트리 컨트롤) - LV_ITEM 구조체, 멤버 함수





TV_ITEM 구조체typedef struct _LVITEM {
    UINT mask;           //TVIF_TEXT, TVIF_IMAGE, TVIF_SELECTEDIMAGE
    HTRRITEM hItem;      //항목 핸들
    UINT state;          //항목의 상태
    UINT stateMAsk;      //항목의 상태 마스크
    LPSTR pszText;       //항목이 사용할 텍스트
    int cchTextMax;      //pszText이 가리키는 버퍼의 크기
    int iImage;          //항목에서 사용할 이미지 인덱스
    int iSelectedImage;  //항목이 선택되었을 때 사용할 이미지 인덱스
    int cChildren;       //현재 항목이 하위 항목을 갖는지 여부를 나타낸다.
    LPARAM lParam;       //현재 항목과 관련된 부가 정보를 나타내는 32비트값
} LVITEM, *LPLVITEM;




TreeCtrl 멤버 함수
InsertItem()            새로운 항목을 추가한다.
DeleteItem()            지정한 항목을 삭제한다.
DeleteAllItems()        트리 컨트롤 내의 모든 항목을 삭제한다.
GetCount()              트리 컨트롤 내의 항목의 총 개수를 얻는다.
GetItemText()           지정된 항목의 텍스트를 리턴한다.
SetItemText()           지정된 항목의 텍스트를 설정
HitTest()               지정된 항목의 핸들을 얻는다.
GetImageList()          이미지 리스트 설정
SetImageList()          트리 컨트롤에서 사용할 이미지 리스트를 설정한다.
GetITem()               지정된 항목의 속성을 얻는다.
GetRootItem()           루트 항목의 핸들을 리턴한다.
GetNextSiblingItem()    동일한 레벨의 다음 항목에 대한 핸들을 리턴한다.
Expand()                설정된 항목의 하위 항목을 모두 확장한다.
SelectItem()            지정된 항목을 선택한다.
ShortChildre()          자식 노드들을 정렬
SetCheck()              지정된 아이템 체크 해제 또는 체크
                        (TVS_CHECKBOXES 스타일의 컨트롤일 경우만 사용됨)
EnsureVisible()         지정된 항목이 화면에 보이도록 함




[TreeCtrl] - TVN_SELCHANGED



TVN_SELCHANGED



- 한 항목에서 다른 항목으로 선택이 변경 되었을 때 발생하는 메시지

 

현재 선택된 트리뷰의 아이템 얻기
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
HTREEITEM hItem = pNMTreeView->itemNew.hItem;


즉, HTREEITEM hItem = pNMTreeView->itemNew.hItem;
hItem 으로 선택된 아이템(항목) 에 대한 작업을 하면 된다.



이벤트 메시지가 발생한 상황 판별LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);






pNMTreeView->action;


action 값을 조사하면 이벤트 메시지가 발생한 상황 판별 가능
TVE_EXPAND  :  아이템 확장 시
4096                :  Create된후에 포커스 받아서 Root가 선택되는 경우


0                    :   DeletaAllItems() 으로 호출됬을 경우
1                     : 내가 선택했을 경우

cf). 내 경험상 DeleteAllItems() 함수 호출 때 발생하지 않던데...



발생하는 경우

1. OnInitialUpdate() 함수에서 TreeCtrl 에 항목을 추가 하였을 때
   즉, 비어있는 TreeCtrl에 항목을 추가 시켰을 때 발생한다.
   (Create된후에 포커스 받아서 Root가 선택되는 경우)





cf) NMTREEVIEW 구조체 정보
    MSDN : http://msdn.microsoft.com/en-us/library/bb773411(VS.85).aspx


2008년 11월 5일 수요일

LookupAccountSid()



LookupAccountSid()







의미

 SID로부터 계정(Account) 정보를 얻어 오는 함수.

 (사용자 이름, 도메인 이름, SID 타입  구할 수 있음)



원형
BOOL WINAPI LookupAccountSid(  __in_opt      LPCTSTR lpSystemName,  __in          PSID lpSid,  __out_opt     LPTSTR lpName,  __in_out      LPDWORD cchName,  __out_opt     LPTSTR lpReferencedDomainName,
  __in_out      LPDWORD cchReferencedDomainName,
  __out         PSID_NAME_USE peUse
);





Parameter

lpSystemName

-       SID가 속한 컴퓨터 이름(널문자로 끝나는)

-       원격 컴퓨터 이름 가능

-       NULL 값 일 때는 Local 컴퓨터를 대상으로 함.

   lpSid

-       조사 대상 SID

   lpName

-       SID 에서 조사한 사용자 이름 (Null –terminated)

   cchName

-       lpName 버퍼의 크기(size, in TCHARs)

   lpReferencedDomainName

-       계정 이름이 위치한 Domain 이름. (Null-terminated)

   cchReferencedDomainName

-       lpReferencedDomainName 버퍼의 크기(size, in TCHARs)

   peUse

-       계정의 타입 (SID_NAME_USE )






typedef enum _SID_NAME_USE

{

    SidTypeUser = 1,

SidTypeGroup,

SidTypeDomain,

SidTypeAlias,

SidTypeWellKnownGroup,

SidTypeDeleteAccount,

SidTypeInvalid,

SidTypeUnknown,

SidTypeComputer,

SidTypeLabel1   

}SID_NAME_USE,  *PSID_NAME_USE;

Constants

SidTypeUser

A user SID.

SidTypeGroup

A group SID.

SidTypeDomain

A domain SID.

SidTypeAlias

An alias SID.

SidTypeWellKnownGroup

A SID for a well-known group.

SidTypeDeletedAccount

A SID for a deleted account.

SidTypeInvalid

A SID that is not valid.

SidTypeUnknown

A SID of unknown type.

SidTypeComputer

A SID for a computer.

SidTypeLabel

A mandatory integrity label SID.



Return Value

   성공 시 : 0 이 아닌 값

   실패 시 : 0   (GetLastError 로 자세한 정보 얻음)



Windows NT 4.0:  Forest lookup and account lookup by SIDhistory are not supported

 ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/secauthz/security/lookupaccountsid.htm

2008년 11월 3일 월요일

[MFC_Debug] fatal error C1853: 미리 컴파일된 헤더 파일이 이전 버전의 컴파일러에서 만들어졌거나,


" ... 미리 컴파일된 헤더 파일이 이전 버전의 컴파일러에서 만들어졌거나, ... "

Visual Studio 2008 을 사용하다가 필요에 의해 Visual Studio 2008 Service Pack1 을 설치 하였습니다.
설치를 마치고, 다시 진행하던 프로젝트를 열었습니다. 컴파일 해보니... 위와 같은 Error 메시지가 나오더군요.

Service Pack1 에서 컴파일러 부분에 많은 수정이 가해졌나 봅니다.



<해결 방법>
Deg 폴더에 보시면 *.pch 파일이 있습니다. 프리 컴파일러 헤더 파일인데
컴파일 속도를 위해 미리 컴파일된 부분이 들어있습니다.
이것을 지우고 다시 빌드 하니 되는군요.

*.pch 파일이 보이지 않아  윈도우즈의 "검색" 기능을 이용해 찾고 삭제 하였습니다.

[MFC_Debug] Detected memory leaks!


Detected memory leaks!


 컴파일도 잘 되었고, 디버그 할 때도 아무 메시지 없다가
디버그 종료하니 출력창에 "Detected memory leaks!" 이라고 나온다.



소스를 다시 보니..
동적 메모리 할당 해놓고, 메모리 해제 하는 부분을 주석처리 하고 그냥 놔둬 버렸다.



이럴때 이런 메시지가!!