3

@EDIT: Windows 7 と VS 2012 でクラシック ビューと Aero ビューの両方を試してみたところ、Windows 8 RC の問題であることがわかりました。@Werner Henze と @Ven Boigt のフィードバックに感謝します

EDIT 2:これはベータ版であったため、Windows のバグであり、新しいリビジョンで修正されたので、もう心配する必要はありません。とにかくフィードバックをありがとう。

以前は、800*600 のクライアント領域のウィンドウを作成するために次のことを行っていました。

dwStyle = WS_OVERLAPPED | WS_THICKFRAME | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX;
hWindowHandle = CreateWindow(   L"CGFramework", wszWndCaption, 
                            pWindowData->dwStyle, pWindowData->nPositionX, pWindowData->nPositionY, 
                            800 + GetSystemMetrics( SM_CXSIZEFRAME )*2, 
                            600 + GetSystemMetrics( SM_CYSIZEFRAME ) *2
                            + GetSystemMetrics( SM_CYCAPTION ),
                            0, 0, hInstance, 0
                        ); 

その後、GetClientRect を使用してクライアント rect をクエリすると、以前は 800*600 を取得していましたが、Visual Studio 2008 プロジェクトを VS2012 にアップグレードしたところ、GetClientRect() 関数が代わりに 792*592 を返すようになりました。

その上、作成されるウィンドウの実際のサイズは 804*629 です。サイズ変更可能なフレーム (WS_THICKFRAME から) は明らかに両側で 2 ピクセルよりも大きいため、理由はわかりません。

これは Windows 8 の Aero 動作の問題だと思っていましたが、これは VS2012 ビルドでのみ発生し、VS2008 ビルドでは発生しないことに気付きました。Aero またはクラシック スタイルで実行しても違いはありません。動作は VS2012 ビルドにのみ適用されます。なんで?この恐ろしい動作を修正するために、VS2012 プロジェクト構成を変更できるものはありますか?

プロジェクト構成の「DPI認識」設定を変更してみましたが、違いはありません。また、同じ構成ページでマニフェストの使用を削除しましたが、結果のウィンドウにはまだ変化が見られません。

これは私のテストコードです:

#include <Windows.h>
#include <cstdio>

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uMsg )
    {
    // WM_DESTROY is sent when the window is being destroyed.
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nShowCmd )
{

    WNDCLASS wc;
    wc.style                = NULL; // CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc          = MainWndProc; 
    wc.cbClsExtra           = 0;
    wc.cbWndExtra           = 0;
    wc.hInstance            = hInstance;
    wc.hIcon                = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor              = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground        = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
    wc.lpszMenuName         = 0;
    wc.lpszClassName        = L"CGFramework";
    DWORD dwStyle   = WS_OVERLAPPED | WS_THICKFRAME | WS_BORDER | 
                                WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX; // WS_DLGFRAME | 
    if( !RegisterClass(&wc) )
    {
        MessageBox(0, L"RegisterClass FAILED", 0, 0);
        return E_FAIL;
    }

    RECT r;
    //r.left        = 100;
    //r.top     = 100;
    //r.right       = 800;
    //r.bottom  = 600;
    ////-----------------------------
    r.left      = 100;
    r.top       = 100;
    r.right     = 900;
    r.bottom    = 700;
    ////-----------------------------
    //r.left        = 100;
    //r.top     = 100;
    //r.right       = 800+GetSystemMetrics( SM_CXFRAME )*2;
    //r.bottom  = 600+GetSystemMetrics( SM_CYFRAME )*2+GetSystemMetrics( SM_CYCAPTION );

    BOOL result = AdjustWindowRect( &r, dwStyle, FALSE );

    HWND hWindowHandle = CreateWindow( L"CGFramework", L"testWindow", dwStyle,
                          r.left, r.top, r.right-r.left, r.bottom-r.top, 
                          // r.left, r.top, r.right, r.bottom, 
                          0, 0, hInstance, 0 );



    if( 0 == hWindowHandle )
    {
        MessageBox(0, L"CreateWindow FAILED", 0, 0);
        UnregisterClass( wc.lpszClassName, hInstance );
        return 0;
    }

    char buffer[512]; // for outing test message
    GetClientRect( hWindowHandle, &r );
    sprintf( &buffer[0], "left=%i, top=%i, right=%i, bottom=%i", r.left, r.top, r.right, r.bottom );
    MessageBoxA(0, buffer, 0, 0); // print rect values before ShowWindow

    ShowWindow( hWindowHandle, SW_SHOW );

    GetClientRect( hWindowHandle, &r );
    sprintf( &buffer[0], "left=%i, top=%i, right=%i, bottom=%i", r.left, r.top, r.right, r.bottom );
    MessageBoxA(0, buffer, 0, 0);  // print rect values after ShowWindow

    // main window loop
    MSG msg;
    ZeroMemory( &msg, sizeof( MSG ) );
    while( msg.message != WM_QUIT )
    {
        while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }

        if( GetAsyncKeyState( VK_ESCAPE ) )
            DestroyWindow( hWindowHandle );
    }
    UnregisterClass( wc.lpszClassName, hInstance );
    return 0;
}

回答する前にコードを注意深く見てください。私がすでに試したことに回答してしまう可能性があるためです (すべての選択肢を無駄にしたため、この質問を投稿しています)。

Windows 8 RC (MS Windows 6.2.8400) と VS2012 RC (11.0.50706.0 QRELRC July 2012) を使用してこの奇妙な動作を取得していますが、この問題に対処できる回答はありませんでした。このコードはさまざまな方法でテストされていますが、微妙な違いがあり、最終的には改善されませんでした。

4

3 に答える 3

6

このCreateWindow関数は Windows API の一部であり、Visual Studio では提供されず、Visual Studio のバージョンは影響しません。

最も可能性の高い説明は、VS2012 の既定のプロジェクト設定が、アプリケーションを Aero 対応または DPI 対応としてマークするマニフェストを追加し、そのマニフェストの存在が WinAPI 関数の動作を変更したことです。マニフェストを編集または削除して、古い動作にすることができます。

可能性は低いですが、Windows が PE ヘッダーの「最小 OS バージョン」フィールドをチェックしている可能性もあります。リンカーの新しいバージョンでは、通常、このフィールドに古いバージョンを書き込むためのサポートが削除されますが、editbinツールを使用してリンク後に変更できます。

于 2012-08-06T13:45:37.603 に答える
6

他の人が述べたように、AdjustWindowRectまたはAdjustWindowRectEx行く方法です。WS_VSCROLLまたはWS_HSCROLLが設定されている場合は、特別な処理を行う必要があります。私の util ライブラリでは、 の特別な処理も行ってWS_EX_STATICEDGEいますが、この情報をどこから入手したかは尋ねないでください (少なくとも、 の MSDN ドキュメントにはありませんAdjustWindowRect[Ex])。

最新のテストのバグは、間違った方法で呼び出しCreateWindowていることでした。右と下ではなく、幅と高さが必要です。これは必要に応じて機能するはずです。

dwStyle = WS_OVERLAPPED | WS_THICKFRAME | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX; 
RECT r; 
r.left      = 100; 
r.top       = 100; 
r.right     = 900; 
r.bottom    = 700; 
BOOL result = AdjustWindowRect( &r, dwStyle, FALSE ); 
hWindowHandle = CreateWindow( L"CGFramework", wszWndCaption, pWindowData->dwStyle,
                              pWindowData->nPositionX, pWindowData->nPositionY,  
                              r.left, r.top, r.right-r.left, r.bottom-r.top, 
                              0, 0, hInstance, 0 );

参考までに、完全なサンプルを次に示します。

#include "stdafx.h"

#include <Windows.h> 
#include <cstdio> 
#include <cassert>

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
    switch( uMsg ) 
    { 
    // WM_DESTROY is sent when the window is being destroyed. 
    case WM_DESTROY: 
        PostQuitMessage(0); 
        return 0; 
    default: 
        return DefWindowProc( hWnd, uMsg, wParam, lParam ); 
    } 
} 

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nShowCmd ) 
{ 

    WNDCLASS wc; 
    wc.style                = NULL; // CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc          = MainWndProc;  
    wc.cbClsExtra           = 0; 
    wc.cbWndExtra           = 0; 
    wc.hInstance            = hInstance; 
    wc.hIcon                = LoadIcon(0, IDI_APPLICATION); 
    wc.hCursor              = LoadCursor(0, IDC_ARROW); 
    wc.hbrBackground        = CreateSolidBrush(GetSysColor(COLOR_3DFACE)); 
    wc.lpszMenuName         = 0; 
    wc.lpszClassName        = L"CGFramework"; 
    DWORD dwStyle   = WS_OVERLAPPED | WS_THICKFRAME | WS_BORDER |  
                                WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX; 
    if( !RegisterClass(&wc) ) 
    { 
        MessageBox(0, L"RegisterClass FAILED", 0, 0); 
        return E_FAIL; 
    } 

    RECT r; 
    //r.left        = 100; 
    //r.top     = 100; 
    //r.right       = 800; 
    //r.bottom  = 600; 
    ////----------------------------- 
    r.left      = 100; 
    r.top       = 100; 
    r.right     = 900; 
    r.bottom    = 700; 
    ////----------------------------- 
    //r.left        = 100; 
    //r.top     = 100; 
    //r.right       = 800+GetSystemMetrics( SM_CXSIZEFRAME )*2; 
    //r.bottom  = 600+GetSystemMetrics( SM_CYSIZEFRAME )*2+GetSystemMetrics( SM_CYCAPTION ); 

    BOOL result = AdjustWindowRect( &r, dwStyle, FALSE ); 
    assert(result);
    char buffer[512]; 
    sprintf( &buffer[0], "adjust left=%i, top=%i, right=%i, bottom=%i", r.left, r.top, r.right, r.bottom ); 
    MessageBoxA(0, buffer, 0, 0); 

    HWND hWindowHandle = CreateWindow(  L"CGFramework", L"Window Test", dwStyle, r.left, r.top, r.right-r.left, r.bottom-r.top, 0, 0, hInstance, 0 );  

    if( 0 == hWindowHandle ) 
    { 
        MessageBox(0, L"CreateWindow FAILED", 0, 0); 
        UnregisterClass( wc.lpszClassName, hInstance ); 
        return 0; 
    } 

    assert(GetWindowRect(hWindowHandle, &r));
    sprintf( &buffer[0], "wnd left=%i, top=%i, right=%i, bottom=%i", r.left, r.top, r.right, r.bottom ); 
    MessageBoxA(0, buffer, 0, 0); 

    GetClientRect( hWindowHandle, &r ); 
    sprintf( &buffer[0], "style=%08x/%08x, exstyle=%08x, left=%i, top=%i, right=%i, bottom=%i", GetWindowLong(hWindowHandle, GWL_STYLE), dwStyle, GetWindowLong(hWindowHandle, GWL_EXSTYLE), r.left, r.top, r.right, r.bottom ); 
    MessageBoxA(0, buffer, 0, 0); 

    ShowWindow( hWindowHandle, SW_SHOW ); 

    GetClientRect( hWindowHandle, &r ); 
    sprintf( &buffer[0], "left=%i, top=%i, right=%i, bottom=%i", r.left, r.top, r.right, r.bottom ); 
    MessageBoxA(0, buffer, 0, 0); 

    MSG msg; 
    ZeroMemory( &msg, sizeof( MSG ) ); 
    while( msg.message != WM_QUIT ) 
    { 
        while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) 
        { 
            TranslateMessage( &msg ); 
            DispatchMessage( &msg ); 
        } 

        if( GetAsyncKeyState( VK_ESCAPE ) ) 
            DestroyWindow( hWindowHandle ); 
    } 

    UnregisterClass( wc.lpszClassName, hInstance ); 
    return 0; 
} 
于 2012-08-13T11:47:56.540 に答える
3

使用してみてAdjustWindowRectEx、スタイルと拡張スタイルがウィンドウが使用する最終的なスタイルと正確に一致することを確認してください。たとえば、 の後CreateWindowで追加のスタイルを設定する場合、ライブラリによって自動的に行われたとしても、 に対応するスタイルも設定する必要がありますAdjustWindowRectEx。作成後にスタイルを取得して、Windows または一部のライブラリがスタイルを追加したかどうかを確認することができます。

スクロールバーを使用する場合は、それも考慮する必要があります。

于 2012-08-13T14:08:54.533 に答える