DirectX using the “Windows” style form, not XAML kind of form

I have been staring at the DirectX Quickstart “Direct2D Quickstart for Windows 8” for the past year from time to time and just have to put myself in the shoes of the hobbyist or student trying to figure out windows.  The initial example seems like it might work in the DirectX Templates, but where in the template do I put it?  Umm?

Ha-ha, I got tricked!  Those silly C++ Quickstart writers, they got me, really, just did not see how the QuickStart that seemed like it was for XAML/C++/DirectX was suppose to be used with the “Windows” style form creation.  That is because I misunderstood the title “Direct2D Quickstart for Windows 8”, I thought that the writer was referring to the XAML/C++ or just C++ and DirectX, I would be wrong, wrong, wrong. 

See in the header: Drawing a Simple Rectangle, the code given is suppose to be used in a WINDOW, not a XAML based page.  This should have been clear to me because there was a reference to the Windows::UI::Core::CoreWindow.  Really should have been clear to me or any new comer that they would have to include the “QuickStart” code in my Visual Studio effort.  This was just silly of me.  Or that I could just drop the code into a Win32 app and have it work, nope did either.

Then it dawned on me while I was reading Programming 2D Games by Charles Kelly, an excellent book, even if it does use VS 2010, it’s examples still run nicely in VS 2013!  That made me think about the Win32 Templates, which I have been avoiding for the past 12 years.  Sad.  But it came to me how to get that example working, and that example in the “Direct2D Quickstart for Windows 8”, had been bugging me for over a year.  I went back to it and got it to work finally.

It’s easy, thanks to one of Charles Kelly’s example (and if you got a spare $42 or so bucks, please buy his book, especially if you want to get started with DirectX):

Download the project from: https://www.programming2dgames.com/chapter2/CharacterInput.zip, go ahead unzip it and then open it with VS2013, accept the dialog boxes about the conversion, run it, you will see a black “Old style” window, when you press your keyboard you will see a small box that shows the single character.image

You can either simply copy and paste this code over the exisitng code or just make the two simple changes shown in comments, once you get this working then you are at the point where you can work with the “Direct2D Quickstart for Windows 8”.  I know that if I was a new person to Microsoft Windows, DirectX/C++ and XAML, I should have seen that this was EXACTLY what I should do.  Also, if you try this with the Win32 template it won’t work, and I don’t have time to troubleshoot this.  Also, this code yields a really ugly rectangle that you can’t control.  It will look like the image on the right, this is by strict definition a Windows drawn using DirectX and you are now a DirectX programmer.  Great right?

Explanation of code etc. is provided by Charle Kelly in his book, and since I copied enough of his IP here, so just buy his book.  You can get it at CRC Press (make sure to get a coupon for the paper book, but no way to get a discount on the ebook) at: https://www.crcpress.com/product/isbn/9781466508682

And thank you Charles for this well written book!

First download the following: https://www.programming2dgames.com/chapter2/CharacterInput.zip

Then unzip and open the file into VS 2013, in winmain.cpp paste the following code  over the existing code:

/*Added these two #includes or it doesn't work
  Just paste them in, you do not have to load
  DirectX this added automatically with the
  Windows SDK ********************************/
#include <d2d1.h>
#include <d2d1_1.h>
/*******End Of Paste***************************/
// Function prototypes
bool CreateMainWindow(HINSTANCE, int);
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);

// Global variables
HINSTANCE hinst;
HDC    hdc;                 // Device context handle
RECT rect;                  // rectangle struct
PAINTSTRUCT ps;             // WM_PAINT variable

// Constants
const char CLASS_NAME[]  = "Keyboard";
const char APP_TITLE[]   = "Character Input";
const int  WINDOW_WIDTH  = 700;     // width of window
const int  WINDOW_HEIGHT = 300;     // height of window

/*******************************************************************
* Windows application starting point
*******************************************************************/
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                    LPSTR     lpCmdLine,
                   int       nCmdShow)
{
    MSG  msg;

    // Window Creation
    if (!CreateMainWindow(hInstance, nCmdShow))
        return false;

    // main msg loop
    int done = 0;
    while (!done)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            //look for quit message
            if (msg.message == WM_QUIT)
                done = 1;

            //After decoding, pass the messages to WinProc
            TranslateMessage(&msg);
             DispatchMessage(&msg);
        }
    }

    return msg.wParam;
}

/*******************************************************
* Window event callback function
*******************************************************/
LRESULT WINAPI WinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{

    switch( msg )
    {
         case WM_DESTROY:
            //tell Windows to kill this program
            PostQuitMessage(0);
            return 0;  

        /**************************************************************************
        * This is the starting point where I pasted the code OVER the
        * Char Input Code
        * From https://msdn.microsoft.com/en-us/library/windows/apps/hh780340.aspx
        * Into Charles Kelly's code from, but buy his book!
        * https://www.programming2dgames.com/chapter2/CharacterInput.zip
        * Unzip the file and open it with VS2013, it works just fine
        **************************************************************************/
        case WM_PAINT:              // the window needs to be redrawn
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &ps);

            // Obtain the size of the drawing area.
            RECT rc;
            GetClientRect(
                hwnd,
                & rc
                 );

            // Save the original object
            HGDIOBJ original = NULL;
            original = SelectObject(
                 ps.hdc,
                GetStockObject(DC_BRUSH)
                 );

            // Create a pen.           
             HPEN blackPen = CreatePen(PS_SOLID, 10, 255);

            // Select the pen.
            SelectObject(ps.hdc, blackPen);

            // Draw a rectangle.
            Rectangle(
                 ps.hdc,
                rc.left + 100,
                rc.top + 100,
                rc.right - 100,
                rc.bottom - 100);

            DeleteObject(blackPen);

            // Restore the original object
            SelectObject(ps.hdc, original);

            EndPaint(hwnd, &ps);
            /************ End of Paste *****************************/
            return 0;
    }
}

/*******************************************************
* Create the window
* Returns: false on error
*******************************************************/
bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
    WNDCLASSEX wcx;
     HWND hwnd;
 
    /*    Window class structure and parameters
        These describe the main window.        */
    wcx.cbSize = sizeof(wcx);           // structure size
    wcx.style = CS_HREDRAW | CS_VREDRAW;    // size changes causes redraw
    wcx.lpfnWndProc = WinProc;          // points to Window procedure
     wcx.cbClsExtra = 0;                 // no extra class memory
    wcx.cbWndExtra = 0;                 // no extra window memory
    wcx.hInstance = hInstance;          // handle to instance
    wcx.hIcon = NULL;
    wcx.hCursor = LoadCursor(NULL,IDC_ARROW);   // predefined arrow
    wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);    // black background brush
    wcx.lpszMenuName =  NULL;           // name of menu resource
    wcx.lpszClassName = CLASS_NAME;        // name of window class
    wcx.hIconSm = NULL;                 // small class icon
 
     // Register the window class.
    // RegisterClassEx returns 0 on error.
    if (RegisterClassEx(&wcx) == 0)    // if error
        return false;

    // Create window
    hwnd = CreateWindow(
        CLASS_NAME,             // name of the window class
        APP_TITLE,              // title bar text
        WS_OVERLAPPEDWINDOW,    // window style
        CW_USEDEFAULT,          // default horizontal position of window
        CW_USEDEFAULT,          // default vertical position of window
        WINDOW_WIDTH,           // width of window
        WINDOW_HEIGHT,          // height of the window
        (HWND) NULL,            // no parent window
        (HMENU) NULL,           // no menu
         hInstance,              // handle to application instance
         (LPVOID) NULL);         // no window parameters

    // if there was an error creating the window
    if (!hwnd)
        return false;

    // Show the window
    ShowWindow(hwnd, nCmdShow);

    // Send a WM_PAINT message to the window procedure
    UpdateWindow(hwnd);
    return true;
}