18

Visual C++ 2012 RC、Win7

中国語(簡体字

プロジェクトのプロパティ > マルチバイト文字セットを使用

このプログラムを実行すると、ウィンドウのタイトルに「Sample」という単語全体ではなく、1 文字の「S」が表示されます。

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

Unicode (プロジェクト プロパティ) を使用し、ソース コードを変更しない場合、ウィンドウ タイトルは "Sample" と表示され、正しく表示されます。

マルチバイトを使用する場合、ソース コードで WNDCLASS = { ..., "MyWindowClass" } と RegisterClassA を使用し、CreateWindowExW を変更せず、ウィンドウ タイトルに "Sample" という単語が表示され、正しいように見えます。

マルチバイトを使用する場合、ソース コードで CreateWindowExA("MyWindowClass", "Sample") を使用し、WNDCLASSW と RegisterClassW を変更せずに、ウィンドウ タイトルに文字 "S" を表示します。

単一の「S」が表示される理由は何ですか? 何か間違っていますか?

追加

すべてを変更しない場合、つまり、マルチバイトを使用し、上記のコードを使用すると、ウィンドウのタイトルに文字「S」が表示されます。

(このプログラムを実行して、ウィンドウ タイトルに "S" ではなく "Sample" が表示される場合は、vc++ 2012 (または OS) の chs バージョンに固有の問題である可能性が高くなります)。

4

6 に答える 6

32

コードの問題は、DefWindowProc代わりに を使用していることですDefWindowProcW。それを変更すると、コードが修正されます。

理想的には、マルチバイト文字セットではなく、Unicode を使用するようにプロジェクト設定を変更する必要があります。これによりすべてが簡素化され、Unicode / ANSI バージョンをそのまま明示的に使用する代わりに、CreateWindowExandのようなマクロを使用できます。RegisterClassEx

他の人が言ったように、これは文字セット間の不一致です。

相互にやり取りするすべての API 呼び出し間で文字セットを一致させることが理想的です。したがって、使用する場合は、 、、...CreateWindowExWも使用する必要があります。RegisterClassExWDefWindowProcWDispatchMessageW

于 2012-08-09T13:16:56.223 に答える
6

これはとてもいいものです。何か新しいことを学びました!

変更する必要があります

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

if(IsWindowUnicode(hWnd))  
  return DefWindowProcW(hWnd, uMsg, wParam, lParam);  
else  
  return DefWindowProcA(hWnd, uMsg, wParam, lParam);

またはさらに良いこと: 1 つの文字エンコーディングに固執します。せいぜい、などを使用して、コンパイラに正しい Unicode または ANSI 関数を使用RegisterClassCreateWindowExせます。

于 2012-08-09T14:20:42.550 に答える
2

CreateWindowExA は、文字列を 8 ビット文字として解釈します。最初の文字が 0x0053 であるため、L"Sample" の 2 番目の 8 ビットはゼロです。L はワイド文字を使用することを意味します。そのため、関数はそれを 1 文字の null で終了する文字列として解釈します。

于 2012-08-09T13:06:05.140 に答える
1

ここでの失敗の理由に関するヒントのmsdnページRegisterClassだと思います。備考セクションでは、ワイド文字またはANSIサポートのいずれかを使用する場合、内部テキストパラメータ/メッセージをこの形式で渡す方法について言及しています(ワイド文字/ANSI )。CreateWindowExAWindows SDK が内部的にその文字列をワイド文字列としてエンコードしCreateWinowExA、Ansi 文字列であるかのように出力しようとするため、これはウィンドウ タイトルで起こっている可能性があります。 .

つまり、正当な理由がない限り、W メソッドと A メソッドを混在させないでください。ワイド char のサポートが必要な場合は、UNICODE マクロを定義して、Windows ヘッダーに任せてください。

于 2012-08-09T13:41:40.543 に答える
0

これを見つけてよかったです。私は答えを探していましたが、Googleなどで正しく見つけるのはかなり難しいようです。特定のプログラムについて報告された同様の問題を見つけ、常に「何らかのプラグイン」を非難しました。

WndProc の問題は、CreateWindowEx や RegisterClassEx への呼び出しに近いところにないため、これは腹立たしいことです。

ところで、-W サフィックスを明示的に使用します。これは、いずれかの方法でビルドされたプログラムで動作する 1 つの DLL を作成するか、追加するプログラムの非 Unicode 設定を克服したいためです。

于 2012-08-30T05:26:33.893 に答える
0

あなたの最後のケースでは、L"Sample" はまだ Unicode のままですよね? プロジェクトの Unuicode 設定に応じて、L プレフィックスを自動的に追加または削除する _T() マクロを使用できます。

そして、@Pete が既に述べたように、Unicode L"Sample" は ascii では "S\0..." であるため、シンボルが 1 つだけ出力されます。

于 2012-08-09T13:06:03.993 に答える