. 명령 항목 관리

앞에서 작성한 OnCommand 함수를 다시 한 번 보도록 하자. IDM_FILE_NEW를 선택하면 New 함수를 부르고 IDM_FILE_SAVE를 선택하면 Save 함수를 호출한다. 이 명령이 전달되기만 하면 무조건 함수를 부르고 있는 셈이다. 새 파일이나 열기는 항상 새로운 차일드를 만들기 때문에 작업 대상 윈도우가 필요없지만 저장할 때는 현재 활성화된 차일드를 대상으로 한다. 그래서 hActive에 활성 차일드의 핸들을 미리 구해놓았으며 Save SaveAs 함수를 호출할 때 이 핸들을 인수로 전달하였다.

만약 활성 차일드가 없는 상태라면 hActive NULL이 되며 이 경우 저장 명령은 실패할 뿐만 아니라 있지도 않는 hActive로부터 pSi를 구하려고 하기 때문에 결국 죽고 만다. pSi NULL이 되고 pSi->Ae는 무효이기 때문이다. 그래서 활성창이 필요한 명령은 다음과 같이 반드시 호출하기 전에 hActive가 있는지 점검해보는 것이 원칙이다.

 

     case IDM_FILE_SAVE:

          if (hActive) {

              Save(hActive);

          }

          break;

 

hActive NULL이 아닐 때만 Save 함수를 호출한다. 이렇게 하면 충분한 안전 장치를 마련한 셈인데 실제로는 hActive NULL이 될 때 저장 명령 자체가 없다. Dangeun은 두 개의 메뉴를 가지고 있으며 활성 차일드가 없을 때는 아예 저장이라는 명령 자체가 메뉴에 나타나지 않는다. 그럼에도 불구하고 IDM_FILE_SAVE에서 hActive를 점검해야 하는 이유는 이 명령을 액셀러레이터나 툴바로도 전달할 수 있기 때문이다. 메뉴는 실행중에 교체하지만 액셀러레이터는 교체되지 않는다.

저장뿐만 아니라 닫기, 읽기전용 속성 변경, 파일 되돌리기, 복사, 붙여넣기, 자동개행 변경, 찾기, 바꾸기 등등 앞으로 만들 대부분의 명령들도 마찬가지로 활성창이 없을 때는 실행할 수 없다. 그렇다면 활성창이 필요없는 일부 몇 개의 명령을 제외하고는 일일이 if (hActive)를 붙여주어야 하는가 하면 그럴 필요가 분명히 있다. 활성창이 없을 때 메뉴 명령을 제대로 막지 않으면 프로그램이 다운되는데 그대로 두고 볼 수는 없지 않은가? 하지만 Dangeun은 좀 다른 방법으로 활성창이 필요한 명령들을 막기로 했다.

 

BOOL TestNeedActive(WORD ID)

{

     static WORD IDs[]={ IDM_FILE_NEW,IDM_FILE_OPEN,IDM_FILE_EXIT,IDM_FILE_PROJECT,

          IDM_FILE_FTPOPEN, IDM_FILE_HTTPOPEN, IDM_VIEW_OUTPUT,

          IDM_VIEW_TOOLBAR,IDM_VIEW_STATUS,IDM_VIEW_FILE,IDM_VIEW_FILETAB,

          IDM_SEARCH_FILES,IDM_SEARCH_RFILES,IDM_TOOL_CONFIG,IDM_TOOL_UNINSTALL,

          IDM_HELP_ABOUT };

     int i;

 

     for (i=0;i<sizeof(IDs)/sizeof(IDs[0]);i++) {

          if (ID==IDs[i])

              return FALSE;

     }

     return TRUE;

}

 

이 함수는 명령 ID가 활성창을 필요로 하는지 아닌지를 조사한다. IDs 배열에 활성창이 필요없는 명령 항목을 미리 정의해두고 이 중 하나일 때만 FALSE를 리턴하며 그 외의 경우는 TRUE를 리턴한다. 활성창이 필요한 명령들이 대부분이라 반대로 필요없는 명령인지를 조사하는 것이 더 빠르다. OnCommand에서는 다음과 같이 이 함수를 호출하여 명령의 실행 여부를 결정한다.

 

void OnCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

     ....

     hActive=(HWND)SendMessage(g_hMDIClient,WM_MDIGETACTIVE,0,NULL);

    if (hActive==NULL) {

        if (TestNeedActive(LOWORD(wParam)))

           return;

    }

 

hActive NULL이면 이 명령이 활성창이 없어도 되는 명령인지 조사한 후 그렇지 않다면 그냥 리턴하도록 했다. 따라서 hActive가 반드시 필요한 명령은 hActive가 없을 때는 아예 실행을 하지 않는다. 원칙을 따지자면 모든 명령에 if (hActive)를 붙여주는 것이 더 좋은 방법이다. 그러나 여기서 이런 방법을 쓰는 이유는 결과적으로 이 방법이 더 간단해서이기도 하지만 보여주기 위한 예제이기 때문이다. 모든 명령에 일일이 if (hActive)를 붙이자면 소스가 길어질 뿐만 아니라 들여쓰기가 한 칸 더 되어야 하기 때문에 보기에도 좋지 않다. 지면에 실어야 할 소스는 90컬럼을 넘어서는 곤란하다는 말 못할 사정이 있기 때문이다.