레이블이 편집기인 게시물을 표시합니다. 모든 게시물 표시
레이블이 편집기인 게시물을 표시합니다. 모든 게시물 표시

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


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

사용자 삽입 이미지

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

notepad2 컴파일 삽질기 부록#5.2 : context-menu 기능 수정

삽질기 부록#5.1 : context-menu 통합 및 수정을 수정한 포스팅. 부록 #5/#5.1과 본 포스트는 동시 적용불가.

구차니님께서 수고해주신 덕분에 context 메뉴(오른쪽 버튼 클릭 메뉴)를 통해 Notepad2를 사용할 수 있었다.
(삽질기 부록#1 : context-menu 추가삽질기 부록#2 : context-menu 추가 업그레이드 참조)

그런데, Notepad2 3.1.21 정식버전에서는 이 수정을 미묘하게 바꿔야 했으며, 이후 okto님구차니님과 context 메뉴에 대한 수정을 논의한 결과 메뉴를 조금 간결하게 변형하기로 했다.
(File 메뉴에 있는 context-menu 관련 메뉴를 하나만 남기도록 수정)

그리고, 레지스트리에 등록이 실패했을 때의 코드가 빠져있었는데, 실패했을 경우 간단한 경보음을 들려주도록 했다.

삽질기 1~3을 모두 적용했다고 가정하고 시작한다.
그리고, notepad2 컴파일 삽질기 부록#5.1 : context-menu 통합 및 수정은 적용하지 않은 상태에서 시작한다.


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


1. resource.h

다음 한 줄을 추가.
#define IDM_REGISTRY_ALL            40690


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 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.h

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


4. Notepad2.c

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


다음, 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);


다음, 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));
이 부분을 아래와 같이 수정한다. 1줄을 추가하는 것임.
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_ALL,bRegistryAllType || bRegistryUnknownType);

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


다음은 LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정임.
이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 case 중에 IDM_REGISTRY_ALL을 추가함.
case IDM_REGISTRY_ALL:
// Register registry - type all
if (bRegistryAllType || bRegistryUnknownType)
{
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");
bRegistryAllType = FALSE;
}
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");
bRegistryUnknownType = FALSE;
}
}
else
{
HKEY key1;
LONG res = RegCreateKey(HKEY_CLASSES_ROOT,L"*\\shell\\Open with notepad2",&key1);
bRegistryAllType = TRUE;
if (res == ERROR_SUCCESS)
{
WCHAR cmd[] = L"Open with &notepad2";
RegSetValue(key1, NULL, REG_SZ, cmd, wcslen(cmd));
}
else bRegistryAllType = FALSE;
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);
}
else bRegistryAllType = FALSE;
RegCloseKey(key1);

if (!bRegistryAllType)
{
MessageBeep(MB_ICONEXCLAMATION);
}
}
break;


마지막으로 함수를 하나 추가한다.
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);
}

이렇게 수정하면 아래처럼 File 메뉴에서 context-menu 메뉴 하나가 표시된다.

사용자 삽입 이미지

context-menu가 하나만 나오도록 수정. ^^;


notepad2 컴파일 삽질기 부록#11 : 포트란 스킴 추가

회사에서 일을 하면서 포트란 소스를 C++로 변환할 일이 생겼다.
notepad2에서 포트란 스킴을 지원하는 줄 알았는데, 지금 보니 지원하지 않았다. 헐~

그래서 포트란 스킴을 추가하기로 했다.
notepad2에서 사용하는 Scintilla에서는 포트란 스킴은 지원하지만, 이를 notepad2에서 사용하지 않는 것이다.
따라서, 이를 사용하기 위해서는 조금만 수정하면 된다.

포트란 스킴을 사용하려면 아래와 같이 수정하면 된다.


1. Notepad2.rc 수정

아래와 같은 부분을 찾는다.
    63016                   "Batch Files"
    63017                   "Diff Files"
    63018                   "SQL Query"
    63019                   "Python Script"
    63020                   "Apache Config Files"
    63021                   "PowerShell Script"
END

여기에 아래와 같이 한 줄을 추가한다. 위치는 물론 END 바로 앞이며, 언어를 이미 추가한 경우 적절히 알아서 한다.
    63022                   "Fortran Source Code"
   63023                   "Fortran77 Source Code"


2. Styles.h 수정

아래와 같은 부분을 찾는다.
// Number of Lexers in pLexArray
#define NUMLEXERS 30

NUMLEXERS의 값을 둘 증가시킨다. 아래처럼.


#define NUMLEXERS 32


3. Styles.c 수정 #1

아래와 같은 부분을 찾는다.
// This array holds all the lexers...
PEDITLEXER pLexArray[NUMLEXERS] =
{
  &lexDefault,

바로 앞에 아래와 같은 코드를 추가한다.



// FORTRAN added by BLUEnLIVE - 25th June 2010
KEYWORDLIST KeyWords_FORTRAN = {
"abs achar acos acosd adjustl adjustr aimag aimax0 aimin0 aint ajmax0 "
"ajmin0 akmax0 akmin0 all allocated alog alog10 amax0 amax1 amin0 amin1 "
"amod anint any asin asind associated atan atan2 atan2d atand bitest bitl "
"bitlr bitrl bjtest bit_size bktest break btest cabs ccos cdabs cdcos cdexp "
"cdlog cdsin cdsqrt ceiling cexp char clog cmplx conjg cos cosd cosh count "
"cpu_time cshift csin csqrt dabs dacos dacosd dasin dasind datan datan2 "
"datan2d datand date date_and_time dble dcmplx dconjg dcos dcosd dcosh "
"dcotan ddim dexp dfloat dflotk dfloti dflotj digits dim dimag dint dlog "
"dlog10 dmax1 dmin1 dmod dnint dot_product dprod dreal dsign dsin dsind "
"dsinh dsqrt dtan dtand dtanh eoshift epsilon errsns exp exponent float "
"floati floatj floatk floor fraction free huge iabs iachar iand ibclr ibits "
"ibset ichar idate idim idint idnint ieor ifix iiabs iiand iibclr iibits "
"iibset iidim iidint iidnnt iieor iifix iint iior iiqint iiqnnt iishft "
"iishftc iisign ilen imax0 imax1 imin0 imin1 imod index inint inot int "
"int1 int2 int4 int8 iqint iqnint ior ishft ishftc isign isnan izext jiand "
"jibclr jibits jibset jidim jidint jidnnt jieor jifix jint jior jiqint jiqnnt "
"jishft jishftc jisign jmax0 jmax1 jmin0 jmin1 jmod jnint jnot jzext kiabs "
"kiand kibclr kibits kibset kidim kidint kidnnt kieor kifix kind kint kior "
"kishft kishftc kisign kmax0 kmax1 kmin0 kmin1 kmod knint knot kzext lbound "
"leadz len len_trim lenlge lge lgt lle llt log log10 logical lshift malloc "
"matmul max max0 max1 maxexponent maxloc maxval merge min min0 min1 "
"minexponent minloc minval mod modulo mvbits nearest nint not nworkers "
"number_of_processors pack popcnt poppar precision present product radix "
"random random_number random_seed range real repeat reshape rrspacing rshift "
"scale scan secnds selected_int_kind selected_real_kind set_exponent shape "
"sign sin sind sinh size sizeof sngl snglq spacing spread sqrt sum "
"system_clock tan tand tanh tiny transfer transpose trim ubound unpack verify",
"access action advance allocatable allocate apostrophe assign assignment "
"associate asynchronous backspace bind blank blockdata call case character "
"class close common complex contains continue cycle data deallocate decimal "
"delim default dimension direct do dowhile double doubleprecision else elseif "
"elsewhere encoding end endassociate endblockdata enddo endfile endforall "
"endfunction endif endinterface endmodule endprogram endselect endsubroutine "
"endtype endwhere entry eor equivalence err errmsg exist exit external file "
"flush fmt forall form format formatted function go goto id if implicit in "
"include inout integer inquire intent interface intrinsic iomsg iolength "
"iostat kind len logical module name named namelist nextrec nml none nullify "
"number only open opened operator optional out pad parameter pass pause "
"pending pointer pos position precision print private program protected "
"public quote read readwrite real rec recl recursive result return rewind "
"save select selectcase selecttype sequential sign size stat status stop "
"stream subroutine target then to type unformatted unit use value volatile "
"wait where while write",
"", "", "", "", "", "", "" };

EDITLEXER lexFORTRAN = { SCLEX_FORTRAN, 63022, L"Fortran Source Code", L"f; for; f90; f95", L"", &KeyWords_FORTRAN, {
    { STYLE_DEFAULT, 63126, L"Default", L"", L"" },
    { SCE_F_COMMENT, 63127, L"Comment", L"italics; fore:#008000", L"" },
    { SCE_F_NUMBER, 63130, L"Number", L"bold; fore:#0000FF", L"" },
    { MULTI_STYLE(SCE_F_STRING1,SCE_F_STRING2,SCE_F_STRINGEOL,0), 63131, L"String", L"fore:#008000", L"" },
    { MULTI_STYLE(SCE_F_OPERATOR,SCE_F_OPERATOR,0,0), 63132, L"Operator", L"bold", L"" },
    { SCE_F_IDENTIFIER, 63281, L"Identifier", L"bold; fore:#C80000", L"" },
    { SCE_F_WORD, 63236, L"Word", L"fore:#0000A0; bold", L"" },
    { SCE_F_WORD2, 63260, L"Word2", L"fore:#0000FF; bold", L"" },
    { SCE_F_WORD3, 63203, L"Word3", L"fore:#008000; bold", L"" },
    { SCE_F_PREPROCESSOR, 63133, L"Preprocessor", L"fore:#FF8000", L"" },
    { SCE_F_LABEL, 63235, L"Label", L"fore:#000000; back:#FFFFD1; bold", L"" },
    { SCE_F_CONTINUATION, 63257, L"Continuation", L"back:#FFC0C0", L"" },
    { -1, 00000, L"", L"", L"" } } };

EDITLEXER lexFORTRAN77 = { SCLEX_F77, 63023, L"Fortran77 Source Code", L"f77", L"", &KeyWords_FORTRAN, {
    { STYLE_DEFAULT, 63126, L"Default", L"", L"" },
    { SCE_F_COMMENT, 63127, L"Comment", L"italics; fore:#008000", L"" },
    { SCE_F_NUMBER, 63130, L"Number", L"bold; fore:#0000FF", L"" },
    { MULTI_STYLE(SCE_F_STRING1,SCE_F_STRING2,SCE_F_STRINGEOL,0), 63131, L"String", L"fore:#008000", L"" },
    { MULTI_STYLE(SCE_F_OPERATOR,SCE_F_OPERATOR,0,0), 63132, L"Operator", L"bold", L"" },
    { SCE_F_IDENTIFIER, 63281, L"Identifier", L"bold; fore:#C80000", L"" },
    { SCE_F_WORD, 63236, L"Word", L"fore:#0000A0; bold", L"" },
    { SCE_F_WORD2, 63260, L"Word2", L"fore:#0000FF; bold", L"" },
    { SCE_F_WORD3, 63203, L"Word3", L"fore:#008000; bold", L"" },
    { SCE_F_PREPROCESSOR, 63133, L"Preprocessor", L"fore:#FF8000", L"" },
    { SCE_F_LABEL, 63235, L"Label", L"fore:#000000; back:#FFFFD1; bold", L"" },
    { SCE_F_CONTINUATION, 63257, L"Continuation", L"back:#FFC0C0", L"" },
    { -1, 00000, L"", L"", L"" } } };

여기서 48, 63행의 63022, 63023은 위의 1번에서 추가한 값과 똑같아야 한다.


4. Styles.c 수정 #2


위의 3번에서 찾은 내용은 아래와 같이 생겼다.

PEDITLEXER pLexArray[NUMLEXERS] =
{
  &lexDefault,
  &lexHTML,
  &lexXML,
  &lexCSS,
  &lexJS,
  &lexVBS,

이 배열의 맨 마지막에 아래와 같은 내용을 추가한다.


  &lexFORTRAN,
  &lexFORTRAN77


이러한 수정이 적용된 화면은 아래와 같다.

포트란이 지원되는 메모장2!


2009년 11월 14일 토요일

notepad2 컴파일 삽질기 부록#10 : 시간/날짜 삽입 순서 변경

okto님의 블로그를 통해 삼각형 님께서 시간/날짜의 삽입 순서를 바꿔달란 요청을 해오셨다.

사용자 삽입 이미지

결국 직역의 한계는 그대로... ㄷㄷㄷ


처음엔 옵션 기능을 추가해서 선택적으로 바꿀 수 있도록 할 생각도 했지만, 결국 IME 패치를 사용하는 사람들은 모두 한국사람인지라 걍 순서를 바꾸는 것으로 수정. (전문용어로 게으르니즘이라고 한다)

수정 대상은 Notepad2.c 달랑 하나. (당연한 얘기다)

아래와 같은 줄을 찾는다.

wsprintf(tchDateTime,L"%s %s",tchTime,tchDate);

이걸 아래와 같이 고친다.

wsprintf(tchDateTime,L"%s %s",tchDate,tchTime);

참 쉽죠잉?

2009년 7월 10일 금요일

notepad2 컴파일 삽질기 5 : 스크롤 시 캐럿 출력 버그 수정

가급적 notepad2 3.x의 수정은 그만할 생각이었지만, 버그라서 수정했다. ㅠ.ㅠ


이 패치는 엄밀히는 삽질기 2 : IME 메시지를 처리하도록 수정과 함께 적용되어야 한다.
패치를 적용한 뒤에 notepad2를 사용해보면 스크롤 시에 캐럿이 늦게 반응하며, 잠깐씩 엉뚱한 위치게 가는 현상이 있다.
패치를 적용하게 되면 커서를 자체적으로 그리는데, 이게 스크롤 시에 좀 늦게 반응하기 때문이다.

수정 대상 파일은 ScintillaWin.cxx 하나이다.

void ScintillaWin::ScrollText(int linesToMove) 함수를 찾는다.
이 함수는 아래와 같은 내용이다.

void ScintillaWin::ScrollText(int linesToMove) {
    //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
    ::ScrollWindow(MainHWND(), 0,
        vs.lineHeight * linesToMove, 0, 0);
    ::UpdateWindow(MainHWND());
}

이것을 아래와 같이 수정한다.
캐럿을 삭제했다 다시 그리는 두 줄이 추가된 것이다.

void ScintillaWin::ScrollText(int linesToMove) {
    //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
    DestroySystemCaret();
    ::ScrollWindow(MainHWND(), 0,
        vs.lineHeight * linesToMove, 0, 0);
    ::UpdateWindow(MainHWND());
    CreateSystemCaret();
}

잘 쓰기 바란다.

덧. 수정을 강요(?)하신 구차니 님께 감사드립니다. ^^;

2009년 7월 1일 수요일

notepad2 컴파일 삽질기 부록#9 : 다음 바꾸기(Replace Next) 메뉴에 추가

okto님 블로그에서 잠시 언급된 건데, 추가하는 것이 어렵지 않아 삽질기 부록#8에 이어서 포스팅함

Notepad2에서는 찾기 관련된 기능은 모두 메뉴에 등록되어 있다.
찾기(Ctrl-F), 다음 찾기(F3), 이전 찾기(Shift-F3) 모두 말이다.

그런데, 바꾸기의 경우 바꾸기(Ctrl-H)는 등록되어 있는데, 다음 바꾸기(F4)는 메뉴에 등록되어 있지는 않다.
(기능 자체는 있다)

물론, 이 기능은 단축기를 이용하는 쪽이 훨씬 편한 기능이지만, 메뉴에 없으면 기능 자체를 모를 수 있어 메뉴에 넣기로 했다.


1. Notepad2.rc

아래와 같은 부분을 찾다. File 메뉴의 일부이다.

    MENUITEM "Select To Ne&xt\tF2",         IDM_EDIT_SELTONEXT
    MENUITEM "R&eplace...\tCtrl+H", IDM_EDIT_REPLACE

이 아래에 아래의 한 줄을 추가한다.

    MENUITEM "Replace Nex&t\tF4",           IDM_EDIT_REPLACENEXT



2. Notepad2.c

void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에서 아래와 같은 부분을 찾는다.

    EnableCmd(hmenu,IDM_EDIT_SELTOPREV,i && lstrlenA(efrData.szFind));
    EnableCmd(hmenu,IDM_EDIT_REPLACE,i /*&& !bReadOnly*/);


이 아래에 다음의 한 줄을 추가한다.

    EnableCmd(hmenu,IDM_EDIT_REPLACENEXT,i);


수정된 결과는 아래와 같다

사용자 삽입 이미지

짜잔~


notepad2 컴파일 삽질기 부록#8 : '기본 인코딩으로 다시 읽기' 메뉴로 할당

Notepad2 3.1로 HTML 파일을 편집하다보니 인코딩을 잘못 인식하는 경우가 발생했다.

Notepad2의 4.x 베타버전에는 인코딩을 수동으로 지정하는 기능이 있는데, 찾아보니 3.x에는 그런 기능까진 아니더라도 F8을 누르면 인코딩을 자동으로 확인하지 않고 기본 인코딩으로 다시 읽어주는 기능이 있더라.

가끔은 굉장히 필요한 기능인데, 메뉴에 따로 할당되지 않아 기능이 있다는 사실을 모르는 경우가 많을 것 같더라.
그래서, 이 기능을 별도의 메뉴로 지정했다.

이렇게 수정하는 방법은 아래와 같다.
수정할 대상은 Notepad2.rcNotepad2.c 두 개이다.


1. Notepad2.rc

아래와 같은 부분을 찾는다. File 메뉴의 일부이다.

    MENUITEM SEPARATOR
    MENUITEM "&Default...",                 IDM_ENCODING_SETDEFAULT

이 아래에 아래와 같은 두 줄을 추가한다.

    MENUITEM SEPARATOR
    MENUITEM "&Reload w/o Encoding Detection...\tF8",              CMD_F8



2. Notepad2.c

void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) 함수에서 아래와 같은 부분을 찾는다.

    //EnableCmd(hmenu,IDM_LINEENDINGS_LF,!bReadOnly);
    //EnableCmd(hmenu,IDM_LINEENDINGS_CR,!bReadOnly);


이 아래에 다음의 한 줄을 추가한다.

    EnableCmd(hmenu,CMD_F8,i);


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

사용자 삽입 이미지

깨진 인코딩 문제(적색으로 표시)는 Reload... 한 방으로 해결된다!


2009년 6월 30일 화요일

notepad2 컴파일 삽질기 부록#5.1 : context-menu 기능 수정

삽질기 부록#5 : context-menu 통합 및 수정을 수정한 포스팅임. 부록 #5 와 본 포스트는 동시에 적용할 수 없음.

구차니님께서 수고해주신 덕분에 context 메뉴(오른쪽 버튼 클릭 메뉴)를 통해 Notepad2를 사용할 수 있었다.
(삽질기 부록#1 : context-menu 추가삽질기 부록#2 : context-menu 추가 업그레이드 참조)

그런데, Notepad2 3.1.21 정식버전에서는 이 수정을 미묘하게 바꿔야 했으며, 이후 okto님구차니님과 context 메뉴에 대한 수정을 논의한 결과 메뉴를 조금 간결하게 변형하기로 했다.
(File 메뉴에 있는 context-menu 관련 메뉴를 하나만 남기도록 수정)


삽질기 1~3을 모두 적용했다고 가정하고 시작한다.
그리고, notepad2 컴파일 삽질기 부록#5 : context-menu 통합 및 수정 (#1, #2 통합)은 적용하지 않은 상태에서 시작한다.


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


1. resource.h (두 줄에서 한 줄로 줄어듦)

다음 한 줄을 추가.
#define IDM_REGISTRY_ALL            40690


2. Notepad2.rc (context-menu 항목이 하나로 줄어듦)

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 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.h (불변)

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


4. Notepad2.c (수정됨)

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


다음, 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);


다음, 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));
이 부분을 아래와 같이 수정한다. 1줄을 추가하는 것임.
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_ALL,bRegistryAllType || bRegistryUnknownType);

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


다음은 LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam)의 수정임.
이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 case 중에 IDM_REGISTRY_ALL을 추가함.
case IDM_REGISTRY_ALL:
// Register registry - type all
if (bRegistryAllType || bRegistryUnknownType)
{
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");
bRegistryAllType = FALSE;
}
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");
bRegistryUnknownType = FALSE;
}
}
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 = TRUE;
}
break;


마지막으로 함수를 하나 추가한다.
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);
}

이렇게 수정하면 아래처럼 File 메뉴에서 context-menu 메뉴 하나가 표시된다.

사용자 삽입 이미지

context-menu가 하나만 나오도록 수정. ^^;


notepad2 컴파일 삽질기 부록#7 : Shift+마우스 휠에 Page Up/Down 기능 부여

이 기능은 okto 님께서 건의하신 기능임. 구버전에 있었다고 주장하시지만, 그건 아니더라. ㅋㅋ

notepad2에 있는 마우스 휠 기능은 Ctrl키(확대/축소)가 전부다.
(Shift키와 함께 휠을 굴리면 아무런 동작을 하지 않는다)

그런데, Shift키와 함께 휠을 굴리면 Page Up/Down 기능이 동작되게 해달라는 요청이 있었다.
처음엔 그냥 못 들은 척 하려고 했지만(ㅎㅎㅎ) 사용자의 건의를 무시할 수 없어 기능을 부여하게 되었다.

이 기능을 부여하려면 아래처럼 수정하면 된다.

수정 대상 파일은 ScintillaWin.cxx 하나이며, 수정할 함수는 sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam)입니다.
그리고, 이 함수는 전체가 하나의 switch-case 문으로 되어있는데, 이 중 case WM_MOUSEWHEEL: 부분만 수정하면 된다.

case 바로 아래를 보면 아래와 같은 내용이 있다.

if (wParam & MK_SHIFT) {
    return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
}

이 곳은 Shift키와 함께 휠을 굴리면 무시하는 부분인데, 이 내용을 삭제한다.


다음으로, case 문의 끝부분에 있는 아래와 같은 내용을 찾는다.

    } else {
        // Scroll
        ScrollTo(topLine + linesToScroll);
    }

이 부분을 아래와 같이 수정한다.

    } else if (wParam & MK_SHIFT) {
        int topLineNew=topLine;
        if (linesToScroll < 0)
            topLineNew -= LinesToScroll();
        else
            topLineNew += LinesToScroll();
            ScrollTo(topLineNew);
    } else {
        // Scroll
        ScrollTo(topLine + linesToScroll);
    }

앞에서 무력화시킨 Shift의 처리를 여기에 추가하는 것이다.

이렇게 하면 Shift+휠을 Page Up/Down으로 사용할 수 있다.
여러분~ 즐삽하세요~


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 컴파일 삽질기 부록#5 : context-menu 통합 및 수정 (#1, #2 통합)

구차니님께서 수고해주신 덕분에 context 메뉴(오른쪽 버튼 클릭 메뉴)를 통해 Notepad2를 사용할 수 있었다.
(삽질기 부록#1 : context-menu 추가삽질기 부록#2 : context-menu 추가 업그레이드 참조)

그런데, Notepad2 3.1.21 정식버전에서는 이 수정을 미묘하게 바꿔야 했으며, okto님의 수정요청도 받아들여 수정한 것도 있어 전체를 통합한 수정방법을 포스팅한다.
(File 메뉴에서 context-menu 관련 체크박스 2개가 동시에 체크되지 않도록 수정)


삽질기 1~3을 모두 적용했다고 가정하고 시작함.

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


1. resource.h

다음 두 줄을 추가한다.
#define IDM_REGISTRY_UNKNOWN            40690
#define IDM_REGISTRY_ALL                40691


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.h

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


4. Notepad2.c

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


다음, 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);


다음, 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",&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);

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");
bRegistryUnknownType = FALSE;
}

}
bRegistryAllType = !bRegistryAllType;
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);
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");
bRegistryAllType = FALSE;
}

}
bRegistryUnknownType = !bRegistryUnknownType;
break;


마지막으로 함수를 하나 추가한다.
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);
}

이렇게 수정하면 아래처럼 File 메뉴에서 context-menu 관련 기능을 사용할 수 있다.

사용자 삽입 이미지

두 개의 context-menu중 하나만 선택되도록 수정했음. ^^;


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 스킴을 깔끔하게 지원한다