본문 바로가기
Programming/Opencv(C++, MFC)

[MFC] FileListView 예제 및 분석

by MVP 2020. 11. 20.

들어가기에 앞서서..

이 포스트는 FileListView 예제 프로그램을 만드면서 사용된 함수들을 개인적으로 공부 및 정리하기 위해 생성한 포스트입니다. 이에 따라 가독성이 심히 떨어질 수 있음을 양해바랍니다.

 

0. FileListView 예제 정의

특정 폴더를 선택하여 해당 폴더의 파일들을 리스트형식으로 출력한다.

※ 조건 1) 확장자를 선택하여 출력 할 수 있어야 한다.

 

1. 사용된 컨트롤들

Edit Control 1개 - 현재 불러들인 폴더의 경로 출력용 

Button 1개 - 파일다이얼로그를 띄워  특정 폴더를 선택할 용도

ComboBox 1개 - 리스트로 출력할 파일의 확장자를 선택해 특정 확장자만 리스트에 출력하기 위한 용도 

List Control 1개 - 선택한 폴더 내의 파일을 리스트로 출력할 용도

 

2. 소스분석(사용된 함수 위주)

 

우선은 OnBnClickedFilepathBtn 이벤트부터 생성하고 다음과 같이 작성한다.

 

DeleteAllItems 함수

193 번째 줄의 m_FileListCtrl(리스트 컨트롤의 멤버 변수)의 DeleteAllItems 함수는 CListCtrl 클래스의 함수 중 하나인데 기능은 리스트 뷰 컨트롤의 모든 아이템을 삭제하는 단순한 기능이다. 리턴값은 성공시 0이 아닌 값들이며, 실패시 0을 리턴한다. 여기서는 리스트 뷰 컨트롤의 초기화를 위하여 사용하였다.

 

ITEMIDLIST 구조체

195 번째 줄의 포인터 ITEMIDLIST 구조체 pidlBrowse는 아이템 식별자들을 저장하고 있는 리스트를 가리키는 포인터 객체이다. ITEMIDLIST는 구조체 SHITEMID를 포함하고 있다.

 

CTime 클래스

198 번째 줄의 CTime 클래스의 FileLastWriteTime 객체를 선언했다. CTime 클래스는 절대 시간과 날짜를 나타내며 여기서는 읽어온 파일의 마지막 수정 날짜를 가져와 리스트에 출력할 용도로 사용하였다.

 

FILETIME 클래스

199 번째 줄의 FILETIME 클래스의 ftCt, ftLat, ftLwt와 200 번째 줄의 TempTime을 선언했다. CFILETIME 클래스는 파일과 연결된 날짜 및 시간 값을 관리하는 메서드를 제공한다. 여기서는 파일 만든 날짜, 최종 사용한 날짜, 액세스 날짜등을 얻기 위해서 사용하였다.

 

SYSTEMTIME 구조체

201 번째 줄의 SYSTEMTIME 구조체 SystemTime 객체를 선언했다. 날짜와 시간을 개별적으로 사용할 수 있다.

 

BROWSEINFO 구조체

203 번째 줄의 BROWSEINFO 구조체 변수 Brinfo를 선언했다. BROWSEINFO 구조체는 SHBrowseForFolder 함수와 유저가 선택한 폴더에 대해 받은 정보에 대한 파라미터를 저장하고 있다. 여기서 SHBrowseForFolder 함수는 사용자가 Shell 폴더만 선택 가능한 다이얼로그를 출력하는데 사용한다.

 

hwndOwner 함수

205 번째 줄의 brinfo의 hwndOwner 함수는 대화상자의 소유주를 지정하는 함수다. 소유자가 없을 경우는 NULL로 지정할 수 있다.

 

GetSafeHwnd 함수 ( 참고 : adnoctum.tistory.com/152 , CWnd에 대하여)

205 번째 줄의 brinfo의 hwndOwner 함수에 대입한 GetSafeHwnd(); 는 CWnd 클래스의 유일한, 실제의 윈도우 핸들을 반환한다. 아직 실제의 윈도우가 만들어져서 cWnd에 Attach한 것이 아니라면 NULL을 반환한다.

 

pidlRoot _browseinfoA 구조체의 멤버

206 번째 줄을 보면 brinfo의 pidlRoot 멤버에 null을 대입하였다. pidlRoot를 알기전에 먼저 pidl(Pointer to Item iDentifer List)을 알아보자면 pidl이 탄생한 이유부터 알아봐야 한다. 윈도우는 3.1에서 95로 버전업을 하면서 쉘을 파일 중심에서 객체 지향적인 관점으로 바라보게 되었는데 각 객체를 이전의 파일처럼 유일성을 보장하여 서로 구분할 수 있는 새로운 방법이 강구되었다. 그래서 쉘은 namespace(the desktop)에서 각각의 element들을 구분하기 위해서 PIDL을 사용한다. PIDL은 namespace의 루트부터 시작되는 identifier들의 리스트들을 가리키는 포인터이다.

위에서 잠깐 언급한 SHITEMID 구조체를 살펴 보자.

typedef struct _SHITEMID
    {
         UINT cbSize; // 구조체 크기, 자신 포함
         BYTE abID[1]; // 실제적인 데이터
    } SHITEMID

선언에는 UINT와 1BYTE짜리 배열이 있는데 실제로 1BYTE만 쓰는 일은 드물 것이다.  그러나 ITEMDLIST는 여러개의 SHITEMID 구조체가 연속적으로 나오도록 구현되어있기 때문에 다음 element를 얻기 위해서는 현재 포인터에서 cb값을 더하면 된다. cb값은 1 BYTE 배열의 크기가 아닌 SHITEMID 전체의 크기여야한다.  abID가 1BYTE짜리 배열로 선언되어 있지만 뒷부분도 넉넉하게 allocation되기 때문에 0이상 (cb-2)미만의 어떤 n에 대해서도 abID[n]과 같이 사용할 수 있다. 그래서 pidlRoot의 역할은 루트 폴더를 지정하는 것이다.

208 번째 줄 memset 함수를 이용해 BrInfo 구조체의 내용을 모두 0으로 초기화하였다.

 

pszDisplayName 구조체 멤버

209 번째 줄 BrInfo의 pszDisplayName 멤버에 strPath를 대입하였다. pszDisplayName은 선택된 아이템의 표시된 이름을 리턴한다.

Browseinfo 구조체 정의부

210 번째 줄 lpszTitle 멤버에 _T("불러올 폴더를 선택하세요. "); 을 입력하여 밑에 첨부한 이미지와 같이 파일 다이얼로그의 tree view control에 사용자를 위한 지시사항을 텍스트로 출력한다. 여기서 _T("")이 하는 역할은 유니코드를 대응하기 위해서 정의된 매크로이다. _T("")는 L""와 같다. 상수 문자열들은 1바이트로 구성되어있는데 이를 통해 문자열들을 2바이트로 바꿀 수 있다.

211번째 BrInfo의 uflags 멤버에 BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS; 이런식으로 대입했는데 다이얼로그의 기능을 확장할 때 사용하는 플래그들이다. 여기서 쓰인 플래그들을 살펴보자면 BIF_NEWDIALOGSTYLE는 구버전 다이얼로그의 인터페이스를 개선한 새 인터페이스를 사용하는 플래그이다. 파일 다이얼로그의 크기 변경 기능, 새 폴더 생성 기능, 드래그 드랍 기능 등 여러가지 새로운 기능들이 추가된다. BIF_EDITBOX는 하단 이미지처럼 "폴더(f) : " 텍스트박스와 EDITBOX가 추가되는 플래그이다. BIF_RETURNONLYFSDIRS 플래그는 대화상자에서 디렉토리만 설정할 수 있도록 하는 플래그이다. 

BIF_NEWDIALOGSTYLE 옵션 OFF ON

SHBrowseForFolder 함수 

214번째 줄 ITEMIDLIST 구조체 포인터 변수인 pidlBrowse에 SHBrowseForFolder 함수에 &BrInfo를 넣어 대입한다. SHBrowseForFolder 함수는 폴더 선택이 가능한 다이얼로그를 출력하는 기능을 한다.

 

215번째 줄에서 TCHAR형 200바이트 크기의 배열인 szPathName 변수를 선언했다. 여기서 TCHAR 타입은 유니코드에 대응할 수 있는 타입이다.

 

SHGetPathFromIDList 함수

217번째 줄에서 SHGetPathFromIDList(pidlBrowse, szPathName); 으로 함수를 호출했다.  SHGetPathFromIDList는 item identifer list를 파일 시스템 경로로 변환하는 기능을 하는 함수이다. 여기서 첫번째 인수는 pidl를 받으니 pidlBrowse를 넣고 두번째 인수는 pszPath를 받으므로 szPathName을 넣는다. 이렇게하면 pidlBrowse의 리스트를 변환하여 TCHAR형 배열에 넣게된다. 이어서 219번째 줄의 CString strTmpPath 변수에 szPathName을 LPCTSTR 타입으로 형변환하여 대입한다. 또한 221번째 줄에서 strTmpPath 변수에 자기 자신과 "\\*.*" 을 더하였는데 이렇게되면 사용자가 선택한 폴더의 경로에 "\\*.*"가 합쳐지게 된다. 이렇게 합친 값을 가지고 있는 strTmpPath는 CFileFind 클래스의 FindFile 함수를 사용하는데 사용될 것이다.

 

CFileFind 클래스

224 번째 줄에서 CFileFind 클래스의 finder 객체를 선언하였다. CFileFind 클래스는 로컬 파일 검색을 수행하고 인터넷 파일 검색을 수행하는 CGopherFileFind 및 CFtpFileFind의 기본 클래스이다. 기본적으로 여기서는 디렉토리와 파일을 찾는데 사용하는 이 예제의 핵심 클래스이다.

 

226 번째 줄에서 BOOL 타입의 bworking 변수에 finder.FindFile(strpTmpPath); 를 대입하였다. 여기서 FindFile은 주어진 경로의 파일을 찾는 역할을 한다. 주어진 경로의 끝에 *.*을 넣으면 그 경로의 하위로 모든 파일을 찾는다. 파일이 존재할 경우 FileNextFile() 함수를 호출하고 파일이 존재하지 않으면 0을 리턴한다.

 

228 번째 줄과 229번째 줄에서 CString 타입의 fileName 과 DirName 변수를 선언하였는데 변수 이름에서 유추하다 시피 각각 찾은 파일의 이름과 경로를 저장하게 쓰게될 변수들이다.

 

231 번째 줄에서 DirName에 szPathName의 값을 대입한다.

 

232 번째 줄에서 DirName의 경로 텍스트 값을 TextView 다이얼로그의 EditBox 컨트롤인 FilePath_edit에 출력한다.

 

234 번째 줄은 vector<CString> vstr; 으로 CString형 vector 컨테이너를 선언하였는데 여기서는 파일 이름을 배열에 저장은 했지만 이 것을 실제로 사용하지는 않았다. 나중에 파일 이름을 가지고 무엇인가 다른걸 할 때 쓰면 될 것 같다. 일단 이 예제에서는 지워도 무방하다.

 

236 번째 줄에 선언된 정수형 Extension_index 변수에 ComboBox 컨트롤의 멤버 변수인 m_comboExtensionList의 GetCurSel 함수의 반환값을 대입하였다. 즉 현재 ComboBox에서 선택된 텍스트 값을 정수형으로 반환받아서 ComboBox에서 선택된 확장자에 따라 조건문을 이용해서 이 Extension_index에 들어간 값에 따라 다른 결과를 출력하는데 쓰였다.

 

237 번째 줄에서 int i = 0 을 선언하였는데 이는 바로 다음 줄에 쓰이는 while 문안에서 index로 활용될 것이다.

 

 

FindNextFile 함수

239 번째 줄부터 bWorking의 값에 따라 while문으로 반복 될 것이다. 그 바로 다음 줄인 241번째 줄에 bworking = finder.FindNextFile(); 으로 대입문이 작성되어 있다. 여기서 FindNextFile() 함수는 발견된 파일이 디렉토리에서 마지막 파일이거나 오류가 발생한 경우 0을 리턴하므로 이 루프를 빠져 나간다.

 

IsArchived 함수

243번째 줄에선 if문을 finder.IsArchived()의 반환값을 조건으로 사용한다. 여기서 IsArchived 함수는 발견된 파일이 보관되었는지를 확인하고 보관되지 않았으면 0을 반환한다.

 

GetFileName 함수

245번째 줄에서 CString _fileName을 선언하고 finder.GetFileName(); 함수의 결과값을 대입한다. GetFileName 함수는 찾은 파일의 이름을 반환해준다.

 

MakeLower 함수

246번째 줄에서 _fileName.MakeLower() 함수를 호출하였는데 여기서 MakeLower 함수는 Cstring 타입인 _fileName의 모든 문자열을 소문자로 변환해준다. 추후 _fileName의 값에 들어있는 확장자가 jpg가 아니라 JPG라던가 대소문자가  섞여 있을 경우 조건문의 길이가 늘어나게 되기 때문에 모든 문자열을 소문자로 변환해준다. MakeUpper() 함수로 대문자로 변환하고 조건문을 그에 맞춰 사용해도 상관없다.

 

248 번째 줄은 _fileName의 값이 .이거나, .. 혹은 Tumbs.db일 시 다음 코드 실행을 건너 뛴다.

 

CreateFile 함수

259 번째 줄은 HANDLE 타입의 h 변수를 선언하고 CreateFile 함수의 반환값을 대입한다. 여기서 HANDLE 자료형은 운영체제 내부에 있는 어떤 리소스의 주소를 정수로 치환한 값이다. 그리고 CreateFile 함수는 파일을 Open하는 기능을 가지고 있고 반환값은 HANDLE이다. 이 함수가 받는 인수들을 살펴보자.

첫번째 인수로 Open하고자 하는 파일의 이름을 받는다. 여기서는 DirName과 FileName 사이에 \를 더한 값을 사용하였다.

두번째 인수는 dwDesiredAccess 변수인데 접근 방법을 명시하기 위하여 사용한다. 여기서 사용한 값은 GENERIC_READ인데 일반적으로 사용하는 읽기를 뜻한다.

세번째 인수는 dwShareMode 변수인데 개체의 공유 방식을 지정한다. 여기서는 NULL 값을 지정했으므로 개체를 공유 할 수 없는 상태가 되고 핸들이 닫히기 전까지 다른 열기는 실패하게 된다. 

네번째, 다섯번째 인수는 파일의 생성 방식을 명시한다. 여기서는 네번째 인수인 lpSecurityAttributes에 NULL 값을 지정했는데 이는 CreateFile에서 반환된 핸들은 응용 프로그램이 생성할 수 있는 하위 프로세스에 의해 상속될 수 없으며 반환된 핸들과 연결된 파일이나 장치는 디폴트 보안 설명자를 얻는다. 다섯번째 인수는 OPEN_EXISTING 값을 넘겨줬는데 이는 파일이 존재하면 열고, 존재하지 않으면 에러코드로 ERROR_FILE_NOT_FOUND(2)를 설정하게 된다.

여섯번째 인수는 파일의 기타 속성을 지정하는데 FILE_ATTRIBUTE_NORMAL 값을 줬으므로 별 다른 속성을 가지지 않게 된다.

일곱번째 인수는 GENERIC_READ으로 액세스했을 때 템플릿 파일을 제공하는데 템플릿 파일은 WIN NT에서만 제공되는 파일이다. 그러므로 그외의 운영체제에서는 항상 NULL로 세팅해야 한다.

여기서는 파일의 시간을 얻기 위해 핸들을 사용하였지만 사실 이렇게 하지 않고도 더 간편한 방법이 존재한다. 이는 추후 설명할 것이다.

CreateFileA 함수 선언부

GetFileTime 함수

251 번째 줄에서는 GetFileTime 함수를 호출하였는데 이 함수는 파일 혹은 폴더의 생성, 마지막 액세스, 마지막 수정 날짜와 시간을 검색하는 기능을 한다.

첫번째 인수로 날짜와 시간을 검색할 파일 혹은 폴더에 대한 핸들을 받는다. 이때 이 핸들은 GENERIC_READ 액세스 권한이 있는 CreateFile 기능을 사용하여 만든 것이어야 한다. 

두번째 인수는 파일의 생성 시간, 세번째 인수는 파일의 마지막 액세스 시간, 네번째 인수는 파일의 마지막 수정 시간을 전달 받은 인수에 각각 저장한다. 여기서 사용할 시간은 마지막 수정 시간이 된다. 참고로 사용하지 않을때는 NULL을 넣어주면 된다. 그리고 이 시간을 그대로 사용하는 것이 아니라 FILETIME으로 변환해서 사용할 것이다.

 

FileTimeToLocalFileTime 함수

253 번째 줄에서 FileTimeToLocalFileTime 함수를 이용해 FileTime 형식의 마지막 수정 시간을 LocalFileTime 형식으로 바꿔준다.

 

FileTimeToSystemTime 함수

254 번째 줄에서 FileTime 형식의 마지막 수정 시간을 SystemTime 형식으로 바꿔준다.

 

255번째 줄에서 CString 타입의 timeStr 변수를 선언 후 timeStr에 Format 함수를 이용해서 SystemTime의 값들을 원하는 포맷 형식으로 넣어준다.

 

257번째 줄에서는 CString 타입의 GLWT_timeStr 변수를 선언하였는데 위에서 언급한 간편한 방법을 위해서 사용될 것이다.

 

258번째 줄에서는 Extension_index가 2이고 _fileName의 Find 함수에서 ".jpg"를 인수로 넣었을 때 리턴 값이 -1이 아닐 경우 if문에 진입한다. 여기서 Extension_index가 2인 경우는 ComboBox에서 2에 해당하는 .jpg를 선택했을 경우에만 이 조건문에 진입하게 했다. 이는 OninitOnInitDialog에서 정의하였고 밑의 내용에서 설명할 것이다.

Find 함수는 인수에 해당하는 ".jpg"가 해당 변수의 문자열에서 찾을 수 없을 경우 -1을 리턴한다. 찾았을 경우엔 일치하는 첫번째 문자의 인덱스를 반환한다. 

 

push_back 함수

260 번째 줄에서 사용된 push_back 함수는 벡터 배열의 끝에 요소를 추가하는 함수이다. 루프문에 진입했을 때 _fileName은 vector 배열의 끝에 차곡차곡 들어가게 된다.

 

GetLastWriteTime 함수

262 번째 줄은 250 번째 줄 부터 254번째 줄에서의 핸들을 이용해 파일 시간을 구하는 방법과는 다른 방법으로 파일 시간을 구하는 것인데, 이미 존재하는 CFileFind 클래스의 객체의 함수를 이용하므로 훨씬 간편하다는 장점이 있다. finder.GetLastWriteTime(FileLastWriteTime)은 CTime 객체인 FileLastWrtieTime를 인수로 사용하며 성공시 Nonzero를 리턴하며 FindNextFile 함수가 CFileFind 객체에서 한번도 호출되지 않았을 때만 0을 호출한다. if문으로 진입했을 때 264번째 줄에서 FileLastWriteTime의 값을 CTime 클래스의 Format 함수를 이용하여  Date-Time 값으로 변환 뒤 CString 타입의 GLWT_timeStr 변수에 대입한다.

267번째 주석처리 되어있는 줄은 핸들을 이용해 파일 시간을 구하는 코드이며 핸들을 이용하던 GetLastWriteTime 함수를 이용하던 원하는대로 사용하면 된다.

 

CListCtrl::InsertItem 함수

그다음 265 번째 줄에서 리스트 컨트롤의 멤버 변수인 m_FileListCtrl의 InsertItem 함수를 호출하여 리스트 컨트롤의 1번째 열 i번째 행에 GLWT_timeStr의 값을 넣어 파일의 마지막 수정 시간을 넣는다. 

 

 

SetItemText 함수

268번째 줄에서 m_FileListCtrl.SetItemText(i, 1, _fileName); 으로 SetmItemText 함수를 호출하였는데 SetmItemText 함수는 리스트의 subitem을 바꾸는데 주로 사용하는 함수이다. InsertItem 함수같은 경우 Item이라 부르는 1번째 행의 값만 삽입할 수 있기 때문에 그다음 2번째 행부터는 SetItemText 함수를 이용하여 리스트를 i번째 열 1번째 행에 _FileName의 값을 넣어 1번째 행을 파일 이름으로 채워 넣는다. 

 

271번째부터 285번째 줄까지는 콤보박스의 인덱스 및 확장자에 따라 리스트에 들어가는 값이 바뀌는 것일 뿐 위에서 설명한 코드와 내용은 같다.

 

287번째 줄의 CloseHandle(h); 함수는 핸들값을 반환하며 핸들의 프로세서를 참조하지 않게된다.

 

이제 CDlgCFileListViewDlg::OnInitDialog 함수에서 추가 초기화 작업 코드를 작성한다.

108~110번쨰 줄은 콤보박스 컨트롤의 멤버 변수인 m_comboExtensionList의 AddString 함수를 이용하여 콤보 박스에 String을 넣어서 유저가 확장자를 선택 할 수 있도록 한다.

 

112번째 줄에서 SetCurSel 함수를 호출하여 기본적으로 프로그램 실행시 선택될 확장자를 지정한다. 여기서는 0을 인수로 넣었으므로 0번째 인덱스인 "ALL"이 기본적으로 선택된다.

 

115번째 줄은 문자형 포인터 배열 변수인 szText을 선언하고 배열의 0번쨰 인덱스에 "날짜"와 1번째 인덱스에 "파일 이름"을 넣어 초기화했다. 이는 컬럼 헤더가 될 것이다.

 

116번째 줄은 CRect rt; 처럼 CRect 클래스의 객체 rt를 선언했다. CRect 클래스는 Rect 구조체에서 파생된 클래스이며 사각형의 상단 왼쪽 코너와 하단 오른쪽 코너의 좌표를 저장한다.

 

118번째 줄은 리스트 컨트롤 멤버 변수의 함수인 GetClientRect에 인수로 &rt를 넣어 리스트 컨트롤 멤버 영역에서의 좌표값을 반환한다.

 

119번째 줄은 SetExtendedStyle 함수를 호출하는데 인수로 2개의 플래그를 사용하였다. 이 함수는 리스트 컨트롤의 스타일에 확장 속성을 적용 시킬 수 있는 함수이다. 여기서 사용된 플래그들을 살펴보자면 첫번째 플래그 LVS_EX_GRID_LINES는 플래그 이름에서 알 수 있듯이 리스트 컨트롤에 그리드(격자)를 생성한다.

두번째 플래그 LVS_EX_FULLROWSELECT는 row를 선택했을때 그 row에 해당되는 전체 item이 선택되도록 한다.

 

120번째 줄은 정수형 배열 nWid 변수를 선언했는데 {200, rt.Width() - 200} 으로 초기화를 하였다. 여기서 사용된 Width 함수는 사각형의 폭을 구할 수 있는 함수이다. 여기서는 리스트 컨트롤의 폭을 구하게 된다. 그리고 그 값에서 200을 뺀 값을 nWid 배열에 넣었다.

 

121번째 줄에서 LV_COLUMN 구조체 lcol 변수를 선언했다. LV_COLUMN 구조체는 리스트 컨트롤의 View가 report 상태일 때 column의 정보를 저장하고 있다. 

 

123번째 줄에서 lcol.mask 멤버 변수에 플래그들을 대입하고있는데  mask 멤버 변수는 각 멤버가 유효한 정보를 가지고 있는지를 명시하는 변수이다. 

여기서 사용된 플래그를 살펴보자면 첫번째 플래그인 LVCF_FMT는 fmt 멤버가 유효하다는 뜻이다. 여기서 fmt 멤버란 컬럼 헤더과 하위 컬럼의 텍스트를 정렬하는 멤버이다.

두번째 플래그인 LVCF_SUBITEM은  iSubItem 멤버가 유효하다는 뜻이다. iSubItem 멤버는 구조체를 참조하는 부 아이템의 원 베이스 색인 또는 구조체를 참조하는 아이템의 제로 베이스 색인을 뜻하는데 서브아이템의 인덱스라고 보면 된다.

세번째 플래그인 LVCF_TEXT는 pszText 멤버가 유효하다는 뜻이다. pszText는 아이템 텍스트를 명시하는 String의 주소이다.

네번째 플래그인 LVCF_WIDTH는 cx 멤버가 유효하다는 뜻이다.  cx 멤버는 컬럼의 폭을 픽셀로 저장하는 멤버이다. 

그다음 124번째 줄에서 fmt 멤버에 LVCFMT_LEFT 플래그를 대입하였는데 이는 칼럼의 정렬을 왼쪽 정렬하는 플래그이다. _CENTER, _LEFT, _RIGHT를 지원한다.

 

다음은 for 반복문으로 리스트의 칼럼에 실제로 값들을 넣는다.

lCol.pszText 멤버에 szText[i]를 넣어 i 가 0일 때 날짜 를 대입하고 1 일 때 파일 이름을 대입한다.

lCol.iSumbitem 멤버에 i 를 넣어 서브 아이템의 인덱스를 지정한다.

lCol.cx 멤버에 nWid[i]를 넣어 i가 0일 때 200을 대입하고 1일 때 Width() - 200 을 대입한다.

마지막으로 리스트 컨트롤의 멤버 변수인 m_FileListCtrl의 함수 InsertColumn을 호출하여 첫번째 인수로 i를 넣어 컬럼의 순서에 맞게 리스트 컨트롤에 LVCOLUMN 구조체 타입의 각 정보들이 저장되어 있는 lCol 변수를 삽입한다.

 

이렇게 해서 해야할 소스 작업은 끝이 났다. 이제 프로그램을 실행 해보자.

실행 화면

실행후 콤보박스에 All이 기본값으로 잘 설정되어 있는 것을 확인할 수 있다.

콤보박스를 클릭하여 All, bmp, jpg 확장자들을 선택할 수 있게끔 텍스트들이 정상적으로 출력된다.

폴더를 선택 할 수 있는 다이얼로그가 출력되고 폴더 선택, 새폴더 만들기 등이 정상적으로 되는지 확인해본다.

파일 리스트 출력 화면

여기서 폴더를 누르고 확인을 누르면 폴더에 들어있던 파일들의 이름과 날짜가 리스트에 정상적으로 출력되는 것을 확인 할 수 있다. 

원한다면 추가로 소스코드를 수정하여 입맛에 맞게끔 사용해보자 -끝-