2012-08-09 16 views
11

Visual C++ 2012 RC, Win7C++: Dlaczego ten tytuł okna zostanie obcięty?

chiński uproszczony

Właściwości projektu> użyj wielofunkcyjnego charakteru bajt ustawiony

Kiedy uruchomić ten program, tytuł okna pokazuje pojedynczą literę "S", a nie cały słowo "Próbka".

#pragma comment(linker, "/SubSystem:Windows") 

#include <windows.h> 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int) { 
    WNDCLASSW wc = { 0 }; 

    wc.style   = CS_VREDRAW | CS_HREDRAW; 
    wc.hInstance  = hInstance; 
    wc.hIcon   = LoadIcon(nullptr, IDI_APPLICATION); 
    wc.hCursor   = LoadCursor(nullptr, IDC_ARROW); 
    wc.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); 
    wc.lpszClassName = L"MyWindowClass"; 

    wc.lpfnWndProc = [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
     if (uMsg - WM_DESTROY) 
      return DefWindowProc(hWnd, uMsg, wParam, lParam); 
     else { 
      PostQuitMessage(0); 
      return HRESULT(); 
     } 
    }; 

    RegisterClassW(&wc); 

    CreateWindowExW(0, L"MyWindowClass", L"Sample", 
     WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, SW_SHOW, CW_USEDEFAULT, 0, 
     nullptr, nullptr, hInstance, nullptr); 

    for (MSG msg; GetMessage(&msg, nullptr, 0, 0); DispatchMessage(&msg)); 
} 

Gdybym używać Unicode (Właściwości projektu), zachować bez zmian kodu źródłowego, tytuł okna pokazuje „próbka”, wygląda poprawnie.

Jeśli używam wielu bajtów, w kodzie źródłowym używam WNDCLASS = {..., "MyWindowClass"} i RegisterClassA, utrzymuję CreateWindowExW niezmieniony, tytuł okna pokazuje słowo "Sample", wygląda poprawnie.

Jeśli używam wielu bajtów, w kodzie źródłowym używam CreateWindowExA ("MyWindowClass", "Sample"), utrzymuj WNDCLASSW i RegisterClassW niezmienione, tytuł okna pokazuje literę "S".

Co sprawia, że ​​pokazuje się pojedyncze "S", czy robię coś nie tak?

Dołącz

Gdybym zachować wszystko bez zmian, czyli używać wielu bajt, kod użytkowania przedstawionego powyżej, tytuł okna pokazuje litery „S”.

(Jeśli uruchomisz ten program i zobaczysz "Przykład" w tytule okna, zamiast "S", to jest bardziej prawdopodobny konkretny problem z wersją chs vC++ 2012 (lub OS)).

+2

Dlaczego opublikowałeś kod wersji, która działa poprawnie? Wersja, która nie działa, byłaby o wiele bardziej użyteczna w diagnozowaniu problemu. –

+0

To wygląda dziwnie. Używana wersja RegisterClass określa, czy jest to okno Unicode ('IsWindowUnicode()'), czy też nie. Windows robi dwukierunkowe tłumaczenie Unicode <-> ANSI, więc powinieneś móc mieszać wywołania funkcji Unicode i ANSI. Ale: dlaczego miałbyś to robić? Czemu po prostu nie użyć jednego z nich, najlepiej tych bez A i W na końcu, tak aby pliki nagłówkowe okien były odwzorowane do wersji ustawionej we właściwościach projektu (np. 'RegisterClass' - bez A lub W, mapowanie do' RegisterClassA 'lub' RegisterClassW' automatycznie)? –

+0

@Joe Gauterin Jeśli powyższy kod jest poprawny, poprawnie pokazuje "Sample" w tytule okna, to może to błąd w VC++ 2012 RC chs. Powyższy kod pokazuje pojedynczą literę "S" w moim systemie: D – WangZm

Odpowiedz

16

Problem w kodzie polega na tym, że używasz DefWindowProc zamiast DefWindowProcW. Zmiana spowoduje naprawienie kodu.

Najlepiej byłoby zmienić ustawienia projektu, aby korzystać z zestawu znaków Unicode, a nie zestawu wielobajtowego. Uprości to wszystko i możesz używać makr, takich jak CreateWindowEx i RegisterClassEx zamiast jawnie używać wersji Unicode/ANSI, tak jak i Ty.

Tak jak powiedzieli inni, jest to niedopasowanie między zestawami znaków.

Powinieneś idealnie dopasować zestawy znaków między wszystkimi Twoimi połączeniami API, które współdziałają ze sobą. Więc jeśli używasz CreateWindowExW należy również używać RegisterClassExW, DefWindowProcW, DispatchMessageW ...

+0

To jest najwyraźniej najlepsza praktyka.Ale gdzie znalazłeś definicję, która mówi, że nie możesz połączyć RegisterClassW i CreateWindowA? Dokumentacja MSDN dla 'IsWindowUnicode' mówi, że możesz mieszać Unicode i ANSI (okna i wiadomości). Niestety nie mówią nic o CreateWindowExA/W i RegisterClassA/W. –

+0

@WernerHenze: Masz rację, że nie jest to konieczne. W rzeczywistości myliłem się, że było to niedopasowanie między 'CreateWindowEx' i' RegisterClassEx'. W rzeczywistości było to niedopasowanie między 'RegisterClassEx' i' DefWindowProc'. – tenfour

+0

@tenfour: DefWindowProcW, dokładnie! Problem rozwiązany, dzięki! Podczas korzystania z RegisterClassW/CreateWindowExW musimy wywołać DefWindowProcW. Do Wernera Henze: "To jest najwyraźniej najlepsza praktyka, ale gdzie znalazłeś definicję, która mówi, że nie możesz połączyć RegisterClassW i CreateWindowA?" Zgoda: D – WangZm

0

W twoim ostatnim przypadku Twoja L "Próbka" nadal pozostaje Unikodem, prawda? Możesz użyć makra _T(), które automatycznie dodaje lub usuwa prefiks L w zależności od ustawienia Unuicode projektu.

I Unicode L "Sample", jak już powiedział @Pete, jest "S \ 0 ..." w ascii, dlatego drukowany jest tylko jeden symbol.

+0

Używasz '_T()' z makrem 'CreateWindowEx'. Tutaj jawnie używa 'CreateWindowExW', więc nie jest to istotne. – tenfour

+0

Proszę przeczytać mój post ponownie, mówię tylko o ostatnim przypadku autora (gdzie ma problemy). Używa tam CreateWindowExA. – Steed

+0

Oryginalny plakat powiedział, że w przypadku, gdy wywoła CreateWindowExA ("MyWindowClass", "Sample") tytuł okna jest niepoprawny. Nie pisze tam "próbki". –

2

CreateWindowExA interpretuje ciąg jako 8-bitowe znaki. Drugie 8 bitów L "Sample" wynosi zero, ponieważ jego pierwszym znakiem jest 0x0053 - L oznacza szerokie znaki. Tak więc funkcja interpretuje to jako łańcuch zakończony 1 znakiem null.

+0

Nie należy również używać CreateWindowExA ani CreateWindowExW, wystarczy użyć CreateWindowEx i pozwolić preprocesorowi na określenie, którego z nich należy używać zgodnie z ustawieniami zestawu znaków. To samo dotyczy wszystkich innych funkcji Win32. – Pete

+0

Oryginalny plakat powiedział, że w przypadku, gdy wywoła "CreateWindowExA (" MyWindowClass "," Sample ")' tytuł okna jest niepoprawny. Nie pisze "Próbki" L "tam. –

1

myślę, że msdn page for RegisterClass podpowiedzi na przyczynę niepowodzenia tutaj, w sekcji uwagi, jak wspomina, że ​​jeśli użyć szerokiego znaku lub ANSI wsparcie, następnie przekaże wewnętrzne parametry tekstowe/wiadomość w tym formacie (szeroki char/ansi).Całkiem możliwe, że tak się dzieje z tytułem okna, chociaż mówimy o użyciu CreateWindowExA, to nie działa tak, jak wewnętrznie SDK systemu Windows zakodował ten ciąg jako szeroki ciąg znaków, a CreateWinowExA próbuje wyprowadzać tak, jakby był Ciąg Ansi.

W skrócie, nie mieszajcie metod W i A, chyba że masz ku temu dobry powód i niech zajmują się nim nagłówki Windowsa, jeśli chcesz szerokie wsparcie, zdefiniuj makro UNICODE.

4

To bardzo miłe, nauczyłem się czegoś nowego!

Musisz zmienić

return DefWindowProc(hWnd, uMsg, wParam, lParam); 

do

albo jeszcze lepiej: trzymać się jednego kodowania znaków. W najlepszym razie wystarczy użyć RegisterClass, CreateWindowEx i tak dalej, a następnie pozwolić kompilatorowi wybrać właściwą Unicode lub ANSI.

+0

Dzięki! W praktyce trzymam się tych makr Api i TEXT(). Jeśli chodzi o zabawę, chciałbym wyglądać dziwnie. :RE – WangZm

0

Cieszę się, że znalazłem to. Szukałem odpowiedzi na wszystkie pytania i wydaje mi się, że trudno jest znaleźć prawidłowe wyniki w Google itp. Znalazłem podobne problemy zgłaszane dla konkretnych programów, zawsze obwiniając "niektóre wtyczki".

To jest denerwujące, ponieważ problem z WndProc jest nigdzie w pobliżu połączenia do CreateWindowEx ani RegisterClassEx!

BTW, używam -W sufiksów jawnie, ponieważ chcę utworzyć jedną bibliotekę DLL, która działa dla programów zbudowanych w jedną stronę, lub pokonać ustawienia innych niż Unicode programu, do którego dodałem.

Powiązane problemy