2018. 7. 17. 15:51

m_listCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);



nIndex : 해당 선택 줄 (0번부터 시작)

2018. 4. 20. 20:51

컨트롤을 업데이트 하기 전에 다음 함수를 넣어준다



LockWindowUpdate();



모든 컨트롤을 업데이트 하고 나서 다음 함수로 해제한다



UnlockWindowUpdate();



그러면 깜빡임이 발생하지 않는다

2018. 2. 9. 11:05

훅 체인에 등록되어 메시지를 감시하는 함수를 훅 프로시저(Hook Procedure)라고 한다


훅 타입에 따라 훅 프로시저의 인수나 리턴값의 의미는 달라지지만 원형은 고정되어 있다


다음은 WH_KEYBOARD 타입의 키보드 훅 프로시저인데 다른 타입의 훅 프로시저도 이름만 다르고 원형은 동일하다


LRESULT CALLBACK KeyboardProc( int code, WPARAM wParam, LPARAM lParam);


훅 프로시저는 응용 프로그램이 제공하는 콜백함수이므로 원형만 제대로 지킨다면 이름은 마음대로 정할 수 있다


세 개의 인수


1. code : 훅 프로시저에서 이 메시지를 어떻게 처리할 것인가를 지정

           이 값이 음수이면 훅 프로시저는 이 메시지를 처리하지 말고 다음

           훅 프로시저에게 메시지를 넘김


2. wParam : 메시지 추가 정보


3. lParam : 메시지 추가 정보


훅 프로시저를 설치할 때는 다음 함수를 사용한다


HHOOK SetWindowsHookEx

( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId );



1. idHook : 설치하고자 하는 훅의 타입을 지정

              WH_로 시작되는 매크로 상수중 하나를 사용


2. lpfn : 훅 프로시저의 번지


3. hMod : 훅 프로시저를 가진 인스턴스 핸들


4. dwThreadId : 훅 프로시저가 감시할 스레드의 ID

                   이 값이 0이면 시스템의 모든 스레드에서 발생하는 메시지가 훅                     프로시저로 전달



자신의 메시지를 훅킹할 때는 GetCurrentTrheadId 함수로 현재 스레드의 ID를 넘긴다


시스템의 모든 메시지를 감시하고자 한다거나 다른 프로그램의 메시지를 감시하고자 할 경우 lpfn은 반드시 분리된 DLL에 있어야 하며 이 때 hMod는 이 DLL의 핸들이어야 한다


다음은 지역 훅과 전역 훅을 설치하는 일반적인 방법이다


지역 훅 : SetWindowsHookEx( idHook, lpfn, NULL, GetCurrentThreadId() );


전역 훅 : SetWindowsHookEx( idHook, hpfn, hDll, 0 );



SetWindowsHookEx 함수는 훅 프로시저를 설치한 후 HHOOK 타입의 훅 핸들을 리턴하는데 이 핸들은 해제를 위해 전역 변수에 잘 보관해 두어야 한다


만약 에러가 발생했ㄷ사면 NULL 을 리턴한다


훅 프로시저를 해제하는 함수는 다음과 같다


BOOL UnhookWindowsHookEx( HOOK hhk );


해제하고자 하는 훅 핸들을 인수로 전달하는데 이 핸들은 설치할 때 받은 값이다


훅을 설치한 프로그램은 종료되기 전에 반드시 훅 프로시저를 해제해야 한다


훅 프로시저가 설치되면 해당 타입의 메시지는 목표 윈도우로 보내지기 전에 훅 프로시저에게 먼저 전달되는데 훅 프로시저는 메시지를 살펴본 후 특별한 이유가 없으면 메시지를 훅 체인의 다음 훅 프로시저에게 전달해야 한다


이 때는 다음 함수를 사용한다


LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam);


hhk 는 현재 처리하고 있는 훅의 핸들인데 SetWindowsHookEx 함수가 리턴한 값이다












2018. 2. 8. 23:01

메시지 기반의 윈도우즈에서는 운영체에와 응용 프로그램, 또는 응용 프로그램 사이나 응용 프로그램 내부의 컨트롤끼리도 많은 메시지들을 주고 받는다


훅(Hook)이란 메시지가 목표 윈도우로 전달되기 전에 메시지를 가로채는 특수한 프로시저이다


오고 가는 메시지를 감시하기 위한 일종의 덫(Trap)인 셈인데 일단 응용 프로그램이 훅 프로시저를 설치하면 메시지가 윈도우로 보내지기 전에 훅 프로시저를 먼저 거친다


서브 클래스 프로시저와 마찬가지로 훅 프로시저에서는 메시지를 단순히 살펴보기만 할 수도 있고 메시지를 변경하거나 아예 없애버릴 수도 있다


훅 프로시저가 어떤 메시지를 받을 것인가는 훅의 타입과 범위에 따라 달라진다


훅 타입은 WH_ 로 시작되는 매크로 상수로 지정하는데 WH_HOUSE, WH_KEYBOARD 등 여러 가지가 있다


이름으로 유추할 수 있듯이 WH_HOUSE 훅은 마우스 메시지를 가로채고 WH_KEYBOARD 훅은 키보드 메시지를 가로챈다 


또한 훅은 메시지를 가로챌 범위에 따라 지역 훅 (Thread Specific)과 시스템 전역 훅(System Wide)으로 나누어진다


지역 훅은 특정 스테르에서 발생하는 메시지들만 전달 받으며 전역 훅은 시스템의 모든 스레드에서 발생하는 메시지를 가로챌 수 있다


응용 프로그램 자신의 메시지만 받고 싶을 때는 지역 훅을 사용하며 시스템에서 발생하는 모든 메시지를 받고자 할 때는 전역 훅을 설치해야 한다


훅 프로시저는  응용 프로그램이 자신의 필요에 따라 언제든지 설치할 수 있기 때문에 하나의 훅 타입에 대해 여러 개의 훅 프로시저가 존재할 수도 있다


그래서 운영체제는 설치된 훅 프로시저들을 훅 체인(Hook Chain) 으로 관리한다

훅 체인이란 훅 프로시저 함수들의 번지를 담고 있는 일종의 함수 포인터 배열이라고 할 수 있다


응용  프로그램이 훅 프로시저를 설치하면 운영체제는 훅 체인의 선두에 등록된 프로시저에게 이 메시지를 전달하고 훅 프로시저는 체인을 따라 다음 훅 프로시저에게 메시지를 연속적으로 전달하며 종국에는 그 메시지를 받을 윈도우에게 전달한다


물론 중간에서 메시지가 변형되거나 사라질 수도 있다


훅 프로시저가 설치되어 있으면 시스템은 메시지가 발생할 때마다 훅 프로시저에게 메시지를 전달한다


훅 체인에 여러 개의 훅 프로시저가 설치되어 있다면 메시지는 훅 체인 내의 모든 훅 프로시저를 거쳐야만 비로소 목표 윈도우로 전달될 수 있다


그래서 훅은 시스템의 전반적인 속도를 눈에 띄게 만든다


짧은 순간에 수백 개의 메시지가 처리되는데 이 메시지들이 훅 프로시저를 한 바퀴 돌아오려면 당연히 시간이 걸릴 수 밖에 없다


훅을 사용하는 디버거나 스파이 등의 툴을 띄워 놓으면 시스템이 느려지는 것을 직접 경험해 본 바 있을 것이다


그래서 훅은 꼭 필요할 때만 설치해야 하며 끝난 후에는 곧바로 제거하는 것이 좋다





2017. 12. 18. 21:23


Windows 7 Professional 인지 Windows 7 Embedded 인지 확인하는 방법은


레지스트리에 등록된 정보를 얻어와야 한다



OS 이름은 다음 레지스트리에 있다


HKEY_LOCAL_MACHINE

    

    -  SOFTWARE


        - Microsoft

     

             - Windows NT


                 - CurrentVersion



에서 ProductName 에 있다



CString strvalue;

CRegKey key;


if (key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")) == ERROR_SUCCESS)

{

DWORD size(256);

if (key.QueryStringValue(_T("ProductName"), strvalue.GetBuffer(size), &size) == ERROR_SUCCESS)

strvalue.ReleaseBuffer();


key.Close();

}



strValue 에 현재 OS 이름이 들어온다




2017. 9. 6. 00:13

USB를 꽂고 뺄 때 발생하는 이벤트를 처리하는 함수를 구현한다


WM_DEVICECHANGE 메시지를 재정의한다


메시지 맵에는 다음과 같은 함수가 추가된다


ON_WM_DEVICECHANGE()



다음과 같은 메시지 핸들러 내부를 처리한다


afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData)

{

if(7 == nEventType) // USB 넣고 뺄 때 nEventType이 7로 날라옴

CreateDriveButtons();


return TRUE;


}

2017. 9. 5. 23:56

ON_CONTROL_RANGE 매크로를 이용하여 여러 개의 범위를 처리한다


1. 이벤트가 발생하면 메시지를 처리한다고 결정한다

EX) 버튼이 눌렸을 때 - BN_CLICKED



2. 메시지 핸들러를 등록한다


afx_msg void OnDriveButtonClicked(UINT uID);



3. 처리 범위를 결정한다.



enum enDriveButtonID

{

_EN_ID_DRIVE_BASE_ = 2001,

};


static const size_t nMaxButtonCount(4);



4. ON_CONTROL_RANGE( ) 를 이용하여 범위를 등록한다



ON_CONTROL_RANGE(BN_CLICKED, // 발생 이벤트

  _EN_ID_DRIVE_BASE_, // 시작 ID

  _EN_ID_DRIVE_BASE_ + nMaxButtonCount, // 끝 ID

  OnDriveButtonClicked) // 메시지 처리 함수



5. 메시지 핸들러를 구현한다


void CDlg::OnDriveButtonClicked(UINT uID)

{

for(int nIndex(0); nIndex < nMaxButtonCount; ++nIndex)

{

if(uID == _EN_ID_DRIVE_BASE_ + nIndex)

{

m_strDrive = strFiles[nIndex];

if(m_bSearchMode)

m_editSearch.GetWindowTextW(m_strExtension);

break;

}

}


OnOK();

}

2017. 9. 1. 00:50

* IPC 기법 대신 사용하는 방법이다


이 방법을 Broadcase 통신이라고 하는데 

RegisterWindowMessage( ) API 를 이용한다


WPARAM, LPARAM을 이용하여 메시지 통신을 한다



사용 방법은 다음과 같다


* 보내는 프로세스


1. 메시지 등록


UINT nRegisterMessage = RegisterWindowMessage(_T("MyCommunication"));



2. PostMessage를 이용하여 데이터 전송


int nData = 2000;

PostMessage(HWND_BROADCAST, nRegisterMessage, (WPARAM)nData, 0);




* 받는 프로세스


1. 메시지 등록


UINT nRegisterMessage = RegisterWindowMessage(_T("MyCommunication"));



2. 메시지 핸들러 추가


ON_REGISTERED_MESSAGE(nRegisterMessage, &CTestDlg::OnMyHandler)



3. 메시지 처리를 할 함수 구현


LRESULT CTestDlg::OnMyHandler(WPARAM wParam, LPARAM lParam)

{

       int nData = (int)wParam;


       // 그 이외의 함수 처리

}



* 주의  - 최상위 부모에만 전달된다 따라서 자식 윈도우에 전달하고 싶으면 최상위 부모에서 전달해야 한다

2017. 2. 7. 22:29

탭 컨트롤 선택 후 속성에서


Vertical 항목을 True 로 하면 탭 버튼이 세로로 된다






2017. 2. 7. 15:55

1. 탭 컨트롤을 다이얼로그에 붙인 후 변수를 추가한다


카테고리(범주) : Control

CTabCtrl m_tabCtrl;



2. 탭 개수를 추가하고 헤더에 이름을 추가한다




3. 각 탭에 다이얼로그를 보여줄 다이얼로그를 생성한다

그대로는 자식 윈도우로 사용할 수 없으므로 일부 속성을 변경


Border 속성 : None

Style 속성 : Child


- 이렇게 수정한 대화상자 리소스는 메인 프레임 윈도우가 되지 못하고 특정 윈도우의 자식 윈도우로 생성/동작



4. 수정한 대화상자의 클래스를 추가한다




5. 탭 컨트롤 영역을 얻어와 탭 컨트롤의 자식으로 각 다이얼로그를 생성하고

보여주는 다이얼로그를 설정한다 - OnInitDialog()




6. 탭을 눌렀을 때 이벤트 처리는 현재 보여주는 윈도우는 닫고 선택한 윈도우를 보여준다 - OnTcnSelchangeTab()



7. 창이 삭제될 때 객체들을 삭제한다 - OnDestroy()





2017. 1. 17. 10:33

가상 메모리

- 물리적인 메모리(RAM)와 하드디스크의 페이징 파일 합한 것


- 사실 페이징 파일은 물리적인 RAM과 논리적으로는 동일하되 다만 속도가 좀 느린 메모리


- 응용 프로그램 입장에서 볼 때 자신의 주소 공간에 연결된 가상 메모리가 물리적인 RAM인가 페이징 파일인가는 전혀 신경쓰지 않음



- 운영체제의 안정성에도 큰 역할


- 각 프로세스의 주소 공간은 상호 독립적이기 때문에 프로세스 끼리 서로의 주소 영역을 침범할 수 없다


- 운영체제는 프로세스가 생성될 때마다 독립적인 4G 바이트의 주소 공간을 생성하고 물리적인 메모리를 논리적인 주소 공간에 연결



- 물리적인 메모리와 논리적인 주소 공간의 대응관계는 페이지 테이블이라는 표에 작성



- 페이지 테이블에는 가상메모리의 어디쯤이 응용 프로그램의 누구의 몇 번지에 연결되어 있다는 정보가 기록


- 응용 프로그램은 오로지 자신의 주소 공간 상의 번지만 다룸


- 프로세스는 자신에게 주어진 4G의 가상 주소 공간이 실제의 메모리인 것 처럼 사용


- 주소 공간 : 이 페이지 테이블에 기록 되어 있는 응용 프로그램이 참조하는 주소값


- 가상 주소 공간 : 실제로 존재하는 메모리가 아니라 다만 페이지 테이블에 기록되는 개념적인 주소

2016. 12. 8. 17:38

* 핵심은 모든 그리는 것을 비트맵에 그리고 나중에 

화면에 결과 비트맵을 보여준다


기존 DC 와 호환되는 Memory DC를 생성하고 거기에 비트맵을 선택하여

Memory DC를 이용하여 그림을 그린 다음

Bitmap을 기존 DC를 이용하여 그려준다



다시 순서를 정리하면


1. 기존 DC와 호환되는 Memory DC 객체 생성 - CreateCompatibleDC( );


2. 기존 DC와 호환되는 비트맵 객체 생성 - CreateCompatibleBitmap( );


3. 메모리 DC가 비트맵 객체를 선택 - SelectObject( )


4. 메모리 DC를 가지고 그림을 그림 - MoveTo, LineTo, Ellipse, Rect 등등


5. 비트맵 객체를 기존 DC를 가지고 그려줌 - BitBlt( )


6. 메모리 객체 해제


void CView::OnPaint(CDC* pDC)

{

// 1. memDC 객체 생성

CDC memDC;

memDC.CreateCompatibleDC(pDC);


// 2. 메모리 비트맵 생성

    CRect rect;

    GetClientRect(rect);

    CBitmap bitmap;

    bitmap.CreateCompatibleBitmap(pDC, rect.Width()rect.Height());


// 3. 메모리 DC 가 메모리 비트맵 선택

   CBitmap* oldmap = memDC.SelectObject(&bitmap);


// 4. 그려주기

   memDC.MoveTo(0, 0);

   memDC.LineTo(100, 100);


// 5. 그려주기

   pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);


// 6. 메모리 객체 해제

    memDC.SelectObject(oldmap);

    memDC.DeleteDC();

    bitmap.DelectObject();

}








2016. 12. 1. 11:28

* 더블 버퍼링


- 화면에 보여줄 버퍼와 내부 작업에 사용할 버퍼를 따로 유지

- 내부 버퍼에 미리 그림을 그린 후 화면 버퍼로 고속 전송

- 그리는 중간 과정을 숨겨진 내부 버퍼에서 처리



- 더블 버퍼링에 사용되는 내부 버퍼는 구체적으로 메모리 영역인데 

  이 메모리의 영역은 외부 버퍼, 즉 화면의 포맷과 호환되어야 한다

- 그래야 내부 버퍼에 그린 그림을 별도의 조작없이 외부 버퍼로 고속 전송 가능


- 윈도우즈에서는 내부 버퍼를 메모리에 직접 작성할 필요가 없는데

  왜냐하면 비트맵이 내부 버퍼 역할을 멋지게 대신함


- 화면 DC 와 호환되는 비트맵(색상 포맷이 같고 크기가 동일)을 생성한 후

  이 비트맵에 그림을 긜면 비트맵  자체가 내부 버퍼 역할을 함

- 비트맵에 그려진 화면을 전송할 때는 BitBlt 함수 사용




2016. 11. 22. 13:04

    ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);


    CRect rect;

    GetDesktopWindow()->GetWindowRect(rect);

    MoveWindow(rect);

    ShowWindow(SW_SHOWMAXIMIZED);

    RedrawWindow();


2016. 11. 18. 03:16

DC의 정의

프로그래밍/MFC 2016. 11. 18. 03:16

- 윈도우즈에서 화면상에 무엇인가를 그리는 과정은 상상외로 복잡하다


- 대충 출력하기는 쉽지만 꼭 필요할 때 최대한 짧은 시간에 최소한의 영역만 그리면서도 깜빡임을 최소화 하는 것은 보통 어려운 것이 아니다


- 그리기를 얼마나 빠른 시간에 효율적으로 할 수 있는가에 따라 응용 프로그램의 질에 큰 차이가 나게 되므로 결코 가볍게 다룰 수 있는 주제가 아니다


- 윈도우즈에서 그리기가 복잡하고 난해한 근본적인 이유는 여러 개의 프로그램이 동시에 실행되는 멀티 태스킹 운영체제


- 윈도우즈 프로그램은 화면을 혼자서 사용하지 못하며 화면에 출력하는 것이 아니라 자신이 차지하고 있는 윈도우에 그것도 허가된 영역에만 그릴 수 있다


- 게다가 공간적으로 제약이 따를 뿐만 아니라 한 번 그려 놓은 그림이 항상 그대로 있다고 보장되지 않는 시간적 제약도 있다


- 복수 개의 프로그램이 같은 화면에 겹쳐서 공존하다 보니 서로 간에 지켜야 할 약속과 제약이 존재하고 그리는 과정도 복잡하다


- 이런 복잡한 과정을 조금이나마 단순화하기 위한 장치가 DC


- DC에는 그리기에 필요한 여러 가지 정보가 저장되어 있으며 프로그램은 DC의 정보를 참조하여 그리기를 하고 DC의 정보를 조작하여 그리는 방법을 변경