2008년 12월 6일 토요일

notepad2 컴파일 삽질기 4 : Visual C++ 6.0 SP6 컴파일

step4. Visual C++ 6.0 SP6에서 컴파일

Visual Studio .Net2003/2005/2008 등으로 Notepad2를 컴파일하면 MSVCR**.dll 파일을 필요로 합니다.
물론, Visual Studio Redistribution을 설치하면 간단히 해결되는 문제(?)이긴 하죠.

하지만, 윈도우를 설치하자마자 기본 편집기로 지정하려고 하면 상황이 좀 복잡해집니다.
또, 단독실행버전을 가볍게 만들어 갖고 다니려고 해보면 뭔가 이상해집니다.

그래서! Visual C++ 6.0에서 컴파일해봤습니다.
이렇게 컴파일하면 무엇보다, 실행파일만 달랑 있으면 모든 것이 해결된다는 점입니다.

제작자 홈페이지에 링크된 패치 자료실에 가면 이런 저런 패치 자료가 올라와있습니다.
그 중 np2-3.0.20-build_vc6.patch는 Notepad2를 Visual C++ 6.0(이하 VC6)에서 컴파일할 수 있도록 해주는 패치입니다.

이 패치는 사실 VC6용 dsp 파일을 생성해주는 역할만을 담당합니다.

그런데… 문제는 이것만으로는 정상적으로 컴파일이 되지 않습니다.
notepad2 컴파일 삽질기 1, 삽질기 2, 삽질기 3의 내용을 모두 수정해도 말입니다.

아래의 수정과정을 거쳐야 VC6에서 컴파일할 수 있습니다.


1. VC6 설치

당연히, VC6을 먼저 설치해야 합니다. 그리고, Service Pack 6도 함께 설치합니다.


2. Platform SDK 설치

VC6 만으로는 제대로 컴파일되지 않습니다.
Platform SDK를 함께 설치해야 됩니다.
Windows® Server 2003 R2 Platform SDK ISO Download에서 다운받으면 됩니다.
(Server 2008용 PSDK도 공개되었는데, VC6에서 정식으로 지원하지 않습니다. ㅡㅡ;;
공식적으로는 2003년 2월 버전까지만 지원하는데, 이 버전에서도 제대로 동작하더군요)


3. VC6용 dsp 파일 만들기

np2-3.0.20-build_vc6.patch를 다운받아 Notepad2.dsp 파일을 만듭니다.
patch에 필요한 도구는 같은 페이지에 있는 np2-3.0.20-allpatches.7z에 함께 압축되어 있습니다.





Platform SDK 2003년 2월 버전을 설치해보니 아래의 패치가 필요하지 않더군요.
아래의 패치는 VC6에 Windows® Server 2003 R2 Platform SDK를 설치한 경우에만 필요합니다.
괜히 불필요한 코드 수정에 시간을 낭비했군요. ㅡㅡ;;;


이것으로 일반적인 준비가 끝났습니다.
하지만, 이것만으로는 충분하지 않고, 소스를 조금 수정해야 됩니다.

VC6+PSDK2003R2은 이후의 버전과 달리 유니코드를 완벽하게 지원하지 않습니다.
일부 메쏘드에서는 윈도우에서 처리된 유니코드를 WCHAR로 명시적으로 변환해주지 않으면 깨져나옵니다.

사용자 삽입 이미지

뭡니까, 이게~


4. Dlapi.c 수정

int DirList_Fill()에서 아래 부분을 찾아 몇 줄을 추가합니다.

szDisplayName를 선언합니다.
파일의 확장자가 .cpp/.cxx가 아니라 .c이기 때문에 반드시 맨 앞부분에 추가해야 합니다.
WCHAR szDisplayName[MAX_PATH*10];

다음으로 아래 코드를 찾습니다.
    lvi.iImage = (dwAttributes & SFGAO_FOLDER) ?
    lpdl->iDefIconFolder : lpdl->iDefIconFile;

    ListView_InsertItem(hwnd,&lvi);


이 코드를 아래와 같이 수정합니다.
ListView_InsertItem() 메써드 위에 4줄이 추가된 것입니다.
    lvi.iImage = (dwAttributes & SFGAO_FOLDER) ?
      lpdl->iDefIconFolder : lpdl->iDefIconFile;

    SHGetPathFromIDList(pidlEntry, szDisplayName);
    lvi.pszText = szDisplayName + wcslen(szDisplayName);
    while (lvi.pszText >= szDisplayName && (*(lvi.pszText) != L'\\')) lvi.pszText--;
    if (*(lvi.pszText) == L'\\') lvi.pszText++;

    ListView_InsertItem(hwnd,&lvi);


다음으로, BOOL IL_GetDisplayName()를 찾아 수정합니다.
새로 추가된 함수를 이용하는 경우에 공백을 정상적으로 인식하지 못하는 문제를 해결하기 위한 수정입니다.
일단, 아래 부분을 찾습니다.
    // Shlwapi.dll provides new function:
    return StrRetToBuf(&str,pidl,lpszDisplayName,nDisplayName);
    // ...but I suppose my version is faster ;-)
    /*switch (str.uType)
    {

      case STRRET_WSTR:
        WideCharToMultiByte(CP_ACP,
                            0,
                            str.pOleStr,
                            -1,
                            lpszDisplayName,
                            nDisplayName,
                            NULL,
                            NULL);
        g_lpMalloc->lpVtbl->Free(g_lpMalloc,str.pOleStr);
        break;

      case STRRET_OFFSET:
        lstrcpyn(lpszDisplayName,
                 ((WCHAR *)(pidl)) + str.uOffset,
                 nDisplayName);
        break;

      case STRRET_CSTR:
        lstrcpyn(lpszDisplayName,str.cStr,nDisplayName);
        break;

    }
    return TRUE;*/



이 부분을 아래와 같이 수정합니다.
    // Shlwapi.dll provides new function:
    //return StrRetToBuf(&str,pidl,lpszDisplayName,nDisplayName);
    // ...but I suppose my version is faster ;-)
    switch (str.uType)
    {

      case STRRET_WSTR:
        WideCharToMultiByte(CP_ACP,
                            0,
                            str.pOleStr,
                            -1,
                            lpszDisplayName,
                            nDisplayName,
                            NULL,
                            NULL);
        g_lpMalloc->lpVtbl->Free(g_lpMalloc,str.pOleStr);
        break;

      case STRRET_OFFSET:
        lstrcpyn(lpszDisplayName,
                 ((WCHAR *)(pidl)) + str.uOffset,
                 nDisplayName);
        break;

      case STRRET_CSTR:
        lstrcpyn(lpszDisplayName,str.cStr,nDisplayName);
        break;

    }
    return TRUE;
보시면 알겠지만, 단지 새로운 함수를 적용하며 주석처리한 옛 코드를 다시 살릴 뿐입니다.


5. Dialogs.c 수정

step4.에서 수정한 내용만으로도 다이얼로그의 글자는 정상적으로 표시됩니다.

사용자 삽입 이미지

짜잔~

하지만, 표시가 정상적으로 될 뿐 기능을 사용할 수는 없습니다.
(아이템을 선택한 뒤 OK 버튼을 클릭해보면 정상적으로 동작하지 않습니다)

정상적으로 동작하게 하려면 아래의 수정을 거쳐야 합니다.

일단, BOOL OpenWithDlg() 메쏘드의 앞부분에서 아래 부분을 찾습니다.
  if (IDOK == DialogBoxParam(g_hInstance,MAKEINTRESOURCE(IDD_OPENWITH),
                             hwnd,OpenWithDlgProc,(LPARAM)&dliOpenWith))
  {
    SHELLEXECUTEINFO sei;
    WCHAR szParam[MAX_PATH];

    ZeroMemory(&sei,sizeof(SHELLEXECUTEINFO));
    sei.cbSize = sizeof(SHELLEXECUTEINFO);
    sei.fMask = 0;
    sei.hwnd = hwnd;
    sei.lpVerb = NULL;
    sei.lpFile = dliOpenWith.szFileName;
    sei.lpParameters = szParam;
    sei.lpDirectory = NULL;

이 부분을 아래의 코드로 바꿔줍니다. 유니코드로 받은 데이터를 명시적으로 WCHAR로 변환해주는 것입니다.
  if (IDOK == DialogBoxParam(g_hInstance,MAKEINTRESOURCE(IDD_OPENWITH),
                             hwnd,OpenWithDlgProc,(LPARAM)&dliOpenWith))
  {
    SHELLEXECUTEINFO sei;
    WCHAR szFilename[MAX_PATH];
    WCHAR szParam[MAX_PATH];

    MultiByteToWideChar(CP_ACP,
        0,
        dliOpenWith.szFileName,
        -1,
        szFilename,
        MAX_PATH);

    ZeroMemory(&sei,sizeof(SHELLEXECUTEINFO));
    sei.cbSize = sizeof(SHELLEXECUTEINFO);
    sei.fMask = 0;
    sei.hwnd = hwnd;
    sei.lpVerb = NULL;
    sei.lpFile = szFilename;
    sei.lpParameters = szParam;
    sei.lpDirectory = NULL;
    sei.nShow = SW_SHOWNORMAL;


다음으로, BOOL FavoritesDlg(HWND hwnd,LPWSTR lpstrFile) 메쏘드에서 다음 부분을 찾습니다.
  lstrcpyn(lpstrFile,dliFavorite.szFileName,MAX_PATH);

이 부분을 아래의 코드로 바꿔줍니다.
  MultiByteToWideChar(CP_ACP,
    0,
    dliFavorite.szFileName,
    -1,
    lpstrFile,
    MAX_PATH);
이 부분 역시 유니코드로 받은 데이터를 명시적으로 WCHAR로 변환해주는 것입니다.

이렇게 변환된 소스는 VC6에서 정상적으로 컴파일되며, 독립실행버전을 만들거나 윈도우를 막 포맷한 상태에서도 정상적으로 사용할 수 있습니다.
(윈도우 98 및 그 이전 버전에서는 테스트해보지도 않았고 해볼 생각도 없습니다. ^^;;;)



댓글 23개:

  1. trackback from: 메모장2 (3.0.20)
    2008/12/6 이전에 수정버전을 받으신 분께서는 번거로우시더라도 새로 받으시기 바랍니다.그 사이 BLUEnLIVE님께서 버그 하나를 잡아주시고 컴파일도 새로 해주셔서 완전 단독실행 가능한 버전입니다.메모장2가 2.1.19에서 3.0.20으로 껑충 버전업한 것을 발견했다.이전 게시물에서도 언급했듯이 메모장2는 Florian Balmer가 공개하는 것 말고도 변종 프로젝트가 상당히 많다. 우연히 공식홈에 링크된 수정버전을 살펴봤는데 몇가지 유용한...

    답글삭제
  2. 방금 들어와서 (아~ 배불러) 확인해보니 이제는 정말 완전체인것 같네요. 감사합니당~

    답글삭제
  3. @okto - 2008/12/06 23:09
    오홍~ 굳굳굳

    답글삭제
  4. @okto - 2008/12/06 23:09
    아~ 지금 보니 (결과적으로는) 불필요한 수정이었다능~ ㅠ.ㅠ

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

    답글삭제
  6. @BLUEnLIVE - 2008/12/06 23:29
    다행히 버그가 안보이네요ㅎㅎ 이제 평생 이것만 쓸래요ㅠㅠ

    답글삭제
  7. :P 항상 열심 이시군요 ^^ 놀다갑네다~

    답글삭제
  8. @eliai534 - 2008/12/11 13:21
    언제나 웰컴~

    한해 마무리 잘 하길~

    답글삭제
  9. 이제야 들어와 보는 군요

    프로그램 수정하시느라 고생하셨나요 ^^

    한가지 팁을 말하자면 2005 이상에서 MSVCR**.dll 문제가 발생할때

    컴파일 옵션에서 띡띡 몇개만 바꿔주면 exe파일만 가지고도 실행이 되지요 ^^

    저도 올해 초쯤에 비슷한 문제로 골머리 좀 썩다가 해결한 문제라서 ㅎㅎㅎ



    PS. 언제 한번 배트맨 DVD 한번 구경시켜 주삼 ㅋㅋ

    답글삭제
  10. @JAFO - 2008/12/14 16:53
    물론, 그 방법은 알고 있습니다만, 원체 원래 소스가 다양한 환경을 지원하도록 만들어진 덕분에 static으로 컴파일하면 컴파일 자체가 안되더군요. ㅠ.ㅠ

    그게 잘 되었으면 설마 저 짓(??)을 했겠습니까?



    다음주에 도착한다고 합니다.

    도착하면 연락드리겠습니다. 쿠헬헬헬

    답글삭제
  11. 우클릭만 해결되면 acroedit에서 notepad로 갈 의향이 있는데 말이죠 ㅠ.ㅠ

    답글삭제
  12. @구차니 - 2008/12/15 18:21
    우클릭 문제라뇨? 뭔가 도움이 필요한가요?

    답글삭제
  13. @BLUEnLIVE - 2008/12/15 20:04
    우클릭 context-menu가 미지원이더라구요 ㅠ.ㅠ

    옥토님도 몇가지에 대해서만 우클릭 연결해서 쓰신다고 해서 조금 아쉬워서요 ^^

    답글삭제
  14. 혹시 notepad2 버그 수정한 실행파일 좀 보내주실 수 없나요? ^^

    min_mail@hanmail.net

    답글삭제
  15. frhed에 추가되어 있는 context-menu 를 적용해 볼까 하는데

    VC++ 6.0 뿐인데.. 패치 적용이 제대로 안되서 프로젝트가 안되네요 ㅠ.ㅠ



    죄송하지만 패치 적용된 프로젝트를 메일이나 링크 걸어 주실수 있으신가요?

    답글삭제
  16. @toto - 2008/12/18 09:49
    okto님 블로그에 가시면 버그 수정된 실행파일에 한글화까지 한 버전을 다운받으실 수 있습니다. ^^;;;

    답글삭제
  17. @구차니 - 2008/12/18 13:28
    이런... 링크는 좀 부담스럽고, 주소를 알려주시면 VC6용 소스를 메일로 보내드리겠습니다.



    참, 글에도 적었듯이 PSDK는 정확한 버전을 설치해야 잘 컴파일됩니다. ^^:;;

    답글삭제
  18. 그냥 frhed 에서 사용하는 방식대로 모든 파일에 대해서 context-menu 를 사용시

    "open with notepad2" 를 추가해서 사용중입니다 ^^



    그나저나.. .net이 많이 쓰이나 보네요 ㅠ.ㅠ

    전 닷넷 알레르기가 있어서 말이죠 후우..



    처음에 notepad2 소스 받아서 .net용 프로젝트 보고 아이C~ 소리 나오더라구요 ㅋ

    조금은 번거로웠지만 frhed 소스에서(API 스타일) 레지스트리 키 삽입하여 context-menu 제어 하는 부분을 직접 수정해 볼까하다가 그냥 귀차니즘에 졌답니다. OTL





    아 메일은 minimonk골뱅이네이트닷컴 으로 부탁드리겠습니다 ^^

    답글삭제
  19. 원본 notepad2 파일에서 한글을 복사해서 다른 에디터에 붙여넣으면 한글이 깨져서

    열심히 수정해서 올려놓은 파일을 받아서 테스트해봤습니다.

    그런데 그 현상은 마찬가지였습니다.

    어떻게 해결 좀 안될까요? ^^

    답글삭제
  20. @toto - 2008/12/26 14:49
    원본 notepad2의 문제는 원제작자에게 질문은 해주시기 바랍니다.

    답글삭제
  21. 여기서 받은 파일에서도 그런 현상이 나는데 어떻게 해결 안될까요?

    그래서 매번 utf-8 로 변환해서 사용해야 되더라구요. ^^;

    답글삭제
  22. @toto - 2009/01/10 16:49
    저는 notepad2의 실행파일을 전혀 배포하지 않는데 "여기서 받은 파일"이란 말씀은 무슨 뜻인지 모르겠군요.

    답글삭제
  23. @toto - 2009/01/10 16:49
    덧붙여서, 질문/요청을 올리셨는데, 무슨 내용인지를 알 수가 없군요.



    질문이 명확하지 않으면 도와드릴 수 있는 방법은 전혀 없습니다.

    답글삭제