간단한 자동 업데이트 프로그램이 필요해서 작업중. 네트워크상으로 뭔가 주고받는건 정말 오랜만에 만들어본다.

mfc로는 해본 적이 없는듯? 아무튼 기록용 글. 나중에 또 찾을거같아서.


* Rich Edit 2.0

  1. 단순히 추가만 해서는 사용이 불가능하다. 실행조차 안됨.
  2. "AfxInitRichEdit();"을 코드 상에 추가해야한다. OnInitDialog에 넣으면 될 줄 알았는데 안 됨.
  3. InitInstance내에 넣어야 한다고 한다. 하지만 이 코드는 ☆☆☆☆Dlg.cpp에는 없음.
  4. 알고보니 (적어도 나는) 절대 들어갈 일 없는 ☆☆☆☆.cpp파일에 있었다.
  5. 추가하니 잘 뜬다.
귀찮아서 안쓰기로 했다. 역시 리스트박스가 최고

* Progress Bar

  • 일반적으로 파일 다운 진행같은 경우 스레드로 만들어서 돌리는 모양.
  • 무한 진행은 SetMarquee(스레드없어도 문제X). 인자는 얼마나 천천히 진행하느냐 인 것 같은데, 0이어도 별 문제 없음.

* Ping

https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa366050(v=vs.85).aspx

귀찮네. 안 할래.


* HTTP 받기

WinInet이용. 인터넷 핸들 열고, URL 여는 식인 듯. 아 귀찮아.

이거때문에 파일 호스팅할 서버 찾고 홈페이지까지 열었다. 주객이 전도된 느낌마저 있다....

apache상에서 password protection 된 폴더는 Unauthorized가 뜬다 이거 어떻게 해결할지 고민중...

-> 약간 다른 함수를 쓰기로 했다.

https://support.microsoft.com/ko-kr/kb/234913 참조

첫번쨰 방법은 실패 -> username과 password지정해서 connect

두번째 방법은 http://microsoft.public.inetsdk.programming.wininet.narkive.com/8PDvK30R/filled-username-password-in-internetconnect-but-internetreadfile-shows-unauthorized

이것도 실패.......................... 아파치 폴더 잠금 때문인지 아닌지 모르겠지만 그냥 FTP를 쓰도록 하기로 하였다...^v^...


* ZIP 압축 해제

운영체제 자체에서 제공되는 걸 이용하는 방법, 직접 헤더 따서 읽어들이는 방법, 라이브러리를 이용하는 방법 등이 있다.

솔직히 이미 만들어져 있는 라이브러리 쓰는게 천배만배 나은 걸 아는데 무슨 생각인지 쓰기 싫다. ZIP이 생각보다 구조가 그리 복잡하진 않은듯. 압축된 경우 푸는 방법이 좀 의문이긴 하지만 뭐 푸는 법이 있겠지...

 기본적으로는 리소스 뷰에서 다이얼로그의 설정을 적당히 바꾸면 항상 위 설정과 프로그램 투명도를 바꿀 수 있긴 하다. 하지만 프로그램 내에서 자유롭게 설정을 바꿀 수 있게 하려면 다음과 같은 방법을 취하면 된다.

 

 

1. topmost(항상 위)

 

 체크박스로 TOPMOST를 설정 및 해제하는 예시이다. SetWindowPos를 이용하여(앞에 '::'를 붙여야한다.) HWND_TOPMOST를 설정해주고, 해제할 때에는 HWND_NOTOPMOST를 설정해주면 간단하게 오케이! 뒤의 SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW는 창을 움직이지 않고, 사이즈를 변경하지 않으며, 창은 띄우라는 의미로 저렇게 설정하였는데 더 축약시켜서 보기좋게 쓰는 방법이 있을 거라고 본다.

 

 

2. 투명도 조절

 

 투명도 조절은 Layered window만 가능하도록 되어있다. 그러므로 윈도우의 스타일을 수정해 주어야 한다. 해당 스타일은 GWL_EXSTYLE부분에 있으므로 SetWindowLong과 GetWindowLong을 잘 조합하여 설정해 준다.

 

 Layered window로 스타일을 바꿔 주었다면 SetLayerdWindowAttributes를 통해 투명도 설정이 가능하다. 두번째 인자는 컬러 키를 이용한 투명화를 해야할 때 사용되는데, 필자는 전체 창의 투명도를 바꿔야 하므로 NULL로 지정했다. 세번째 인자는 투명도 값이며 0~255의 범위를 가진다. 네번째 인자는 전체 창 투명도를 조작할 지, 컬러키 투명도를 조작할 지 플래그를 지정한다.

 

적당히 값을 넣어주면 다음과 같은 화면을 볼 수 있다.

 

 

 

예전에 현재 프로그램의 투명도를 바꿔 VS위에 겹쳐놓고 업무시간에 딴짓할 때 쓰는 프로그램을 짰던 기억이 새록새록하다.

 

 

참고자료

MSDN, "SetWindowPos function". http://msdn.microsoft.com/ko-kr/library/ms633545.aspx

MSDN, "Layered Windows". http://msdn.microsoft.com/en-us/library/ms997507.aspx

MSDN, "SetLayeredWindowAttributes function". http://msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx

 리스트 컨트롤은 목록 형식의 컨트롤로, 리스트박스와 약간 다른 점이 있습니다. 예를 들어 상단에 열 제목을 추가하는 등의 동작이 가능합니다. 이번에는 리스트 컨트롤을 사용하는 방법에 대해 알아보겠습니다.




우선 대화상자에 리스트 컨트롤을 선택하고 적당하게 배치합니다.



Properties에서 View 항목을 Report로 바꾸어 줍니다.




바꾸어 주었으면 열의 헤더가 생긴 것을 확인할 수 있습니다.




리스트 컨트롤을 선택하고 우측 마우스를 클릭하여 변수 추가를 선택해 줍니다.




멤버 변수 추가 마법사에서 원하는 변수 이름을 적고 '마침'버튼을 클릭합니다.




그러면 DoDataExchange 함수에 빨간 박스와 같은 코드가 작성된 것을 볼 수 있습니다.



이후 InitDialog 함수에서 아래 코드와 같이 작성합니다.



// 헤더 설정

LV_COLUMN m_lCol; // 열의 헤더 부분을 담당합니다.


m_lCol.mask = LVCF_TEXT | LVCF_WIDTH; // 변경할 부분을 마스킹하여 설정합니다.


m_lCol.pszText = "테스트1"; // 출력될 문자열입니다.

m_lCol.cx = 100; // 출력될 가로 폭입니다.

m_cList.InsertColumn( 0, &m_lCol ); // 열의 번호와 구조체의 주소를 넘깁니다.


m_lCol.pszText = "테스트2";

m_lCol.cx = 100;

m_cList.InsertColumn( 1, &m_lCol );


// 값 삽입

LV_ITEM m_lItem;


m_lItem.mask = LVIF_TEXT;


m_lItem.pszText = "아이템1";

m_lItem.iItem = 0;

m_lItem.iSubItem = 0;

m_cList.InsertItem( &m_lItem );


m_lItem.pszText = "아이템2";

m_lItem.iItem = 1;

m_lItem.iSubItem = 0;

m_cList.InsertItem( &m_lItem );


// 비어 있는 열의 값 추가(2번째)

m_lItem.pszText = "아이템3";

m_lItem.iItem = 0;

m_lItem.iSubItem = 1;

m_cList.SetItem( &m_lItem );


m_lItem.pszText = "아이템4";

m_lItem.iItem = 1;

m_lItem.iSubItem = 1;

m_cList.SetItem( &m_lItem );




컴파일하면 이렇게 리스트가 뜨는 것을 볼 수 있습니다.

같은 컨트롤의 개수가 많을 때 같은 이벤트 처리기를 여러개 만들 경우, 보기도 안좋고 번거로운 작업이 필요합니다.

이벤트 처리기를 한 데 묶어 쓰는 방법입니다.




우선 테스트를 위해 버튼을 네개 만들어 두었습니다. 각각의 ID는 IDC_BUTTON1~IDC_BUTTON4까지입니다.




대화상자 cpp파일 내에 처리 내용이 담긴 함수를 만들어 줍니다. 인자는 UINT 형 변수이고 반환형은 없어야 합니다.

인자로 ID가 넘어와 이걸 통해 컨트롤 간의 구분이 가능합니다. 함수의 원형은 헤더 파일에 선언합니다.




메시지 맵에 빨간 박스와 같이 적습니다. ON_COMMAND_RANGE 매크로인데, 첫번째 인수는 시작 ID, 두번째 인수는 끝 ID, 세번째 인수는 반환형이 void이고 인자가 UINT인 함수의 주소를 넘겨줍니다.

그러면 IDC_BUTTON1~IDC_BUTTON4까지의 컨트롤에 이벤트가 발생할 경우 해당 함수가 호출됩니다.




잘 작동하는 것을 볼 수 있습니다.

에디트박스의 글자 크기를 변경하고 싶을 때는 CFont를 이용하면 된다.

우선 CFont의 인스턴스를 전역에 선언해둔 후(지역에 선언하면 이후 커서만 커지고 글자 크기는 그대로가 된다)

컨트롤을 GetDlgItem으로 가져온 후, SetFont로 앞에서의 인스턴스의 주소를 넘겨주면 된다.


CFont g_editFont;

g_editFont.CreatePointFont( 200, TEXT( "굴림" ) );

GetDlgItem( IDC_EDIT_NUM )->SetFont( &g_editFont );



<정상적으로 된 경우>


<폰트 인스턴스를 지역에 선언한 경우>

#include <afxwin.h>

// MFC를 사용해서 윈도우 프로그램을 작성할 때는 반드시 <afxwin.h> 헤더를 포함시킨다.


#include "Cmmsdk.h"

#include "CmmsdkDef.h"


/*

class CMyWindow : public CWnd

// CWnd의 파생 클래스를 생성.

// PostNcDestroy라는 가상 함수를 재정의. 윈도우가 파괴될 때 MFC 프레임워크에 의해 호출된다.

{

public:

virtual void PostNcDestroy();

};


void CMyWindow::PostNcDestroy()

{

delete this; // 창을 닫을 시 자신의 메모리를 삭제

}

*/


class CMainFrame : public CFrameWnd

// MFC로 윈도우 창을 만들기 위해서는 CFrameWnd에서 파생된 클래스를 만들어야 한다.

{

};


class CMFCTest : public CWinApp

// MFC는 CWinApp라는 클래스를 제공하는데, MFC를 사용하는 모든 윈도우 프로그램은

// CWinApp 클래스의 파생클래스를 반드시 1개 만들어야 한다.

{

public:

virtual BOOL InitInstance();

virtual BOOL ExitInstance();

};


BOOL CMFCTest::InitInstance()

// CWinApp 클래스는 InitInstance() 라는 가상 함수를 제공하며,

// 사용자는 반드시 이 가상함수를 재정의해서 응용 프로그램의 초기화 코드를 만든다.

// 초기화에 성공하면 TRUE를, 실패하면 FALSE를 리턴한다.

// 함수를 재정의 할 때는 CWinApp::InitInstance()를 먼저 한번 호출해야 한다.(언어 관련 리소스 초기화)

{

CWinApp::InitInstance();


//==================================================

// CWnd 윈도우 1

//==================================================

CMainFrame* pFrame = new CMainFrame;

// 사용자가 만든 클래스에 대해서 new를 사용해 객체를 생성한다.

// MFC가 종료될 때 new를 이용해 할당받은 메모리는 자동으로 소거되므로 delete해주지 않아도 된다.


m_pMainWnd = pFrame;

// CWinApp의 멤버 변수인 m_pMainWnd에 반드시 사용자가 만든 윈도우 객체의 주소를 넣어야 한다.

// 윈도우 생성 이후 MFC가 해당 포인터 변수를 이용해 몇 가지 작업을 자동으로 수행한다.\


pFrame->Create( 0, "MFC 테스트!!" );

// 실제 윈도우를 생성하는 함수. 첫 번째 인자에는 윈도우 클래스 이름이 들어가며,

// 0이 전달되면 MFC가 내부적으로 윈도우 클래스를 등록해서 사용하게 된다.


pFrame->ShowWindow( SW_SHOW );

// 윈도우를 보여주기 위해 꼭 사용해야 하는 함수.

// SW_SHOW 부분은 바꾸어서 창의 크기를 조절하는 등의 변경이 가능


pFrame->UpdateWindow();

// 생략해도 되나, 이 함수를 호출해 주면 조금 빠르게 동작하는 것 처럼 보일 수 있다.


/*

//==================================================

// CWnd 윈도우 2

//==================================================

CString classname = AfxRegisterWndClass(

CS_HREDRAW | CS_VREDRAW,

LoadStandardCursor( IDC_ARROW ),

( HBRUSH )::GetStockObject( WHITE_BRUSH ), // WinAPI 함수이므로 앞에 스코프 연산자(::)를 붙인다.

LoadStandardIcon( IDI_APPLICATION ) );

// CFrameWnd를 사용해서 윈도우를 만들 경우 사용자가 직접 윈도우 클래스를 만들지 않아도 MFC가 내부적으로 등록

// CWnd클래스를 사용해서 윈도우를 만들 경우 반드시 윈도우 클래스를 먼저 등록.

// 윈도우 클래스 스타일, 커서, 배경 브러시, 아이콘


CMyWindow * pWnd = new CMyWindow;

pWnd->CreateEx( 0, classname, "CWnd로 만든 윈도우", WS_OVERLAPPEDWINDOW, CRect( 0, 0, 300, 300 ), 0, 0 );

// 확장 윈도우 스타일, 윈도우 클래스 이름(윈도우2), 타이틀 문자열,

// 윈도우 스타일, 윈도우 위치 및 크기, 부모 윈도우 포인터, ID


pWnd->ShowWindow( SW_SHOW );

pWnd->UpdateWindow();

// 화면상에 출력

*/


if( cmmLoadDll() == TRUE ) // DLL로딩 함수 실행

{

AfxMessageBox( "DLL 로딩에 성공하였습니다!!" );

}

else

{

AfxMessageBox( "DLL 로딩에 실패하였습니다!!" );

AfxGetMainWnd()->SendMessage( WM_CLOSE ); // 종료 메시지 보냄

}


return TRUE;

}


BOOL CMFCTest::ExitInstance()

{

cmmUnloadDll();

return CWinApp::ExitInstance();

}


CMFCTest test;

// 사용자가 만든 파생클래스에 대해서 객체를 전역적으로 한 개만 생성해야 한다.



/*

MFC는 내부적으로 WinMain() 함수를 제공한다.

*/

+ Recent posts