Регистрация класса окна в Win32API - PullRequest
1 голос
/ 19 марта 2012

Несмотря на чтение большого количества информации в Интернете, наряду с книгой Петцольда, Программирование Windows API , и, черт возьми, почти копирование точно такой же методологии из книги, наряду с это документация о том, как инициализировать контекст OpenGL, я не смог запустить и запустить Window Class.

Я попытался скомпилировать как VC ++, так и MinGW (я использую Qt Creator), чтобы посмотреть, сработает ли это. Я попытался сделать мой WNDCLASSEXA указатель, а также разместить его в стеке. Никаких кубиков для обоих.

Таким образом, я совершенно не уверен, что с этим делать. Иногда класс просто не регистрируется, тогда как в другое время HWND, который возвращается из CreateWindowExA, просто не работает и возвращает NULL. После попытки просто продолжить программу, несмотря на происходящие инциденты, я получаю приложение, которое не может нарисовать окно.

Идея проста: у меня есть структура, которую я использую для простого хранения всех используемых данных (DEVMODEA, WNDCLASSEXA, HGLRC и т. Д.).

Оттуда я использую эту структуру для создания окна, а затем передаю его вызывающей функции.

Все, что я действительно хочу сделать, это написать простую игру, похожую на понг, в OpenGL, используя GLSL / OpenGL 3.3. Для этого мне, очевидно, сначала нужен контекст, но я не могу понять, является ли проблема Qt Creator, Windows или чем-то еще.

Итак, что я могу делать не так?

GameData Структура

typedef struct
{
    HGLRC        hrc;
    HDC          hdc;
    HWND         hwnd;
    HINSTANCE    hInstance;
    UINT         numFormats;
    WNDCLASSEXA* winClass;
    DWORD        dwExStyle;
    DWORD        dwStyle;
    RECT         winRect;
    DEVMODEA     screenSettings;

    bool         fullscreen;
    const char*  winClassName;
    int          pixelFormat;
    bool         keys[ 256 ];
    bool         active;
}
GameData;

initPong() функция

static GameData* initContextAndWindow( void )
{
    GameData* dat = new GameData;

    const int width     = 640;
    const int height    = 480;
    const int bitsPerPixel = 32;

    dat->winRect.left   = ( long )0;
    dat->winRect.right  = ( long )width;
    dat->winRect.top    = ( long )0;
    dat->winRect.bottom = ( long )height;

    dat->fullscreen     = false;

    dat->hInstance              = GetModuleHandleA( NULL );

    dat->winClass = ( WNDCLASSEXA* )calloc( sizeof( WNDCLASSEXA ), 1 );

    if( !dat->winClass )
        MessageBoxA( NULL, "Something wrong!", "ERROR", MB_OK | MB_ICONINFORMATION );

    dat->winClass->style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    dat->winClass->lpfnWndProc   = ( WNDPROC ) eventHandler;
    dat->winClass->cbClsExtra    = 1;
    dat->winClass->cbWndExtra    = 1;
    dat->winClass->cbSize        = sizeof( WNDCLASSEXA );
    dat->winClass->hInstance     = dat->hInstance;
    dat->winClass->hIcon         = LoadIcon( NULL, IDI_WINLOGO );
    dat->winClass->hCursor       = LoadCursor( NULL, IDC_ARROW );
    dat->winClass->hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH );
    dat->winClass->lpszMenuName  = NULL;
    dat->winClass->lpszClassName = "PongDH";

    if ( !RegisterClassExA( dat->winClass ) )
    {
        MessageBoxA( NULL, "Failed to register class.", "ERROR", MB_OK | MB_ICONINFORMATION );
        exit( 1 );
    }

    if ( dat->fullscreen )
    {
        memset( &dat->screenSettings, 0, sizeof( dat->screenSettings ) );

        dat->screenSettings.dmSize          = sizeof( dat->screenSettings );
        dat->screenSettings.dmPelsWidth     = width;
        dat->screenSettings.dmPelsHeight    = height;
        dat->screenSettings.dmBitsPerPel    = bitsPerPixel;
        dat->screenSettings.dmFields        = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        if ( ChangeDisplaySettingsA( &dat->screenSettings, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
        {
            dat->fullscreen = false;



            const int continuePlaying = MessageBoxA(
                NULL,
                "Could not implement fullscreen. Please check your drivers. Do you plan to continue?",
                "ERROR",
                MB_YESNO | MB_ICONEXCLAMATION
            );

            if ( continuePlaying == IDYES )
            {
                MessageBoxA( NULL, "Will revert back to fullscreen.", "Notifcation", MB_OK );
                dat->fullscreen = false;
            }
            else
            {
                MessageBoxA( NULL, "The program will now close", "Notification", MB_OK );
                exit( 1 );
            }
        }

    }

    if ( dat->fullscreen )
    {
        dat->dwExStyle = WS_EX_APPWINDOW;
        dat->dwStyle = WS_POPUP;
        ShowCursor( FALSE );
    }
    else
    {
        dat->dwExStyle  = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        dat->dwStyle    = WS_OVERLAPPEDWINDOW;
    }

    AdjustWindowRectEx( &dat->winRect, dat->dwStyle, FALSE, dat->dwExStyle );

    dat->hwnd = CreateWindowExA(
                    dat->dwStyle,
                    dat->winClass->lpszClassName,
                    "PongDH",
                    WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    dat->winRect.right,
                    dat->winRect.bottom,
                    NULL,
                    NULL,
                    dat->hInstance,
                    NULL
                );


    if ( dat->hwnd == NULL )
    {
        MessageBoxA( NULL, "Failed to create window; exiting program.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
        exit( 1 );
    }

    const int attrList[] =
    {
        WGL_DRAW_TO_WINDOW_ARB  , GL_TRUE,
        WGL_SUPPORT_OPENGL_ARB  , GL_TRUE,
        WGL_DOUBLE_BUFFER_ARB   , GL_TRUE,
        WGL_PIXEL_TYPE_ARB      , WGL_TYPE_RGBA_ARB,
        WGL_COLOR_BITS_ARB      , 32,
        WGL_DEPTH_BITS_ARB      , 24,
        WGL_STENCIL_BITS_ARB    , 8,
        0,
    };

    wglChoosePixelFormatARB( dat->hdc, attrList, NULL, 1, &dat->pixelFormat, &dat->numFormats );

    const int contextList[] =
    {
        WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
        WGL_CONTEXT_MINOR_VERSION_ARB, 3,
        0,
    };

    dat->hrc = wglCreateContextAttribsARB( dat->hdc, NULL, contextList );

    if( !wglMakeCurrent( dat->hdc, dat->hrc ) )
    {
        MessageBoxA( NULL, "Error making OpenGL Rendering Context current.", "ERROR", MB_OK | MB_ICONEXCLAMATION );
        exit( 1 );
    }

    ShowWindow( dat->hwnd, SW_SHOW );
    SetForegroundWindow( dat->hwnd );
    SetFocus( dat->hwnd );
    resizeScene( width, height );

    UpdateWindow( dat->hwnd );

    glEnable( GL_DEPTH_TEST );

    return dat;
}

Обновление

Здесь я опубликую процедуру того, что я сделал:

Сначала я попытался установить cbClsExtra на 1, тогда как раньше было 0. Затем я установил cbWndExtra на 1. После этого я попытался установить cbSize на sizeof( WNDCLASSEXA ).

Я также пытался компилировать под VC ++ и MinGW; в VC ++ класс просто не регистрируется, где, как и в MinGW, класс будет регистрироваться, но на самом деле он не создаст требуемый hwnd.

Я также попытался отредактировать мой код, сделав WNDCLASSEXA (что является dat->winClass) указателем, в отличие от переменной, выделенной в стеке.

Я также закомментировал свои exit функции в моих if проверках, чтобы увидеть, регистрируется ли класс * , или hwnd не создано. Это приводит к ошибке сегментации при попытке визуализации контекста OpenGL с wglChoosePixelFormatARB.

Обновление 2

Вот мой WndProc:

LRESULT CALLBACK eventHandler( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    return DefWindowProcA( hwnd, uMsg, wParam, lParam );
}

1 Ответ

1 голос
/ 19 марта 2012

Мне не удалось запустить и запустить Window Class.

Там действительно не так много для регистрации и создания окна с использованием WinAPI.

В качестве примера этот простой test.cpp файл:

#define STRICT
#include <windows.h>

long PASCAL WndProc (HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpszCmdParam, int nCmdShow)
{
   static char szClassName[] = "Hello World";
   MSG         msg;
   WNDCLASS    wndclass;

   memset(&wndclass, '\0', sizeof(wndclass));

   if (!hPrevInstance) {
      // define the 'Hello World' window class
      wndclass.style          = CS_HREDRAW|CS_VREDRAW;
      wndclass.lpfnWndProc    = WndProc;
      wndclass.cbClsExtra     = 0;
      wndclass.cbWndExtra     = 0;
      wndclass.hInstance      = hInstance;
      wndclass.hIcon          = LoadIcon (NULL, IDI_APPLICATION);
      wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW);
      wndclass.hbrBackground  = (HBRUSH)GetStockObject (WHITE_BRUSH);
      wndclass.lpszMenuName   = 0;
      wndclass.lpszClassName  = szClassName;

      // register the 'Hello World' window class
      RegisterClass (&wndclass);
   }

   // create a new window that is a 'Hello World' window class
   HWND hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
                              szClassName,
                              "My Hello World Window",
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT,
                              CW_USEDEFAULT,
                              CW_USEDEFAULT,
                              CW_USEDEFAULT,
                              NULL,
                              NULL,
                              hInstance,
                              NULL);

   ShowWindow (hwnd, nCmdShow);

   while (GetMessage (&msg, NULL, 0, 0)) {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
   }

   return msg.wParam;
}

long APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
       case WM_DESTROY:
          PostQuitMessage (0);
          return 0;
    }

    return DefWindowProc (hwnd, message, wParam, lParam);
}

можно скомпилировать и связать из командной строки:

C:\TEMP>cl test.cpp user32.lib gdi32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj
user32.lib
gdi32.lib

и полученный test.exe может быть запущен, и появится окно:

C:\TEMP>test.exe
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...