Search code examples
winapicompiler-errorsdirectx-9obsolete

Is DirextX9 material no longer worthy material for learning win32 API programming?


I have been expanding my library (Physical library of these weird things called 'books'... I know... I know) and I'm reading Beginning DirectX 9.0 by Wendy Jones. As I have gone through some books in the past that are 'outdated' the logic behind them is actually the same, if not more important in the earlier versions (in my experience) of things like C++ books I have read. The issue I am having with this DirectX 9 book is, 10/10 practice codes, don't work, ever. Even the solutions found on here, and MSDN didn't work for me. (Identical problem).

So I was hoping if you could tell me before I go and purchase a book on DX11, if it might be something to do with my compiler/vs or the fact that vs is updated 2015, and this DX9 is obselete/DX11 standards have been introduced.

//Include the Windows header file that's needed for all Windows applications 
#include <Windows.h>


HINSTANCE hInst; // global handle to hold the application instance
HWND wndHandle; // global variable to hold the window handle

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);

//forward declerations
bool initWindow(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND, UINT WPARAM, LPARAM);

//This is winmain, the main etry point for Windows applications
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    //Initialize the window
    if (!initWindow(hInstance))
        return false;
    //main message loop: (See page 13, "Adding the Windows Code" - Chapter 2
    MSG msg;
    ZeroMemory(&msg, sizeof(msg));
    while (msg.message != WM_QUIT);
    {
        //Check the message queue
            while (GetMessage(&msg, wndHandle, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    }
    return(int)msg.wParam;
}


/****************************************************************************** 
* bool initWindow( HINSTANCE hInstance ) 
* initWindow registers the window class for the application, creates the window 
******************************************************************************/

bool initWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    //Fill in the WNDCLASSEX structure. THis describes how the window will look to the system
    wcex.cbSize = sizeof(WNDCLASSEX);                    // the size of the structure
    wcex.style = CS_HREDRAW | CS_VREDRAW;                // the class style
    wcex.lpfnWndProc = (WNDPROC)WndProc;                 // the window procedure callback
    wcex.cbClsExtra = 0;                                 // extra bytes to allocate for this calss
    wcex.cbWndExtra = 0;                                 // extra bytes to allocate for this instance
    wcex.hInstance = hInstance;                          // handle to the application
    wcex.hIcon = 0;                                      // icon to associate with the application
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);          // the default cursor
    wcex.lpszMenuName = NULL;                            // the resource name for the menu
    wcex.lpszClassName = NULL;                           // the class name being created
    wcex.hIconSm = 0;
    RegisterClassEx(&wcex);

    //Create the window
    wndHandle = CreateWindow(
        (LPCWSTR)"DirectXExample",              // the window class to use
        (LPCWSTR)"DirectXExample",              // the title bar text
        WS_OVERLAPPEDWINDOW,                    // the window style
        CW_USEDEFAULT,                          // the starting x coordinate
        CW_USEDEFAULT,                          // the starting y coordinate
        640,                                    //the pixel width of the window
        480,                                    //the pixel height of the window
        NULL,                                   // the parent window; NULL for desktop
        NULL,                                   // the menu for the application; NULL for none
        hInstance,                              // the handle to the apllication instance
        NULL);                                  // no values passed to the window

    //make sure that the window handle that is created is valid
    if (!wndHandle)
        return false;

    //Display the window on the screen
    ShowWindow(wndHandle, SW_SHOW);
    UpdateWindow(wndHandle);
    return true;
}

Solution

  • It's perfectly fine to keep using DirectX 9. But your implementation for getting a minimal host window up on the screen has some simple bugs. It also is doing some bad casts between ANSI and wide strings. Let's get you fixed:

    Remove the forward declaration of WinMain. This line, just remove it.

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);
    

    In the actual function body for WinMain, change the type for lpCmdLine from LPTSTR parameter to be just LPSTR.

    //This is winmain, the main etry point for Windows applications
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        //Initialize the window
        if (!initWindow(hInstance))
    

    Your declaration of WndProc is also incorrect. WndProc should be declared as follows:

    LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam);
    

    Once you fix the above declaration of WndProc, you can take out that bad cast operation in the WNDCLASS initialization. Change this:

    wcex.lpfnWndProc = (WNDPROC)WndProc;  // the window procedure callback
    

    To this:

    wcex.lpfnWndProc = WndProc;  // the window procedure callback
    

    You are missing a definition of WndProc. You need to implement that function yourself. Here's a minimal implementation:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    
    }
    

    The above will get your code to compile, but it will still have some bugs and won't actually run like it should. Let's fix those.

    First, your message pump has an extra ; that is preventing it from actually running and keeping your code in an infinite loop. This line:

    while (msg.message != WM_QUIT);
    

    Should be (without the semicolon):

    while (msg.message != WM_QUIT)
    

    And while I'm here, your message pump implementation is kind of weird. GetMessage only returns FALSE when msg.message==WM_QUIT So the outer loop is not needed. Change this:

    while (msg.message != WM_QUIT)
    {
        //Check the message queue
            while (GetMessage(&msg, wndHandle, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    }
    

    to be this:

    //Check the message queue until WM_QUIT is received
    while (GetMessage(&msg, wndHandle, 0, 0))
    {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
    }
    

    When you actually implement your graphics loop for your DX app, you can change the GetMessage call to PeekMessage and then explicitly check for WM_QUIT then.

    Your initWindow is failing for many reasons.

    You are leaving some garbage values in the WNDCLASSEX variable. Change this line:

     WNDCLASSEX wcex;
    

    To be this:

    WNDCLASSEX wcex = {};
    

    You are forgetting to set wcex.lpszClassName. Make it this:

     wcex.lpszClassName = L"DirectXExample";
    

    And then your casting of ANSI strings to (LPCWSTR) is incorrect. To make it easier, here's a fixed version of your initWindow function.

    bool initWindow(HINSTANCE hInstance)
    {
        WNDCLASSEX wcex = {};
    
        //Fill in the WNDCLASSEX structure. THis describes how the window will look to the system
        wcex.cbSize = sizeof(WNDCLASSEX);                    // the size of the structure
        wcex.style = CS_HREDRAW | CS_VREDRAW;                // the class style
        wcex.lpfnWndProc = (WNDPROC)WndProc;                 // the window procedure callback
        wcex.cbClsExtra = 0;                                 // extra bytes to allocate for this calss
        wcex.cbWndExtra = 0;                                 // extra bytes to allocate for this instance
        wcex.hInstance = hInstance;                          // handle to the application
        wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);                                      // icon to associate with the application
        wcex.hCursor = LoadCursor(NULL, IDC_ARROW);          // the default cursor
        wcex.lpszMenuName = NULL;                            // the resource name for the menu
        wcex.lpszClassName = L"DirectXExample";                           // the class name being created
        wcex.hIconSm = 0;
        RegisterClassEx(&wcex);
    
        //Create the window
        wndHandle = CreateWindow(
            L"DirectXExample",              // the window class to use
            L"DirectXExample",              // the title bar text
            WS_OVERLAPPEDWINDOW,                    // the window style
            CW_USEDEFAULT,                          // the starting x coordinate
            CW_USEDEFAULT,                          // the starting y coordinate
            640,                                    //the pixel width of the window
            480,                                    //the pixel height of the window
            NULL,                                   // the parent window; NULL for desktop
            NULL,                                   // the menu for the application; NULL for none
            hInstance,                              // the handle to the apllication instance
            NULL);                                  // no values passed to the window
    
                                                    //make sure that the window handle that is created is valid
        if (!wndHandle)
            return false;
    
        //Display the window on the screen
        ShowWindow(wndHandle, SW_SHOW);
        UpdateWindow(wndHandle);
        return true;
    }
    

    And that should do it.