레이블이 scintilla인 게시물을 표시합니다. 모든 게시물 표시
레이블이 scintilla인 게시물을 표시합니다. 모든 게시물 표시

2010년 6월 26일 토요일

notepad2 컴파일 삽질기 부록#6.1 : 메모장 대신 사용(수정)



okto님 배포본 notepad2는 설치 및 윈도우 메모장 대체를 위해 notepad.inf 파일을 이용했다.
이 방식은 설치가 쉽다는 장점은 있지만, 설치 제거에 손이 많이 간다는 단점이 있다.

장점을 살리고 단점을 제거하기 위해 구차니님께서 메모장을 대체하는 기능을 구현해주셨다.

그런데, 이를 위해 제작/공개한 notepad2 컴파일 삽질기 부록#6 : 메모장 대신 사용에는 사소한 버그가 하나 있었다.
바로 파일명을 notepad.exe로 바꾼 상태에선 동작하지 않는 다는 것이다.

이 부분은 사실 당연한 것이다.
이 기능은 레지스트리의 Image File Execution Options 키를 이용해서 notepad.exe라는 프로그램을 실행하면 다른 프로그램(notepad2.exe)을 실행하도록 지정하는 것인데, 그 프로그램이 또 notepad.exe라서 발생하는 문제이다.

이 기능을 사용하려면 소스 코드를 아래와 같이 수정하면 된다.

반드시 삽질기 부록#5.1 : context-menu 통합 및 수정을 적용한 후에 이 수정을 해야 함

수정 대상 파일은 역시 resource.h, Notepad2.rc, Notepad2.c 세 개이다.


1. resource.h

다음 줄을 추가한다.
#define IDM_REPLACE_NOTEPAD             40692



2. Notepad2.rc

아래 내용을 찾는다.
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL
, CHECKED
바로 앞에 다음 줄을 추가한다.
MENUITEM "Replace Notepad",             IDM_REPLACE_NOTEPAD



3. Notepad2.c

앞부분에 다음 변수를 하나 선언한다.
BOOL      bReplaceNotepad;


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
또는
CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType || bRegistryUnknownType);
바로 앞에 다음 줄을 추가한다.
CheckCmd(hmenu,IDM_REPLACE_NOTEPAD,bReplaceNotepad);


다음, LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에 다음 case 문을 추가한다.
이 함수 전체가 하나의 switch-case 문으로 되어있는데, case를 하나 추가하는 것이다.
case IDM_REPLACE_NOTEPAD:
if (bReplaceNotepad)
{
//WinNT requires the key to have no subkeys
RegDeleteKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe");
bReplaceNotepad = FALSE;
}
else
{
WCHAR path[MAX_PATH], *wTemp;
GetModuleFileName(GetModuleHandle(NULL), path, MAX_PATH);
bReplaceNotepad = TRUE;

wTemp = path;
while (*wTemp) wTemp++;
if (_wcsicmp(wTemp-12, L"\\notepad.exe"))
{
HKEY key1;
LONG res = RegCreateKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key1);
if (res == ERROR_SUCCESS)
{
WCHAR cmd[MAX_PATH + 4];
int len = wsprintf(cmd, L"\"%s\" /z", path);
RegSetValueExW(key1, L"Debugger", 0, REG_SZ, (const unsigned char*)cmd, len * 2);
}
else
{
bReplaceNotepad = FALSE;
MessageBeep(MB_ICONEXCLAMATION);
}
RegCloseKey(key1);
}
else
{
bReplaceNotepad = FALSE;
MessageBeep(MB_ICONEXCLAMATION);
}
}
break;


마지막으로 void CheckRegistry() 함수의 마지막 부분에 다음 내용을 추가하면 된다.
res = RegOpenKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key);
if(res == ERROR_SUCCESS)
        bReplaceNotepad = TRUE;
else    bReplaceNotepad = FALSE;
RegCloseKey(key);


수정된 결과는 아래와 같다. 짜잔~

사용자 삽입 이미지

수정에 수고해주신 구차니님께 다시 한 번 감사드립니다.

2009년 6월 24일 수요일

notepad2 컴파일 삽질기 부록#6 : 메모장 대신 사용 (재포스팅)

notepad2 컴파일 삽질기 부록#3 : 메모장 대신 사용을 3.1.21 정식버전에 맞게 약간 수정해서 다시 올림


okto님 배포본 notepad2는 설치 및 윈도우 메모장 대체를 위해 notepad.inf 파일을 이용했다.
이 방식은 설치가 쉽다는 장점은 있지만, 설치 제거에 손이 많이 간다는 단점이 있다.

장점을 살리고 단점을 제거하기 위해 구차니님께서 메모장을 대체하는 기능을 구현해주셨다.
이 기능을 사용하려면 소스 코드를 아래와 같이 수정하면 된다.

반드시 삽질기 부록#5 : context-menu 통합 및 수정을 적용한 후에 이 수정을 해야 함

수정 대상 파일은 역시 resource.h, Notepad2.rc, Notepad2.c 세 개이다.


1. resource.h

다음 줄을 추가한다.
#define IDM_REPLACE_NOTEPAD             40692



2. Notepad2.rc

아래 내용을 찾는다.
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL
, CHECKED
바로 앞에 다음 줄을 추가한다.
MENUITEM "Replace Notepad",             IDM_REPLACE_NOTEPAD



3. Notepad2.c

앞부분에 다음 변수를 하나 선언한다.
BOOL      bReplaceNotepad;


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾는다.
CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
또는
CheckCmd(hmenu,IDM_REGISTRY_ALL,bRegistryAllType || bRegistryUnknownType);
바로 앞에 다음 줄을 추가한다.
CheckCmd(hmenu,IDM_REPLACE_NOTEPAD,bReplaceNotepad);


다음, LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에 다음 case 문을 추가한다.
이 함수 전체가 하나의 switch-case 문으로 되어있는데, case를 하나 추가하는 것이다.
case IDM_REPLACE_NOTEPAD:
    if (bReplaceNotepad)
    {
       //WinNT requires the key to have no subkeys
        RegDeleteKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe");
    }
    else
    {
        HKEY key1;
        LONG res = RegCreateKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&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\" /z", path);
            RegSetValueExW(key1, L"Debugger", 0, REG_SZ, cmd, len * 2);
        }
        RegCloseKey(key1);
    }
    bReplaceNotepad = (bReplaceNotepad) ? FALSE : TRUE;
    break;


마지막으로 void CheckRegistry() 함수의 마지막 부분에 다음 내용을 추가하면 된다.
res = RegOpenKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key);
if(res == ERROR_SUCCESS)
        bReplaceNotepad = TRUE;
else    bReplaceNotepad = FALSE;
RegCloseKey(key);


수정된 결과는 아래와 같다. 짜잔~

사용자 삽입 이미지

수정에 수고해주신 구차니님께 다시 한 번 감사드립니다.

notepad2 컴파일 삽질기 1++ : 기본적인 오류수정 등(3.1.21 정식버전용)

사용자 삽입 이미지


Notepad23.1.21 최종판이 드디어 공개되었다.
이에 따라 3.2.21의 한글입력기 등의 패치 방법을 설명한다.
(이 패치는 Scintilla 라이브러리도 함께 수정하기 때문에 Notepad2의 정식패치가 될 가망은 없음)

notepad2 컴파일 삽질기 1++ : 기본적인 오류 수정(3.1.21.5-rc4용)에서 3.1.21-rc4의 소스를 수정하는 방법을 설명했는데, 3.1.21 정식버전에서 아주 조금 바뀌었다.
3.1.21의 소스를 Visual C++ v6.0에서 컴파일할 수 있도록 수정하는 방법을 설명하겠다.


0. 들어가기 전에

다음과 같은 내용은 모두 준비가 되어있다고 가정하고 설명함.
a. Visual C++ v6.0 및 Service Pack 6 설치
b. Platform SDK 설치 (Windows® Server 2003 R2 Platform SDK ISO Download)
c. Scintilla 1.78 다운로드
d. np2-3.1.21-build_vc6.patch 적용



1. Edit.c 수정(예전 패치 그대로임)

void EditTitleCase(HWND hwnd) 메쏘드에서
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'?,pszTextW[i])) {
라는 행을 찾아
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'",pszTextW[i])) {
로 바꿔준다.
이건 소스 쪽 오타다. ㅠ.ㅠ (이건 정말 왜 수정하지 않을까?)



2. Styles.c 수정(약간 수정되었음)

Notepad2/Scintilla에는 약간 이상한 버그가 하나 있다.
글꼴을 지정하는 과정에서 charset이 0으로 기록되면 다른 프로그램으로의 복사/붙이기가 정확하게 이루어지지 않는다.
(okto님께서 Notepad2 제작자에게 문의를 하셨지만, Scintilla 쪽 버그라 손을 안 대겠단 답을 들었음)

이 문제를 간단히 해결하기 위해 charset이 0인 경우는 기록하지 않도록 수정한다.

BOOL Style_SelectFont(HWND hwnd,LPWSTR lpszStyle,int cchStyle,BOOL bDefaultStyle) 메쏘드의 두 군데를 수정하면 된다.
우선, 아래와 같은 부분을 찾는다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != ANSI_CHARSET &&
    lf.lfCharSet != iDefaultCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}
이곳을 아래와 같이 고쳐준다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != ANSI_CHARSET &&
    lf.lfCharSet != iDefaultCharSet &&
    lf.lfCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}


다음으로 이렇게 생긴 부분을 찾는다.
if (Style_StrGetCharSet(lpszStyle,&iValue))
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}
이곳은 이렇게 고친다.
if (Style_StrGetCharSet(lpszStyle,&iValue) && iValue)
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}

2009년 6월 8일 월요일

notepad2 컴파일 삽질기 부록#4 : AutoHotkey 스킴 추가

Zach Thibeau님께서 공개하신 AutoHotkey 스킴을 지원토록 수정된 소스를 설명한 글로, Zach님의 허락[footnote]정확히는 Zach님께서 코드를 작성하신 것은 아니라고 함. 다른 분이라는데, 누군지 확인은 못함.[/footnote]하에 올림.


Notepad2 용 AutoHotkey 스킴을 원하시는 분들이 계시던데, AutoHotkey 포럼에 Zach Thibeau님께서 수정된 소스를 공개하셨다.
하지만, 이 소스는 3.0.20 기반으로 되어있으며, 3.1.21.5 기반의 수정은 별도로 공개되어 있지 않다.
그래서 Zach님께서 어떻게 AutoHotkey 스킴을 수정하셨는가하는 방법을 설명하겠다.

이 수정은 (비록 Notepad2 컴파일 삽질기의 일부이지만) 지금까지의 수정을 하나도 하지 않은 상태에서도 적용이 가능하다.

1. SciLexer.h 수정

SciLexer.h는 전체가 #define 문으로 이루어져 있다.
여기에 아래의 내용을 추가한다.

#define SCLEX_AHK1 98
#define SCE_AHK_DEFAULT 0
#define SCE_AHK_COMMENTLINE 1
#define SCE_AHK_COMMENTBLOCK 2
#define SCE_AHK_ESCAPE 3
#define SCE_AHK_SYNOPERATOR 4
#define SCE_AHK_EXPOPERATOR 5
#define SCE_AHK_STRING 6
#define SCE_AHK_NUMBER 7
#define SCE_AHK_IDENTIFIER 8
#define SCE_AHK_VARREF 9
#define SCE_AHK_LABEL 10
#define SCE_AHK_WORD_CF 11
#define SCE_AHK_WORD_CMD 12
#define SCE_AHK_WORD_FN 13
#define SCE_AHK_WORD_DIR 14
#define SCE_AHK_WORD_KB 15
#define SCE_AHK_WORD_VAR 16
#define SCE_AHK_WORD_SP 17
#define SCE_AHK_WORD_UD 18
#define SCE_AHK_VARREFKW 19
#define SCE_AHK_ERROR 20



2. KeyWords.cxx

이 파일의 맨 끝부분은 아래와 같이 문법 스킴들을 링크하는 코드가 들어있다.

    LINK_LEXER(lmVHDL);
    LINK_LEXER(lmXML);
    LINK_LEXER(lmYAML);

//--Autogenerated -- end of automatically generated section

    return 1;
}

이 LINK_LEXER의 맨 아래에 아래와 같을 한 줄을 추가한다.

    LINK_LEXER(lmAHK1);



3. LexAHK1.cxx 파일 추가

Zach님께서 공개하신 소스 파일 중에서 LexAHK1.cxx 파일을 추출해서 같은 폴더에 저장한다.
저장 위치는 소스\scintilla\src.
그리고, Fileview에도 추가한다. 추가 위치는 Scintilla/src.

압축 파일의 해제가 번거로우시면 아래 코드를 사용해도 된다.

LexAHK1.cxx 소스 보기..




4. Styles.h의 수정

문법 스킴의 개수가 적힌 줄을 찾는다
아래와 같은 모양이다.

// Number of Lexers in pLexArray
#define NUMLEXERS 27

여기 적힌 개수를 하나 증가시킨다.
여기서는 27+1 = 28, 28을 적는다.
결과는 아래와 같다.

#define NUMLEXERS 28



5. Styles.c의 수정 1/2

Zach님께서 공개하신 소스 파일 중에서 Styles.c 파일에서 KEYWORDLIST KeyWords_AHK = { ... } 부분과 EDITLEXER lexAHK1 = { ... } 부분을 같은 위치에 추가한다.
정확한 추가 위치는 아래 코드의 앞부분이다.

// This array holds all the lexers...
PEDITLEXER pLexArray[NUMLEXERS] =

역시 압축 파일의 해제가 번거로우면 아래 코드를 사용해도 된다.

more..




6. Styles.c의 수정 2/2

앞의 5항에서 추가한 위치의 코드는 아래와 같은 모양이다.

// This array holds all the lexers...
PEDITLEXER pLexArray[NUMLEXERS] =
{
  &lexDefault,
  &lexHTML,
  //   :
  //중간 생략
  //   :
  &lexASCII
};

이 내용의 끝에 &lexAHK1을 추가한다. 아래와 같은 모양이 된다.

  &lexASCII,  // 앞의 코드 끝에 컴마(,)를 추가함
  &lexAHK1
};

이렇게 수정된 결과는 아래와 같다.

사용자 삽입 이미지

짜잔~ 이제 3.1.21.5-rc4에서도 AutoHotkey 스킴을 깔끔하게 지원한다



2009년 6월 5일 금요일

notepad2 컴파일 삽질기 1++ : 기본적인 오류 수정(3.1.21.5-rc4 용)

사용자 삽입 이미지

Notepad23.1.21.5로 곧 업그레이드 될 예정이다.
현재는 rc4까지 공개되었는데, rc4가 3월 10일에 나왔으니 조만간에 정식버전이 나올 것 같다.

그런데, rc4에서도 IME 입력문제는 해결이 되지 않았기 때문에 한글을 깔끔하게 입력하려면 패치를 해줘야 한다.
(아마도 앞으로도 계속 그럴 것 같다)

notepad2 컴파일 삽질기 1 : 기본적인 오류 수정에서 3.0.20의 소스를 수정하는 방법을 설명했는데, 3.1.21.5에서 환경이 조금 바뀌었다.
3.1.21.5의 소스를 Visual C++ v6.0에서 컴파일할 수 있도록 수정하는 방법을 설명하겠다.

VS2005, VS2008 등의 환경에서 사용할 수 있도록 수정하는 방법들은  notepad2 컴파일 삽질기 1에서 설명했으므로 넘어가겠다.


0. 들어가기 전에

다음과 같은 내용은 모두 준비가 되어있다고 가정하고 설명하겠다.
a. Visual C++ v6.0 및 Service Pack 6 설치
b. Platform SDK 설치 (Windows® Server 2003 R2 Platform SDK ISO Download)
c. Scintilla 1.78 다운로드
d. np2-3.1.21-build_vc6.patch 적용



1. Edit.c 수정(예전 패치 그대로이다)

void EditTitleCase(HWND hwnd) 메쏘드에서
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'?,pszTextW[i])) {
라는 행을 찾아
if (!IsCharAlphaNumericW(pszTextW[i]) && !StrChr(L"'",pszTextW[i])) {
로 바꿔준다.
이건 소스 쪽 오타다. ㅠ.ㅠ



2. Styles.c 수정(이것 역시 예전 패치 그대로다)

Notepad2/Scintilla에는 약간 이상한 버그가 하나 있다.
글꼴을 지정하는 과정에서 charset이 0으로 기록되면 다른 프로그램으로의 복사/붙이기가 정확하게 이루어지지 않는다는 점이다.
(okto님께서 Notepad2 제작자에게 문의를 하셨지만, Scintilla 쪽 버그라 손을 안 대겠단 답을 들었다)

이 문제를 간단히 해결하기 위해 charset이 0인 경우는 기록하지 않도록 수정한다.

BOOL Style_SelectFont(HWND hwnd,LPWSTR lpszStyle,int cchStyle,BOOL bDefaultStyle) 메쏘드의 두 군데를 수정하면 된다.
우선, 아래와 같은 부분을 찾는다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != iDefaultCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}
이곳을 아래와 같이 고쳐준다.
if (bDefaultStyle &&
    lf.lfCharSet != DEFAULT_CHARSET &&
    lf.lfCharSet != iDefaultCharSet &&
    lf.lfCharSet) {
  lstrcat(szNewStyle,L"; charset:");
  wsprintf(tch,L"%i",lf.lfCharSet);
  lstrcat(szNewStyle,tch);
}


다음으로 이렇게 생긴 부분을 찾는다.
if (Style_StrGetCharSet(lpszStyle,&iValue))
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}
이곳은 이렇게 고친다.
if (Style_StrGetCharSet(lpszStyle,&iValue) && iValue)
{
  if (lstrlen(szNewStyle))
    lstrcat(szNewStyle,L"; ");
  wsprintf(tch,L"charset:%i",iValue);
  lstrcat(szNewStyle,tch);
}



3. Scintilla 소스에 반영

Scintilla가 최근(4월) 1.78로 업데이트 되면서 PerLine.h, PerLine.cxx라는 파일 2개가 추가되었다.
그런데, 앞에서 언급한 VC6 패치에는 이 두 파일이 포함되어있지 않다.
이 두 파일을 소스에 추가해야 정상적으로 컴파일이 된다.
두 파일을 Scintilla/src 카테고리에 추가한다.
사용자 삽입 이미지

바로 여기다. ^^;




4. IME 패치

 IME 메시지를 처리하도록 수정undo/redo가 정상동작하도록 수정 (버그패치) 등은 3.1.21.5에도 그대로 적용된다.
그 패치를 적용하면 IME를 정상적으로 이용할 수 있다.


2009년 1월 11일 일요일

notepad2 버그패치: ASCII Art 수정

Notepad2 수정에 관련된 모든 포스트는 홈페이지에서 언급한 공식 패치를 모두 적용했다고 가정하고 시작했습니다.

그 패치들은 모두 무결할 것이라 믿었습니다만, 지금 보니 ASCII Art 쪽엔 약간의 버그가 있더군요.
정확히는 버그라기 보다는 기본 charset이나 글꼴 등이 그림을 제대로 그려주도록 지정되어 있지 않습니다.

그래서 .nfo 파일을 읽으면 아래와 같이 나와버립니다.

사용자 삽입 이미지

뭡니까, 이게~


이 문제는 Styles.c 에서 딱 한 군데만 수정하면 됩니다.
아래 부분을 찾습니다.
EDITLEXER lexASCII = { SCLEX_NULL, L"ASCII Art", L"nfo; diz", L"", &KeyWords_NULL, {
    { STYLE_DEFAULT, L"Default", L"font:Terminal; charset:255; size:9", L"" },


이 부분을 아래와 같이 수정합니다.
이름을 "ASCII Art"에서 "ASCII_Art"로 바꾸고, 글꼴과 색깔 등을 수정한 것입니다.
이름을 굳이 바꾼 이유는 기존 실행파일에서 notepad2.ini에 설정을 저장한 경우를 대비하기 위함입니다.
EDITLEXER lexASCII = { SCLEX_NULL, L"ASCII_Art", L"nfo; diz", L"", &KeyWords_NULL, {
    { STYLE_DEFAULT, L"Default", L"font:MS LineDraw; charset:1; size:9; fore:#D0D0D0; back:#000000", L"" },

이렇게 수정된 Notepad2로 .nfo 파일을 읽으면 아래와 같이 됩니다.

사용자 삽입 이미지

짜잔~~~~~~~~~~~~~



2009년 1월 7일 수요일

notepad2 컴파일 삽질기 부록#3 : 메모장 대신 사용

okto님 배포본 notepad2는 설치 및 윈도우 메모장 대체를 위해 notepad.inf 파일을 이용했습니다.
이 방식은 설치가 쉽다는 장점은 있지만, 설치 제거에 손이 많이 간다는 단점이 있습니다.

장점을 살리고 단점을 제거하기 위해 구차니님께서 메모장을 대체하는 기능을 구현해주셨습니다.
이 기능을 사용하려면 소스 코드를 아래와 같이 수정하면 됩니다.

반드시 notepad2 컴파일 삽질기 부록#2 : context-menu 추가 업그레이드를 적용한 후에 이 수정을 해야 합니다

수정 대상 파일은 역시 resource.h, Notepad2.rc, Notepad2.c 세 개입니다.


1. resource.h

우선, 다음 줄을 추가합니다.
#define IDM_REPLACE_NOTEPAD             40228


다음으로 아래 내용을 찾습니다.
#define _APS_NEXT_COMMAND_VALUE         40228
이것을 이렇게 수정합니다.
#define _APS_NEXT_COMMAND_VALUE         40229



2. Notepad2.rc

아래 내용을 찾습니다.
MENUITEM "Add context-menu to all file type", IDM_REGISTRY_ALL
, CHECKED
바로 앞에 다음 줄을 추가합니다.
MENUITEM "Replace Notepad",             IDM_REPLACE_NOTEPAD



3. Notepad2.c

앞부분에 다음 변수를 하나 선언합니다.
BOOL      bReplaceNotepad;


다음, void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾습니다.
CheckCmd(hmenu,IDM_REGISTRY_UNKNOWN,bRegistryUnknownType);
바로 앞에 다음 줄을 추가합니다.
CheckCmd(hmenu,IDM_REPLACE_NOTEPAD,bReplaceNotepad);


다음, LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에 다음 case 문을 추가합니다.
이 함수 전체가 하나의 switch-case 문으로 되어있는데, case를 하나 추가하는 것입니다.
case IDM_REPLACE_NOTEPAD:
    if (bReplaceNotepad)
    {
       //WinNT requires the key to have no subkeys
        RegDeleteKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe");
    }
    else
    {
        HKEY key1;
        LONG res = RegCreateKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&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\" /z", path);
            RegSetValueExW(key1, L"Debugger", 0, REG_SZ, cmd, len * 2);
        }
        RegCloseKey(key1);
    }
    bReplaceNotepad = (bReplaceNotepad) ? FALSE : TRUE;
    break;


마지막으로 void CheckRegistry() 함수의 마지막 부분에 다음 내용을 추가하면 됩니다.
res = RegOpenKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\notepad.exe",&key);
if(res == ERROR_SUCCESS)
        bReplaceNotepad = TRUE;
else    bReplaceNotepad = FALSE;
RegCloseKey(key);


수정된 결과는 아래와 같습니다. 짜잔~

사용자 삽입 이미지

수정에 계속 수고해주신 구차니님께 감사드립니다.

2008년 12월 30일 화요일

notepad2 컴파일 삽질기 부록#2 : context-menu 추가 업그레이드

구차니님께서 context-menu기능을 수정하신 내용을 notepad2 컴파일 삽질기 부록: context-menu 추가에 포스팅했습니다.
그런데, 수정 이후에 두 가지 내용을 수정하게되어 수정내용을 포스팅합니다.
수정된 내용은 아래와 같습니다.

흔쾌히 코드를 수정해주신 구차니님께 감사드립니다.

  1. 레지스트리 키 이름이 바로 메뉴에 뜨지 않고 별도의 문자열이 뜨도록 수정
  2. context-menu 등록여부를 ini파일이 아니라 레지스트리에서 직접 확인

코드를 수정하는 절차는 아래와 같습니다.
수정 대상 파일은 Notepad2.h, Notepad2.c 두 개입니다.

반드시 notepad2 컴파일 삽질기 부록 : context-menu 추가대로 수정한 후에 수정해야합니다.


1. Notepad2.h

새로운 함수 하나를 추가합니다.
void CheckRegistry();



2. Notepad2.c

LRESULT CALLBACK MainWndProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾습니다.
case WM_COMMAND:
  return MsgCommand(hwnd,wParam,lParam);
여기에 아래와 같이 한 줄을 추가합니다.
case WM_COMMAND:
  CheckRegistry();
  return MsgCommand(hwnd,wParam,lParam);



다음으로, LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)에서 아래 내용을 찾습니다. (notepad2 컴파일 삽질기 부록 : context-menu 추가에서 수정한 부분입니다)
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;
이 내용을 아래와 같이 수정합니다.
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",&key1);
  if (res == ERROR_SUCCESS)
    {
    WCHAR cmd[] = L"Open with &notepad2";
    RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
  }
    RegCloseKey(key1);

  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);
  }
    RegCloseKey(key1);
}       
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",&key1);
  if (res == ERROR_SUCCESS)
  {
    WCHAR cmd[] = L"Open with &notepad2";
    RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
  }
  RegCloseKey(key1);

  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);
  }
    RegCloseKey(key1);
}
bRegistryUnknownType = (bRegistryUnknownType) ? FALSE : TRUE;
break;



다음은 LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수를 수정합니다.
아래 내용을 찾아 삭제합니다. (이 부분 역시 notepad2 컴파일 삽질기 부록 : context-menu 추가에서 수정한 곳입니다)
case IDM_REGISTRY_UNKNOWN:
// Register registry - type unknown
break;

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



다음으로 void LoadSettings() 함수를 수정합니다.
아래 내용을 찾아 삭제합니다.(이 부분도 notepad2 컴파일 삽질기 부록 : context-menu 추가에서 수정한 곳입니다)
bRegistryUnknownType = IniSectionGetInt(pIniSection,L"RegistryUnknownType",0);
if (bRegistryUnknownType) bRegistryUnknownType = 1;

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



다음으로 void SaveSettings(BOOL bSaveSettingsNow) 함수를 수정합니다.
아래 내용을 찾아 삭제합니다.(이 부분도 notepad2 컴파일 삽질기 부록 : context-menu 추가에서 수정한 곳입니다)
IniSectionSetInt(pIniSection,L"RegistryUnknownType",bRegistryUnknownType);
IniSectionSetInt(pIniSection,L"RegistryAllType",bRegistryAllType);



마지막으로 함수를 하나 추가합니다.
void CheckRegistry()
{
    HKEY key;
    LONG res;

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryAllType = TRUE;
    else    bRegistryAllType = FALSE;
    RegCloseKey(key);

    res = RegOpenKey(HKEY_CLASSES_ROOT,L"unknown\\shell\\Open with notepad2",&key);
    if(res == ERROR_SUCCESS)
            bRegistryUnknownType = TRUE;
    else    bRegistryUnknownType = FALSE;
    RegCloseKey(key);
}


수정된 결과는 아래와 같습니다.
(한글화를 위해 메뉴 내용을 한글로 수정했습니다)

사용자 삽입 이미지


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

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

사용자 삽입 이미지

짜잔~~~~~~~~~