notepad2 컴파일 삽질기 부록#1 : context-menu 추가


나름 열심히 뜯어고친 Notepad2를 잘 쓰고 있었는데, 구차니님께서 소스 일부를 수정하셨습니다.
context-menu(마우스 오른쪽 버튼 클릭시 뜨는 메뉴)에 Notepad2를 손쉽게 등록할 수 있도록 수정해주셨는데, 수정 방법을 간략하게만 포스팅하셨더군요.

이왕 연재한 것이라 이 내용까지 포스팅하겠습니다.
삽질기 1~4를 모두 적용했다고 가정하고 시작합니다.

수정 대상파일은 resource.h, Notepad2.rc, Notepad2.c의 3개이며, 모두 src 폴더에 저장되어 있습니다.


1. resource.h

다음 두 줄을 추가합니다.
#define IDM_REGISTRY_UNKNOWN            40226
#define IDM_REGISTRY_ALL                40227


그리고, 아래 내용을 찾습니다.
#define _APS_NEXT_COMMAND_VALUE         40226
이 코드를 아래와 같이 수정합니다.
#define _APS_NEXT_COMMAND_VALUE         40228
resource.h 파일은 두 부분으로 나뉘는 모습인데, 앞의 두 줄은 앞부분에 삽입하면 됩니다.


2. Notepad2.rc

IDR_MAINWND MENU DISCARDABLE에서 아래 내용을 찾습니다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END
이 부분을 아래와 같이 수정합니다.
MENUITEM "Propert&ies...",              IDM_FILE_PROPERTIES
MENUITEM SEPARATOR
MENUITEM "Create &Desktop Link",        IDM_FILE_CREATELINK
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL
, CHECKED
MENUITEM "Add context-menu to unknown file type",
                                        IDM_REGISTRY_UNKNOWN
, CHECKED
MENUITEM SEPARATOR
POPUP "&Favorites"
BEGIN
    MENUITEM "&Open Favorites...\tAlt+I",   IDM_FILE_OPENFAV
    MENUITEM "&Add Current File...\tAlt+K", IDM_FILE_ADDTOFAV
    MENUITEM "&Manage...\tF9",              IDM_FILE_MANAGEFAV
END

구분자 하나와 context-menu에 관련된 두 줄을 추가하는 내용입니다.


3. Notepad2.c

파일 앞부분의 변수 선언부에 다음 내용을 추가합니다.
BOOL      bRegistryUnknownType;
BOOL      bRegistryAllType;


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾습니다.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));
이 부분을 아래와 같이 수정합니다. 2줄을 추가하는 것입니다.
EnableCmd(hmenu,IDM_EDIT_SELTONEXT,i);
EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);

CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType);

CheckCmd(hmenu,IDM_VIEW_USE2NDDEFAULT,Style_GetUse2ndDefault(hwndEdit));


다음은 LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정입니다.
이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 case 중에 IDM_REGISTRY_ALL, IDM_REGISTRY_UNKNOWN 둘을 추가합니다.
case IDM_REGISTRY_ALL:
    // Register registry - type unknown
      if (bRegistryAllType)
      {
         //WinNT requires the key to have no subkeys
          RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2\\command");
          RegDeleteKey(HKEY_CLASSES_ROOT, L"*\\shell\\Open with notepad2");
      }
      else
      {
          HKEY key1;
          LONG res = RegCreateKey(HKEY_CLASSES_ROOT,
              L"*\\shell\\Open with notepad2\\command",
              &key1);
          if (res == ERROR_SUCCESS)
          {
              WCHAR cmd[MAX_PATH + 4];
            WCHAR path[MAX_PATH];
            int len;
            GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
              len = wsprintf(cmd, L"%s %%1", path);
              RegSetValue(key1, NULL, REG_SZ, cmd, len);
          }
      }       
    bRegistryAllType = (bRegistryAllType) ? FALSE : TRUE;
    break;

case IDM_REGISTRY_UNKNOWN:
    // Register registry - type all
    if (bRegistryUnknownType)
      {
         //WinNT requires the key to have no subkeys
          RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2\\command");
          RegDeleteKey(HKEY_CLASSES_ROOT, L"Unknown\\shell\\Open with notepad2");
      }
      else
      {
          HKEY key1;
          LONG res = RegCreateKey(HKEY_CLASSES_ROOT,
              L"Unknown\\shell\\Open with notepad2\\command",
              &key1);
          if (res == ERROR_SUCCESS)
          {
              WCHAR cmd[MAX_PATH + 4];
            WCHAR path[MAX_PATH];
            int len;
            GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
              len = wsprintf(cmd, L"%s %%1", path);
              RegSetValue(key1, NULL, REG_SZ, cmd, len);
          }
      }
    bRegistryUnknownType = (bRegistryUnknownType) ? FALSE : TRUE;
    break;


다음은 LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정입니다.
이 함수는 하나의 switch-case 문으로 되어있고, 각 case 내에 switch-case 문이 또 들어있는 구조입니다.
외부의 switch문인 switch(pnmh->idFrom)의 case 중에 IDM_REGISTRY_UNKNOWN, IDM_REGISTRY_ALL를 추가합니다.
case IDM_REGISTRY_UNKNOWN:
    // Register registry - type unknown
    break;

case IDM_REGISTRY_ALL:
    // Register registry - type all
    break;


다음은 void LoadSettings()의 수정입니다.
아래 내용을 찾습니다.
iPathNameFormat = IniSectionGetInt(pIniSection,L"PathNameFormat",0);
찾은 줄의 앞에 다음의 내용을 추가합니다. (앞의 내용을 삭제하면 안됩니다)
bRegistryUnknownType = IniSectionGetInt(pIniSection,L"RegistryUnknownType",0);
if (bRegistryUnknownType) bRegistryUnknownType = 1;

bRegistryAllType = IniSectionGetInt(pIniSection,L"RegistryAllType",0);
if (bRegistryAllType) bRegistryAllType = 1;


마지막으로 void SaveSettings(BOOL bSaveSettingsNow)를 수정합니다.
아래 내용을 찾습니다.
IniSectionSetInt(pIniSection,L"PathNameFormat",iPathNameFormat);
찾은 줄의 앞에 다음 2줄을 추가합니다. (이번에도 추가입니다)
IniSectionSetInt(pIniSection,L"RegistryUnknownType",bRegistryUnknownType);
IniSectionSetInt(pIniSection,L"RegistryAllType",bRegistryAllType);

수정을 완료하면 아래와 같은 모양을 볼 수 있습니다.

사용자 삽입 이미지

짜잔~~~~~~~~~