2008년 12월 29일 월요일

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);

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

사용자 삽입 이미지

짜잔~~~~~~~~~



댓글 10개:

  1. @구차니 - 2008/12/31 00:44
    1. 이 부분은 ini에서 읽기 보다는 레지스트리에서 직접 읽는 것이 어떨까 합니다.



    2. 한글화는 원래 저도 okto님께 떠밀었습니다. ^^;;;

    컴파일 완료된 버전을 okto님께 보내드리겠습니다.

    답을 주시겠죠. ^^;;;

    답글삭제
  2. trackback from: 메모장2 (3.0.20.11)
    누군가 메모장2에 한글IME 패치를 해주었으면 하는 소박한 바램이 있었다.다행히 BLUEnLIVE님과 Codewiz님께서 관심을 보여주셨고 (정확히 말하면, 옥토씨가 관심을 강요했다;; )공식 배포본을 Codewiz님이, 수정본을 BLUEnLIVE님이 각각 패치해 주셨다.그동안 여러차례의 수정을 거치며 다듬어지다가 드디어 어제 밤, 진정한 완전체라고 할 수 있는 버전이 태어났다.이제 죽을때까지 이것만 쓸테다. 프로그램에 대한 간단한 소개는 여기...

    답글삭제
  3. 오오... 드뎌 컨텍스트메뉴까지 아우르시는 건가요?

    역시 대단하십니다요 두분...

    한글화는 번개같이 해놓도록 하지요8D

    답글삭제
  4. 여러분들의 노고에 박수를 보냅니다.

    :P:P:P

    답글삭제
  5. @이정일 - 2008/12/29 11:35
    전 그저 밥숟갈을... (응?)

    답글삭제
  6. trackback from: 메모장2 + Context menu
    어느날 구차니님께서 말씀하셨다."메모장2는 다 좋은데 마우스메뉴 지원 안하는게 아쉽군요"필요는 발명의 어머니라고 했던가?결국 먼저 말을 꺼낸 구차니님께서 구차는 몸을 이끌고 컴파일을 위한 몸부림을 시작하셨다ㅎㅎNotepad2 컴파일을 위한 몸부림 -1/2/3/4/5여기에 BLUEnLIVE님께서 협력하시어,notepad2 컴파일 삽질기 부록 : context-menu 추가깔끔하게 문맥메뉴를 지원하는 한글판 메모장2로 재탄생~~ 짜잔~~◈ 수정버전(...

    답글삭제
  7. 결혼 기념일 축하드립니다~~~~

    답글삭제
  8. @okto - 2008/12/30 22:22
    고마울 뿐이라능~

    답글삭제
  9. 우와 초스피드 포스팅이시네요 ^^;

    MsgNotify() 부분에 대해서는 굳이 안 넣어도 되는지 몰라서 그냥 그 부분만 만들어 놓고 확인을 안해 봤습니다. 아무래도 MsgNotify() 쪽에서는 아무런 코드가 없기 때문에 굳이 넣지 않아도 될꺼라고 생각이 됩니다.



    그리고 ini파일이 저장되는 시점이 종료시에 저장이 되기 때문에, 메모장2를 하나 실행하고 레지스트리 관련 설정을 바꾸고 나서 다른 메모장2를 실행하면 설정사항이 저장이 되지 않는 문제점이 발견되었습니다. 이 부분에 대해서는 조금 고려를 해봐야 할 것 같더라구요.



    제가 컴파일 하면 용량이 매우 크고 한글화가 안되어 있어서 BLUEnLIVE님께 떠밀은건데 실패인가요 ㅋㅋ(okto님을 소환해서 더블 어택을 해야겠습니다 ㅋㅋ)



    덧 : 테스트 해보니 MsgNotify()에는 전혀 루틴을 타지 않습니다. 그 부분은 삭제 하셔도 무방합니다.

    답글삭제
  10. trackback from: 한글판 NotePad2 + Context menu
    Notepad2 for kor(context menu), 한글판 노트패드2

    ...

    답글삭제