winAPI와 C를 사용하여 아주 간단한 창 하나 만들 때

kashmir의 이미지

요즘 MSVC++2005를 사용하여 C/C++를 배워볼까 하고 공부를 시작하였습니다.

WINAPI에 대하여 http://www.winprog.org/tutorial/에서 보고 있는데 다음의 코드를 빌드하여 실행하였을 때 이상한 결과가 나오네요.

#include <windows.h>

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
		case WM_LBUTTONDOWN:    
			{
            char szFileName[MAX_PATH];
            HINSTANCE hInstance = GetModuleHandle(NULL);

            GetModuleFileName(hInstance, szFileName, MAX_PATH);
            MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
        }
		break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Window Title",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

아주 간단한 창 하나를 만드는데 창 제목이 이상하게 나옵니다. 만약 영어로 쓰면 이상한 중국어가 뜨고, 한글로 쓰면 네모로 나오네요.

뭐가 잘못된 걸까요 ? 아니면 언어 설정을 따로 해줘야 하는건가요 ?

kashmir의 이미지

Properties에 가서 이것저것 찾다가

Project Defaults에서 Character Set를 Unicode에서 Multi-Byte로 바꾸니까 잘 나오네요.

유니코드가 더 새로운 것이라 하던데 - 솔직히 뭔지 잘 모릅니다 - 어떻게 하면 Unicode로도 잘 나올까요 ? 아니면 이건 아직 초보한테는 어려운 욕심인가요 ?

lovian의 이미지

TEXT라는 키워드 사용해 보셨는지요?

그리고 wchar 같은 것을 사용하는 것 같던데..

:)

-----------------
한글을 사랑합니다.

z4ch4ri4h의 이미지

소스를 보시면 아시겠지만 유니코드가 고려되지 않은 소스입니다.
lovian님 말씀대로 유니코드로 바꾸시려면
wchar_t value = L"알라뷰"; 식으로 사용하셔야만 합니다.

하지만 이건 문자열 리터럴에만 해당되는 얘기고 특정 구조체나 API는 와이드버전과 아스키버전으로 나뉩니다.
가령 위 소스에선 WNDCLASSEX구조체가
lpszMenuName;
lpszClassName;
라는 문자열포인터 멤버를 갖고 있기 때문에 W형과 A형으로 나뉩니다.
VC++는 #define UNICODE나 #define _UNICODE가 설정되어있으면 WNDCLASSEX를 WNDCLASSEXW로 대치하고 아니면 A로 대치합니다.
문자열(혹은 문자열포인터)를 인자로 받는 API의 경우도 이런식으로 처리됩니다.

유니코드로 컴파일을 하면 어느나라권 윈도우즈에서라도 글자가 이쁘게 표현되겠지만 단점으론 Win9x커널에선 동작하지 않습니다.
이유는 RegisterClass() API가 W형이 엔트리가 있긴 하지만 곧바로 0을 리턴해버립니다. 즉 9x계열에선 정상동작을 할수가 없습니다.

그럼 MBCS(Multi-byte Character Set)와 UNICODE, 두가지 버전의 소스를 관리해야할까요?
Windows에선 이를 해결하기 위한 몇가지 꽁수를 지원합니다.
위와 마찬가지로 문자형을 TCHAR을 쓰면 MBCS에선 char가, UNICODE에선 wchar_t로 바꿔줍니다.
그리고 문자열 리터럴은 L을 붙이는것보다 위에 lovian님께서 말씀하신대로
TCHAR *lpText = TEXT("한글최고");식으로 하시면 유니코드일때만 L을 붙여줍니다. 하지만 좀더 간편하게 __T("한글최고")나 _T("한글최고")로 단축매크로를 자주 사용합니다.
그리고 C의 문자열 처리 함수들도 strlen()대신 _tcslen()처럼 _t군을 호출해주어야합니다.(역시 마찬가지로 유니코드일땐 와이드버전을 호출해줍니다)

여기까지가 윈도우즈에서 유니코드컴파일하는 방법이였습니다.
아참, 그리고 윈도우즈의 유니코드 인코딩은 많은 분들께(그리고 저에게도)사랑받는 UTF-8은 아닙니다.
2바이트만을 사용하는 UCS-2입니다.

kashmir의 이미지

답변들 감사합니다.

아직 뭐가 뭔지 어리버리하지만 재밌네요 :)

hyperhidrosis의 이미지

Quote:
아참, 그리고 윈도우즈의 유니코드 인코딩은 많은 분들께(그리고 저에게도)사랑받는 UTF-8은 아닙니다.
2바이트만을 사용하는 UCS-2입니다.

UTF8 은 중간에 데이타를 건네주는 입장에서는 편리한 인코딩 이지만,
데이타를 직접 처리하는 입장에서는 불편한 인코딩 입니다..
직접 데이타를 처리할때에는 결국 UCS2 로 바꿔야
처리가 가능합니다..
아마도 VI 도 UTF8 파일을 읽어서 내부적으로 메모리에는 UCS2(wchar_t)
로 들고 있을껍니다.

익명 사용자의 이미지

utf8은 기존 ascii 코드를 처리하는 프로그램이나 라이브러리에서
유니코드를 별 문제 없이 처리하기 위해 고안한 인코딩 방식이죠.

eungkyu의 이미지

Anonymous wrote:
utf8은 기존 ascii 코드를 처리하는 프로그램이나 라이브러리에서
유니코드를 별 문제 없이 처리하기 위해 고안한 인코딩 방식이죠.

그러게요. 사실 전 qt나 gtk에서 내부적으로 UCS-[24]를 사용하지 않고 UTF-8을 사용하도록 한 정책에 대해 좀 불만입니다.

IO용 인코딩으로서는 모를까 내부 처리용으론 (특히 CJK에게) UTF-8은 별로인거 같습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.