2008년 11월 30일 일요일

notepad2 컴파일 삽질기 1 : 기본적인 오류 수정

윈도우의 메모장을 대치할 수 있는 간단한 텍스트 편집기 중에 notepad2가 있습니다.
이 프로그램의 장점은 무엇보다 실행파일 하나로 구성되어 있어 언제나 갖고다니기 편하단 점입니다.
또한 널리 쓰이는 Scintilla를 기반으로 되어있어 안정성도 어느정도 검증되었다는 장점도 있습니다.

사용자 삽입 이미지

하지만, notepad2에는 다소의 문제점이 있습니다.

1. 한글 IME를 제대로 인식하지 않아 한글 입력 화면이 부자연스러움
2. 원 소스 자체에 약간의 에러 및 버그가 있음 (실행파일을 다운받을 땐 상관 없습니다)

이 외에도 VS.Net(7.0)으로 개발되어 이후 버전의 컴파일러로 컴파일시 약간 불편하단 점도 있더군요.


그래서, Visual Studio 8.0 Express Edition에서 notepad2의 소스를 수정하고 컴파일 해봤습니다.
기본적인 IME 부분 수정은 codewiz님의 방법을 참고했으며, 나머지 부분들은 사용 중에 문제가 있는 부분들 중심으로 수정했습니다.

사전 준비

1. Visual Studio 준비

Visual Studio 8.0 Express Edition에서 다운받을 수 있습니다.
※ 다른 버전(VS.Net 2003, VS 2005 등)에서는 일부 수정 방법이 아주 조금씩 다를 수 있습니다.


2. 소스 다운로드 및 적절한 폴더 설정

Notepad2, Scintilla 에서 각각 소스 파일을 다운로드 받습니다.
이 글을 쓰는 현재 기준으로 notepad2는 3.0.20이, Scintilla는 1.77이 최신버전입니다
일단 Notepad2의 소스의 압축을 풉니다.
다음으로, Scintilla의 소스를 notepad2의 소스 폴더 내에 압축을 풉니다.

사용자 삽입 이미지

이런 구성으로 폴더를 구성하면 됩니다


3. 솔루션 파일 변환

notepad2 소스의 루트 폴더에 Notepad2.sln이라는 솔루션 파일이 있습니다.
이 파일을 VS2008에서 읽어주면 변환은 끝납니다.
여기서 작업이 시작합니다.


step1. 각종 오류/버그 수정

오류/버그 수정은 파일 단위로 적겠습니다.

1. Dlapi.h

Dlapi.h 파일의 맨 마지막 부분에 아래의 3줄을 추가합니다.
#ifndef LPSHELLICON
typedef struct IShellIcon IShellIcon, *LPSHELLICON;
#endif


2. Edit.c

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


3. Helpers.c

void FormatBytes(LPWSTR lpOutput,int nOutput,DWORD dwBytes)에서
int i;
라는 행을 찾아
int i, iLen;
로 바꿔줍니다.

다음으로
swprintf(tch,L"%.2f",dBytes);
라는 행을 찾아
iLen = wsprintf(tch,L" %i",(DWORD)(dBytes*100));
memcpy(tch, tch+1, (iLen-3)*sizeof(WCHAR));
tch[iLen-3] = L'.';
의 세 줄로 수정합니다.


4. Notepad2.rc

"afxres.h"가 들어간 두 행을 찾습니다.
#include "afxres.h"

"#include ""afxres.h""\0"
입니다.


이 두 줄을 각각
#include "windows.h"
#ifndef IDC_STATIC
#define IDC_STATIC              (-1)
#endif

"#include ""windows.h""\0"
으로 바꿔줍니다.
Express Edition에는 afxres.h 파일이 없기 때문입니다.
(VS2005/VS2008의 리테일 버전에서는 이 작업은 필요없습니다)


다음으로,
IDR_RT_MANIFEST         RT_MANIFEST             "..\\res\\Notepad2.exe.manifest"
라는 manifest 지정행이 있는데, 이것을
//IDR_RT_MANIFEST         RT_MANIFEST             "..\\res\\Notepad2.exe.manifest"
과 같이 주석처리합니다.


5. Notepad2.h

VS2008에선 앞의 4번의 아랫부분과 같이 주석처리해도 이상없이 마니페스트 파일을 링크하던데, VS2005는 좀 다르더군요.
VS2005에서 제대로 마니페스트 파일을 링크하려면 Notepad2.h의 맨앞에
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
를 추가해야 합니다.


6. KeyWords.cxx
#define LINK_LEXER(lexer) extern LexerModule lexer; forcer += lexer.GetLanguage();
를 찾아서 다음과 같이 수정합니다.
//#define LINK_LEXER(lexer) extern LexerModule lexer; forcer += lexer.GetLanguage();
#define LINK_LEXER(lexer)

LINK_LEXETR에서 링크하는 외부모듈의 역할은 정확히 모르겠지만,
링크를 원천적으로 차단해버려야 제대로 링크가 되더군요... ㅡㅡ;;;


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


댓글 11개:

  1. 이렇게 어려운 포스팅을... 10%도 이해 못하는 1인~

    답글삭제
  2. 음... 아...! (마치 이해하겠다는듯...)

    답글삭제
  3. trackback from: 메모장2 (3.0.20)
    메모장2가 2.1.19에서 3.0.20으로 껑충 버전업한 것을 발견했다.이전 게시물에서도 언급했듯이 메모장2는 Florian Balmer가 공개하는 것 말고도 변종 프로젝트가 상당히 많다. 우연히 공식홈에 링크된 수정버전을 살펴봤는데 몇가지 유용한 패치가 되어있길래 소개한다.이번 버전의 한글화를 하면서 살펴보니 이전버전에 비해 달라진 점이 참 적었다. 그런데 왜 버전넘버는 1씩이나 올라간거냐-_- (누가 IME 패치도 좀 해줬으면 좋겠는데...;)...

    답글삭제
  4. 8D 왠지~!!! 따라하고 싶어졌어요~!!!.. 그래서 받고있다는.ㅡㅡ;; 우선 셤기간이끝나고 난뒤에..따라해봐야지~~ ^^..ㅋㅋㅋ

    답글삭제
  5. @potocosmos - 2008/12/11 01:29
    즐거운 경험이 되시기 바라겠습니다.

    답글삭제
  6. VC++ 2008 Express Edition으로 Unalz 빌드할 때 afxres.h 관련 에러가 발생하는데, BLUEnLIVE 님 글 덕분에 헤매지 않고 쉽게 해결할 수 있었습니다. 감사합니다. :)

    답글삭제
  7. @Kaisyu - 2009/03/30 15:11
    아... 그렇군요. 도움이 되셨다니 저도 기분이 좋습니다. ^^;

    답글삭제
  8. Your website helped me compile Notepad2 in Visual Studio 2008 Pro. I couldn't find this information anywhere else!

    감사합니다 !

    감사합니다 !

    감사합니다 !

    답글삭제
  9. @Brian - 2009/04/18 16:55
    Really? I'm happy to hear that.

    잘 쓰세요~

    답글삭제