c ++ - Registrering af en vinduesklasse i Win32API

Indlæg af Hanne Mølgaard Plasc

Problem



På trods af at du læser masser af informationer på internettet sammen med Petzolds bog, Programmering af Windows API og forbandelse nær at kopiere den samme metode ud af bogen sammen med denne dokumentation om, hvordan du initialiserer en OpenGL kontekst, har jeg ikke været i stand til at få en løbende Window Class. [26]


Jeg har forsøgt at kompilere på både VC ++ og MinGW (jeg bruger mt Qt Creator) for at se om dette ville fungere. Jeg har forsøgt at gøre min WNDCLASSEXA en pointer, samt at allokere den på stakken. Ingen terninger til begge.


Således er jeg helt usikker på hvad jeg skal gøre ved dette. Nogle gange kan klassen simpelthen ikke registrere, hvor som andre gange HWND, der returneres fra CreateWindowExA, simpelthen ikke virker og returnerer NULL. Efter at have forsøgt at fortsætte programmet, på trods af disse hændelser sker jeg med et program, der ikke tegner et vindue.


Ideen er enkel: Jeg har en struktur, som jeg bruger til at gemme alle de anvendte data (DEVMODEA, WNDCLASSEXA, HGLRC osv.).


Derefter bruger jeg denne struktur til at oprette et vindue og derefter sende det tilbage til funktionens opkalder.


Alt jeg virkelig vil gøre er at skrive et simpelt pong-lignende spil i OpenGL ved hjælp af GLSL/OpenGL 3.3. For at gøre det har jeg naturligvis brug for en sammenhæng først, men jeg kan ikke se om problemet er Qt Creator, Windows eller noget andet.


Så hvad kunne jeg gøre forkert?


GameData Struktur


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() funktion


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


Opdater


Her posterer jeg proceduren for det, jeg gjorde:


Jeg forsøgte først at sætte cbClsExtra til 1, mens før den var 0. Så satte jeg cbWndExtra til 1. Derefter forsøgte jeg at sætte cbSize til sizeof( WNDCLASSEXA ).


Jeg har også forsøgt at kompilere under både VC ++ og MinGW; I VC ++ registrerer klassen simpelthen, hvor som i MinGW, vil klassen registrere, men det vil ikke skabe den nødvendige hwnd.


Jeg har også forsøgt at redigere min kode ved at gøre WNDCLASSEXA (som er dat->winClass) en pointer, i modsætning til en stabelfordelt variabel.


Jeg har også kommenteret mine exit funktioner i mine if kontroller for at se om klassen ikke 't registrerer, eller hvis hwnd isn 't oprettet. Dette giver en segmenteringsfejl, når man forsøger at gøre OpenGL-konteksten til wglChoosePixelFormatARB.


Opdater 2


Her er min WndProc:


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

Bedste reference



  

    Jeg har ikke været i stand til at få en løbende vinduesklasse.

  



Der er virkelig ikke meget at registrere og oprette et vindue ved hjælp af WinAPI.


Som et eksempel på denne simple test.cpp -fil:


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


kan kompileres og forbindes fra kommandolinjen:


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


og den resulterende test.exe kan køres, og den vil vise et vindue:


C:TEMP>test.exe