안녕하십니까 이번 포스팅에서는 작업관리자에서 사용된 함수들을 살펴보겠습니다.

- void InsertItemDlglist(HWND *DesktopHWND1, TCHAR **DesktopWND_title1, int count);

리스트뷰에 항목을 추가하는 함수입니다. 인자는 데스크탑 핸들의 배열, 각 핸들의 타이틀명이 담긴 배열, 핸들의 개수 입니다.

- int checkDesktopWND_title(TCHAR *DesktopWND_title1);

데스크탑 핸들의 타이틀 명을 체크하는 함수입니다. 리스트 뷰에 추가되지 않은 핸들을 제외하기 위해 사용합니다. 인자는 해당하는 핸들의 타이틀 명입니다.

- int CMP_DesktopWND_title(void);

데스크탑 핸들의 타이틀을 비교하는 함수입니다. 윈도우의 타이틀 명이 변경되었을 때 리스트 뷰에 목록을 다시 추가하기 위해 사용합니다. 전역변수가 쓰이므로 인자는 받지 않습니다.

- void free_DesktopWND_title(void);

 핸들의 타이틀 명을 동적할당하여 저장하였으므로 이를 해제하기 위해 사용합니다.

- void free_DesktopWND_title2(void);

 변경되기 전의 윈도우 타이틀명이 저장된 배열을 해제하기 위해 사용합니다.

- void LVHeaderSort(HWND hWnd,TCHAR *DlgListHeader_Str[],int columnindex);

오리지널 작업관리자에서는 리스트 뷰 헤더 버튼을 누를시 작은 삼각형 아이콘이 생김으로써 오름차순인지 내림차순인지를 확인시켜줍니다. 이를 구현하기 위해 만든 함수입니다.

- void asce_sort(void);

리스트 뷰의 아이템들을 오름차순으로 보여주기 위해 데스크탑의 핸들과 타이틀명이 저장된 배열을 오름차순으로 정렬하는 함수입니다.

- void desc_sort(void);

리스트 뷰의 아이템들을 내림차순으로 보여주기 위해 데스크탑의 핸들과 타이틀명이 저장된 배열을 내림차순으로 정렬하는 함수입니다.

- void GetLVHeaderSort(void);

리스트뷰의 헤더가 오름차순 상태인지 아니면 내림차순 상태인지를 읽어와 정렬 함수를 호출하는 함수입니다.

- void MoveWND(HWND hWnd);

작업관리자의 크기가 변경되었을 경우 이에 맞게 컨트롤들의 위치와 크기를 변경해주는 함수입니다.

자 이제 하나씩 살펴봅시다.

- void InsertItemDlglist(HWND *DesktopHWND1, TCHAR **DesktopWND_title1, int count);

코드를 한 줄씩 살펴봅시다.

- int i;

for문을 사용하기 위해 선언하였습니다.

- HICON a;

핸들에서 추출한 아이콘을 저장할 변수 a를 선언하였습니다.

- LVITEM DlgList = {0};

리스트뷰에 항목을 추가할 때 필요한 변수인 LVITEM형 DlgList변수를 선언하고 초기화하였습니다. LVITEM구조체를 살펴봅시다.

여기서 쓰인 멤버들만 살펴봅시다.

* UINT mask

어떠한 멤버를 유효멤버로 정할지를 값으로 받는 멤버입니다. 이 값에 따라 유효멤버가 바뀌며 특정 멤버는 유효멤버가 아니면 어떤 값이 들어가든 무효가 되버립니다.

* int iImage

이미지리스트의 인덱스를 값으로 받습니다. 이 값에 따라 리스트 뷰의 항목에 추가되는 아이콘이 달라집니다.

* int iItem

리스트 뷰의 항목의 인덱스를 값으로 받습니다.

* int iSubItem

리스트 뷰의 하위항목의 인덱스를 값으로 받습니다. 리스트 뷰에서 하위항목이란 열을 의미합니다. 즉 열이 (작업, 상태) 이렇게 되어있으며 하위항목의 값이 각각 0,1로 설정됩니다.

* LPTSTR pszText

항목의 문자열을 받는 멤버입니다.

정리하면 이 구조체는 리스트 뷰에 항목을 추가하기 위해 사용하는 구조체입니다.

- SendDlgItemMessage(Global_TabDlgHWND,Tab1_DLG_List,LVM_DELETEALLITEMS,0,0);

Tab1_DIALOG 대화상자의 핸들이 저장된 지역변수 Global_TabDlgHWND에 속한 Tab1_DLG_List(리스트 뷰)에 LVM_DELETEALLITEMS메세지를 보내 리스트 뷰의 항목을 전부 삭제합니다.

- ImageList_Remove(Global_ImageList,-1);

이미지리스트인 Global_ImageList에 속한 이미지를 전부 삭제합니다. 

- for(i=0;i<count;i++)

핸들 개수만큼 아래의 코드를 반복합니다.

a = (HICON)SendMessage(DesktopHWND1[i],WM_GETICON,ICON_SMALL,0);

데스크탑의 핸들에 WM_GETICON메세지를 보냅니다. 인자가 ICON_SMALL이므로 작은 아이콘을 가져오게 됩니다. 반환된 작은 아이콘은 16*16크기이며 이를 a에 저장시킵니다.

- if(a == NULL)

a = (HICON)GetClassLongPtr(DesktopHWND1[i],GCLP_HICONSM);

만약 위의 SendMessage함수로 아이콘을 가져오지 못하였다면 GetClassLongPtr함수를 사용하여 아이콘을 가져옵니다. 

GetClassLongPtr함수는 지정된 핸들의 WNDCLASSEX 구조체에서 값을 가져오는 작업을 해주는 함수로 옵션을 GCLP_HICONSM로 주면 16*16크기의 아이콘을 가져옵니다. 아이콘을 가져오면 핸들을 a에 저장합니다.

- if(a == NULL)

a = LoadIcon(Global_hInstance,MAKEINTRESOURCE(IDI_ICON2));

GetClassLongPtr함수로도 아이콘을 가져오지 못한다면 리소스에서 대체아이콘을 가져와 a에 저장합니다.

- ImageList_AddIcon(Global_ImageList,a);

가져온 아이콘을 ImageList_AddIcon함수를 사용하여 Global_ImageList에 추가시킵니다.

- SendDlgItemMessage(Global_TabDlgHWND,Tab1_DLG_List,LVM_SETIMAGELIST,(WPARAM)LVSIL_SMALL,(LPARAM)Global_ImageList);

이미지가 저장된 Global_ImageList를 LVM_SETIMAGELIST메세지를 이용하여 Tab1_DLG_List 리스트 뷰에 등록시킵니다. 네번째 인자인 LVSIL_SMALL는 작은 아이콘 이미지 리스트를 의미합니다.

- Global_DesktopWND_title2[i] = (TCHAR *)malloc(sizeof(TCHAR)*(lstrlen(DesktopWND_title1[i])+1));

전역변수인 Global_DesktopWND_title2[i]에 핸들 타이틀명이 저장된 DesktopWND_title1[i] 크기만큼 동적할당합니다.

- memset(Global_DesktopWND_title2[i],0,sizeof(TCHAR)*(lstrlen(DesktopWND_title1[i])+1));

  lstrcpy(Global_DesktopWND_title2[i],DesktopWND_title1[i]);

동적할당된 배열을 초기화시켜주고 DesktopWND_title1[i]의 내용을 Global_DesktopWND_title2[i]에 복사시킵니다.

이러한 작업을 해주는 이유는 나중에 윈도우 타이틀의 문자열이 변경되었을 때 변경된 문자열과 변경 전 문자열을 비교해주기 위함입니다.

- DlgList.mask = LVIF_TEXT | LVIF_IMAGE;

LVITEM구조체인 DlgList의 mask멤버에 LVIF_TEXT | LVIF_IMAGE 값을 넣습니다. LVIF_TEXT는 pszText멤버를 유효화시키며 LVIF_IMAGE는 iImage멤버를 유효화시킵니다.

- DlgList.iImage = i;

가져올 이미지의 인덱스를 i로 지정합니다. 이렇게 하면 for문이 진행될때마다 이미지리스트에서 차례대로 아이콘을 가져옵니다.

- DlgList.pszText = DesktopWND_title1[i];

DesktopWND_title1[i]에 저장된 문자열을 pszText멤버에 대입합니다.

- DlgList.iItem = i;

항목의 인덱스를 i로 지정합니다. 이렇게 하면 for문이 진행될때마다 0~핸들개수 만큼차례대로 삽입하게 됩니다.

- DlgList.iSubItem = 0;

iSubItem값을 0으로 줌으로써 첫번째 하위항목(작업)에 삽입할 것을 명시합니다.

- SendDlgItemMessage(Global_TabDlgHWND,Tab1_DLG_List,LVM_INSERTITEM,0,(LPARAM)&DlgList);

Tab1_DLG_List 리스트 뷰에 LVM_INSERTITEM메세지를 보내 DlgList구조체에 담긴 내용을 토대로 항목을 추가합니다.

- DlgList.iImage = -1;

항목 삽입이 완료되었으면 iImage값에 -1을 주어 다음 항목을 삽입할 때 아이콘을 추가하지 않도록 합니다.

- DlgList.pszText = L"실행 중";

문자열을 바꿉니다.

  DlgList.iSubItem = 1;

iSubItem값을 1로 줌으로써 두번째 하위항목(상태)에 삽입할 것을 명시합니다.

- SendDlgItemMessage(Global_TabDlgHWND,Tab1_DLG_List,LVM_SETITEM,0,(LPARAM)&DlgList);

Tab1_DLG_List 리스트 뷰에 LVM_INSERTITEM메세지를 보내 DlgList구조체에 담긴 내용을 토대로 항목을 추가합니다.

- Global_Dlglist_count = i;

for문의 처리가 다 완료되었으면 i의 값을 Global_Dlglist_count에 저장시킵니다. 그러면이 Global_Dlglist_count는 리스트뷰에 추가한 항목의 수를 의미하게 됩니다.

다음 함수를 살펴봅시다.

- int checkDesktopWND_title(TCHAR *DesktopWND_title1);

- if(!lstrcmp(DesktopWND_title1,L"Program Manager"))

return 1;

인자로 받은 DesktopWND_title1이 Program Manager 인 경우 1을 반환합니다. 1을 반환한다는 것은 리스트 뷰에서 제외될 핸들이라는 뜻입니다.

- if(!lstrcmp(DesktopWND_title1,L"시작 메뉴"))

return 1;

인자로 받은 DesktopWND_title1이 시작 메뉴 인 경우 1을 반환합니다. 우리가 윈도우즈에서 시작 버튼을 눌렀을 때 보여지는 시작 메뉴도 하나의 핸들로 인식하므로 리스트 뷰에서 제외하기 위해 작성하였습니다.

- return 0;

핸들의 타이틀이 위에 해당되지 않는다면 0을 반환합니다.

- int CMP_DesktopWND_title(void);

- for(i=0;i<Global_hwnd_count;i++)  

데스크탑 핸들의 개수만큼 아래의 코드를 반복합니다.

- if(lstrcmp(Global_DesktopWND_title[i],Global_DesktopWND_title2[i])) 

free_DesktopWND_title2();

return 1;

리스트뷰에 추가될 때 저장된 핸들의 타이틀과 새 데스크탑 핸들의 타이틀을 검사합니다. 만약 두 타이틀의 내용이 다르다면 리스트뷰의 항목을 수정해야하므로 free_DesktopWND_title2함수를 호출하여 리스트뷰에 추가될 때 저장된 핸들을 해제해준 다음 1을 리턴합니다. 이 함수에서 1을 리턴하게 되면 InsertItemDlglist함수를 호출합니다.

- return 0;

타이틀의 비교과정에서 바뀐것이 없다면 0을 반환합니다.

- void free_DesktopWND_title(void)

- for(i=0;i<Global_hwnd_count;i++)        

free(Global_DesktopWND_title[i]);

 핸들의 타이틀이 저장된 Global_DesktopWND_title배열을 해제해줍니다.

- void free_DesktopWND_title2(void)

- for(i=0;i<Global_Dlglist_count;i++)        

free(Global_DesktopWND_title2[i]);

리스트뷰에서 항목을 추가할 때 저장시킨 핸들의 타이틀 배열을 해제합니다.

- void LVHeaderSort(HWND hWnd,TCHAR *DlgListHeader_Str[],int columnindex)

- HWND LVHeader;

리스트뷰의 헤더 핸들을 저장할 변수 LVHeader를 선언합니다.

- HDITEM HeaderItem;

HDITEM 구조체 변수 HeaderItem를 선언합니다. HDITEM을 살펴봅시다.

맥락은 LVITEM 구조체랑 비슷합니다. 쓰인 멤버들을 살펴봅시다.

* UINT mask

어떠한 멤버를 유효멤버로 정할지를 값으로 받는 멤버입니다. 이 값에 따라 유효멤버가 바뀌며 특정 멤버는 유효멤버가 아니면 어떤 값이 들어가든 무효가 되버립니다.

* int fmt

리스트뷰 헤더의 형식을 값으로 받는 멤버입니다.

* LPTSTR pszText

리스트뷰 헤더의 문자열을 값으로 받는 멤버입니다.

정리하면 이 구조체는 리스트 뷰 헤더를 조작할 때 사용합니다.

- LVHeader =(HWND)SendDlgItemMessage(hWnd,Tab1_DLG_List,LVM_GETHEADER,0,0);

Tab1_DLG_List 리스트뷰에 LVM_GETHEADER메세지를 보내 리스트뷰 헤더의 핸들을 얻어와 LVHeader에 저장시킵니다.

- SendMessage(LVHeader,HDM_GETITEM,columnindex,(LPARAM)&HeaderItem);

인자로 받은 값인 columnindex에 해당하는 헤더의 정보를 HDM_GETITEM메세지를 이용하여 얻어옵니다. 이렇게 얻어온 헤더의 정보는 HeaderItem구조체에 저장됩니다. 여기서 인자로 받은 columnindex는 사용자가 클릭한 헤더의 인덱스를 의미합니다. 

if(HeaderItem.fmt == 17408)

fmt의 값이 17408인 경우 아래의 코드를 수행합니다. 17408이란 값은 헤더의 상태가 오름차순을 가리킨다는 뜻입니다.

- HeaderItem.mask = HDI_TEXT | HDI_FORMAT;

mask멤버에 HDI_TEXT | HDI_FORMAT 값을 넣습니다. HDI_TEXT는 pszText멤버를 유효화시키며 HDI_FORMAT는 fmt멤버를 유효화시킵니다.

- HeaderItem.fmt = HDF_SORTDOWN | HDF_STRING;

fmt멤버에 HDF_SORTDOWN | HDF_STRING 값을 넣습니다. HDF_SORTDOWN는 헤더에 역삼각형 표시를 그리라는 의미(내림차순)이며 HDF_STRING은 항목에 문자열이 표시된다는 의미입니다.

- HeaderItem.pszText = DlgListHeader_Str[columnindex];

pszText멤버에 인자로 받은 DlgListHeader_Str배열의 columnindex번째 문자열을 저장시킵니다. DlgListHeader_Str배열은 헤더의 문자열이 저장되어 있는 배열을 의미하며 0번째에는 작업, 1번째에는 상태가 저장되어있습니다.

- else if(HeaderItem.fmt == 16896)

fmt가 16896일 경우 아래의 코드를 수행합니다. 16896이란 값은 헤더의 상태가 내림차순을 가리킨다는 뜻입니다.

- HeaderItem.mask = HDI_TEXT | HDI_FORMAT;

  HeaderItem.fmt = HDF_SORTUP | HDF_STRING;

  HeaderItem.pszText = DlgListHeader_Str[columnindex];

fmt속성 중 HDF_SORTDOWN가 HDF_SORTUP으로 바뀐 것 외에는 위와 동일합니다.

HDF_SORTUP은 삼각형 표시를 그리라는 의미(오름차순)입니다.

- else

fmt가 17408도 아니고 16896도 아니면 아래의 코드를 수행합니다. 이 말은 헤더가 오름차순이나 내림차순을 가리키지 않는다는 것을 의미합니다.

- HeaderItem.mask = HDI_TEXT | HDI_FORMAT;

  HeaderItem.fmt = 16384;

HeaderItem.fmt의 값에 16384로 지정합니다. 16384라는 값은 헤더가 오름차순이나 내림차순을 가리키지 않는다는 것을 의미합니다.(삼각형이 안그려진 헤더)

- if(columnindex == 0)

HeaderItem.pszText = DlgListHeader_Str[1];

SendMessage(LVHeader,HDM_SETITEM,1,(LPARAM)&HeaderItem);

columnindex 가 0인 경우 즉 0번째 헤더(작업)를 클릭한 경우입니다. 삼각형이 그려져 있지 않은 헤더를 눌렀을 경우 pszText멤버에  상태 헤더의 문자열을 저장합니다. 그리고 SendMessage함수로 1번째 헤더(상태)에 HDM_SETITEM메세지를 보내 헤더의 형식을 수정합니다.

- else

HeaderItem.pszText = DlgListHeader_Str[0];

     SendMessage(LVHeader,HDM_SETITEM,0,(LPARAM)&HeaderItem);

columnindex가 1인 경우 pszText에 작업 헤더의 문자열을 저장한 후 SendMessage함수로 0번째 헤더(작업)에 HDM_SETITEM메세지를 보내 헤더의 형식을 수정합니다.

이렇게 하면 삼각형이 그려져 있지 않은 헤더를 눌렀을 경우 누르지 않은 헤더에 있던 삼각형의 이미지가 사라집니다.

- HeaderItem.fmt = HDF_SORTUP | HDF_STRING;

  HeaderItem.pszText = DlgListHeader_Str[columnindex];

fmt에 오름차순 삼각형을 그리라는 HDF_SORTUP값을 넣고 누른 헤더의 문자열을 가져와 pszText에 저장시킵니다.

- SendMessage(LVHeader,HDM_SETITEM,columnindex,(LPARAM)&HeaderItem);

모든 if,else구문에 의해 HeaderItem의 멤버가 정리되었다면 SendMessage함수를 사용하여 columnindex헤더를 수정합니다.

- void asce_sort(void)

- int i,j;

for문에 사용할 변수 i,j를 선언합니다.

- TCHAR temp[256] = L"";

정렬을 위해 문자열을 임시로 저장할 변수 temp를 선언과 동시에 초기화합니다. 

- HWND temp2;

정렬을 위해 핸들을 임시로 저장할 변수 temp2를 선언합니다.

- for(i=0;i<Global_hwnd_count-1;i++)

서로 문자열을 비교하기 위해 for문을 돌립니다. 0부터 시작하되 배열의 인덱스개수보다 하나 낮게 최대값을 잡습니다.

- for(j=i+1;j<Global_hwnd_count;j++)

두번째 for문을 돌립니다. j는 i보다 하나 큰 값으로 시작하되 배열의 인덱스 개수를 최대값으로 잡습니다.

for문을 이렇게 선언한 이유는 배열[0] 배열[1] -> 배열[0] 배열[2] -> 배열[0] 배열[3] 이런 식으로 검사를 하기 위해서입니다.

- if((lstrcmp(Global_DesktopWND_title[i],Global_DesktopWND_title[j])) > 0)

Global_DesktopWND_title의 i번째 문자열과 j번째 문자열을 lstrcmp함수로 비교합니다. 이때 lstrcmp함수의 반환값이 양수일 경우 아래의 코드를 실행합니다. 반환값이 양수라는 것은 i번째 문자열이 j번째 문자열보다 값이 크다는 것을 의미합니다. 

예를 들어 i번째 문자열이 "나"이고 j번째 문자열이 "가"이면 lstrcmp함수는 양수를 반환한다는 뜻입니다.

- lstrcpy(temp,Global_DesktopWND_title[i]);

  free(Global_DesktopWND_title[i]);

i번째에 담긴 문자열을 temp에 옮기고 동적할당된 i번째 배열을 해제합니다.

- Global_DesktopWND_title[i] = (TCHAR *)malloc(sizeof(TCHAR)*(lstrlen(Global_DesktopWND_title[j])+1));

해제된 i번째 배열을 j번째 문자열 크기에 맞게 동적할당시킵니다.

- lstrcpy(Global_DesktopWND_title[i],Global_DesktopWND_title[j]);

j번째 문자열을 동적할당된 i번째로 옮깁니다.

- free(Global_DesktopWND_title[j]);

  Global_DesktopWND_title[j] = (TCHAR *)malloc(sizeof(TCHAR)*(lstrlen(temp)+1));

j번째 배열을 해제한 다음 i번째 문자열이 들어있는 temp 크기에 맞게 동적할당합니다.

- lstrcpy(Global_DesktopWND_title[j],temp);

j번째 배열에 i번째 문자열을 넣습니다.

이렇게 하면 i의 문자열과 j의 문자열 위치가 서로 바뀌게 됩니다. 예를 들어 [0]이 "나"이고 [1]이 "가" 였다면 위의 코드로 인해 [0]이 "가" 가 되고 [1]이 "나"가 된것이지요.

- temp2 = Global_DesktopHWND[i];

  Global_DesktopHWND[i] = Global_DesktopHWND[j];

  Global_DesktopHWND[j] = temp2;

문자열의 위치를 바꾸었으면 그에 맞는 핸들도 똑같이 위치를 바꿔줍니다.  

최종적으로 for문이 종료되면 문자열배열은 오름차순으로 정렬되어 집니다.

- void desc_sort(void)

내림차순이므로 lstrcmp함수가 음수를 반환할 때 코드를 수행합니다. 그 외에는 asce_sort함수와 동일합니다.

- void GetLVHeaderSort(void)

- HWND LVHeader;

  HDITEM HeaderItem0,HeaderItem1;

헤더의 정보를 얻기 위해 헤더의 핸들을 받는 변수와 HDITEM 구조체 변수 2개를 선언합니다.

- LVHeader =(HWND)SendDlgItemMessage(Global_TabDlgHWND,Tab1_DLG_List,LVM_GETHEADER,0,0);

Tab1_DLG_List 리스트뷰에 LVM_GETHEADER메세지를 보내 헤더의 핸들을 얻어와 변수에 저장시킵니다.

- SendMessage(LVHeader,HDM_GETITEM,0,(LPARAM)&HeaderItem0);

  SendMessage(LVHeader,HDM_GETITEM,1,(LPARAM)&HeaderItem1);

받아온 핸들을 이용해 0번째 헤더(작업)와 1번째 헤더(상태)에 HDM_GETITEM메세지를 보내 헤더의 상태를 가져옵니다.

- if(HeaderItem0.fmt == 17408 || HeaderItem1.fmt == 17408)

  asce_sort();

  else

desc_sort();

작업 헤더나 상태 헤더에 오름차순을 뜻하는 삼각형이 그려저 있을 경우 asce_sort() 함수를 호출하여 문자열과 핸들을 오름차순으로 정렬시킵니다.

그 외에는 작업 헤더나 상태 헤더에 내림차순을 뜻하는 역삼각형이 그려져 있다는 뜻이므로 desc_sort() 함수를 호출하여 문자열과 핸들을 내림차순으로 정렬시킵니다.

- void MoveWND(HWND hWnd)

- int i;

현재 포커스를 가지고 있는 탭 컨트롤의 탭 인덱스를 가져오기 위한 변수 i를 선언하였습니다.

- RECT WNDRT;

핸들의 영역을 받아오기 위해 RECT형 변수를 선언하였습니다.

- GetClientRect(hWnd,&WNDRT);

인자로 받은 hWnd의 영역을 구해와 변수에 저장시킵니다. 여기서 hWnd는 사용자가 크기조정이 가능한 메인 대화상자의 핸들입니다.

-    MoveWindow(GetDlgItem(hWnd,Tab1),WNDRT.left,WNDRT.top,WNDRT.right,WNDRT.bottom-30,TRUE);

Tab컨트롤의 핸들을 가져와 메인 대화상자에 크기에 맞게 위치와 크기를 재조정합니다.     

-    MoveWindow(Global_TabDlgHWND,WNDRT.left,WNDRT.top+30,WNDRT.right,WNDRT.bottom-70,TRUE);

리스트 뷰가 들어있는 대화상자를 가져와 메인 대화상자에 크기에 맞게 위치와 크기를 재조정합니다. 

-    MoveWindow(GetDlgItem(Global_TabDlgHWND,Tab1_DLG_List),WNDRT.left+20,WNDRT.top+10,WNDRT.right-35,WNDRT.bottom-115,TRUE);

리스트뷰의 핸들을 가져와 메인 대화상자에 크기에 맞게 위치와 크기를 재조정합니다. 

- MoveWindow(GetDlgItem(Global_TabDlgHWND,TaskExit),WNDRT.right-338,WNDRT.bottom-95,102,24,TRUE);

  MoveWindow(GetDlgItem(Global_TabDlgHWND,change),WNDRT.right-230,WNDRT.bottom-95,102,24,TRUE);

  MoveWindow(GetDlgItem(Global_TabDlgHWND,NewTask),WNDRT.right-122,WNDRT.bottom-95,102,24,TRUE);

대화상자의 작업 끝내기, 전환, 새작업 버튼을 대화상자에 크기에 맞게 위치를 재조정합니다. 오리지널 작업관리자에서 이 세개의 버튼은 대화상자의 크기가 바껴도 위치만 바뀔뿐 크기가 바뀌진 않으므로 MoveWindow의 right와 bottom의 인자를 고정값으로 주었습니다.

- MoveWindow(GetDlgItem(hWnd,static1),WNDRT.left+5,WNDRT.bottom-16,70,12,TRUE);

  MoveWindow(GetDlgItem(hWnd,static2),WNDRT.left+100,WNDRT.bottom-16,70,12,TRUE);

  MoveWindow(GetDlgItem(hWnd,static3),WNDRT.left+220,WNDRT.bottom-16,70,12,TRUE);

메인 대화상자의 스태틱들을 대화상자에 크기에 맞게 위치를 재조정합니다. 이 스태틱들은 크기가 고정되어 있으며 메인 대화상자의 bottom값에 따라 y위치가 바뀌므로 인자를 저렇게 주었습니다.

- i = SendDlgItemMessage(hWnd,Tab1,TCM_GETCURFOCUS,0,0);

모든 윈도우의 위치변경이 끝났으면 Tab컨트롤에 TCM_GETCURFOCUS메세지를 보내 현재 선택된 탭 인덱스를 가져와 i에 저장합니다.

- switch(i)

case 0:

ShowWindow(Global_TabDlgHWND,SW_HIDE);

ShowWindow(Global_TabDlgHWND,SW_SHOW);

break;

default:

break;

이 인덱스의 값이 0(응용프로그램)이면 ShowWindow의 SW_HIDE로 윈도우를 한번 숨긴다음 ShowWindow의 SW_SHOW로 윈도우를 다시 보여줍니다. 그냥 SW_SHOW옵션만 쓰면 크기가 변경되었을 때 컨트롤들이 보이지 않게 됩니다. 이 코드 덕분에 크기를 변경할 때 살짝 매끄럽지 못할 수 있습니다.

그 외의 탭이 선택되었다면 변경된 컨트롤들을 보여주지 않습니다.

자 이것으로 함수설명을 마치겠습니다. 다음 포스팅에선 작업관리자에 쓰인 코드를 보여드리겠습니다.



Posted by englishmath
,

안녕하십니까 이번 포스팅에서는 작업관리자의 리소소를 보여드리겠습니다. 액셀러레이터는 틀만 만들고 구현을 하지 않았기 때문에 생략하였습니다.

먼저 대화상자를 보겠습니다.

작업관리자의 메인 대화상자가 되는 부분입니다. 대화상자 안에는 탭 컨트롤을 추가하였고 밑의 글자들은 스태틱으로 작성하였습니다.

메인 대화상자의 첫번째 탭에서 동작할 대화상자입니다. 대화상자 안에는 리스트 뷰와 버튼을 추가하였습니다. 그리고 대화상자의 visible속성을 FALSE로 주어 리스트뷰와 버튼만 보이도록 하였습니다. 마지막으로 이 대화상자를 자식 윈도우로 지정하여 메인 대화상자가 종료될 때 같이 종료되도록 하였습니다.

이제 아이콘을 살펴봅시다.

작업관리자의 메인 아이콘입니다. 이 아이콘은 오리지널 작업관리자에서 추출하였습니다.

작업관리자의 리스트뷰에 추가될 아이콘입니다. 이 아이콘은 데스크탑 핸들에서 아이콘을 추출하지 못했을 경우에 쓰는 대체아이콘이라고 보시면 됩니다.

마지막으로 메뉴를 살펴봅시다.

이 메뉴는 응용프로그램 탭에서 동작하는 메뉴입니다. 다른 탭에서는 이 메뉴와 다른 메뉴가 나타납니다.

이것으로 리소스 포스팅이 끝났습니다. 다음 포스팅에서는 코드에 쓰인 함수들을 살펴보겠습니다.


Posted by englishmath
,

안녕하십니까? 이번 포스팅에서는 제가 구현한 작업관리자의 알고리즘을 설명드리겠습니다. 

물론 실력이 부족하여 전부 구현하지는 못하였고 최소한의 기능(응용프로그램)만 구현하였습니다. 그럼 한번 알고리즘을 살펴봅시다.

1. 작업관리자는 윈도우가 아닌 대화상자로 생성되고 대화상자에 메뉴, 탭 컨트롤 등을 추가한다.

2. 작업관리자 창의 응용프로그램 부분은 리스트 뷰로 구현되어 있다.

3. 리스트 뷰에는 데스크탑에서 얻어온 윈도우 핸들이 추가된다.

   이 때 가져오는 윈도우 핸들은 제목표시줄에 문자열이 존재해야 하고 자식윈도우가 아니어야 하며 보여지는 윈도우(WS_VISIBLE)이어야 한다.

4. 리스트 뷰의 헤더 버튼을 누르면 가져온 윈도우의 핸들들이 정렬된다.

5. 작업관리자는 항상 최상의 창 위치에 존재한다.

6. 작업끝내기 버튼을 누를시 해당되는 핸들에 WM_CLOSE 메세지를 보낸다.

7. 전환 버튼을 누를 시 작업관리자 창은 최소화가 되고 포커스를 해당되는 핸들로 전환한다.

8. 작업관리자는 자기 자신의 핸들을 리스트 뷰에 추가시키지 않는다.

등이 있겠네요. 물론 실제로는 더 많이 있겠지만 일단 제가 구현한 부분만 설명드렸습니다. 다음 포스팅에서는 리소스를 한 번 살펴봅시다.


Posted by englishmath
,