0

I have been taking reference for my project from this source: https://learn.microsoft.com/en-us/windows/win32/directwrite/getting-started-with-directwrite

My goal is very simple: Follow the guidance in the link given below and somehow get the output that the link finally gets. I would have been glad if I at least got the intermediate output.

However, unfortunately my project always seems to compile with a nullptr error, and these are my findings so far. I'm working in an area out of my expertise and I was only able to find the following:

  1. I am not sure if I have created the SimpleText class according to what has been given in the link
  2. I am probably not linking the window handler correctly to the Simple Text class object

Here is my code(it seems big, but it is only just class definition + basic window creation, honestly nothing else at all)

// cvvvv.cpp : Defines the entry point for the application.
//

#include "framework.h"
#include "cvvvv.h"

#include<dwrite.h>
#include<d2d1.h>

#include<iostream>
#include<fstream>

#include<stdio.h>

using namespace std;

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

// *********************************************************************************


//HRESULT HasCharacter(
//  UINT32 unicodeValue,
//  BOOL* exists
//);

long const uniLast = 1114111;
//UINT32 codePoints[uniLast];
//UINT32 codePointsCount = uniLast;
//UINT16 glyphIndices[uniLast];


long long SairamAll;
// https://learn.microsoft.com/en-us/windows/win32/directwrite/getting-started-with-directwrite //

///// Part 1: Declare DirectWrite and Direct2D Resources. /////

// 1. In your class header file(SimpleText.h), declare pointers to IDWriteFactoryand IDWriteTextFormat interfaces as private members.
//IDWriteFactory* pDWriteFactory_;
//IDWriteTextFormat* pTextFormat_;


// 3. Declare pointers to ID2D1Factory, ID2D1HwndRenderTarget, and ID2D1SolidColorBrush interfaces for rendering the text with Direct2D.

//ID2D1Factory* pD2DFactory_;
//ID2D1HwndRenderTarget* pRT_;
//ID2D1SolidColorBrush* pBlackBrush_;

///// Part 2: Create Device Independent Resources. /////
template <class T> void SafeRelease(T** ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}

class SimpleText {
private:
    // 2. Declare members to hold the text string to render and the length of the string.
    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
    const wchar_t* wszText_;

    UINT32 cTextLength_;
    ID2D1Factory* pD2DFactory_;

    ID2D1HwndRenderTarget* pRT_;
    ID2D1SolidColorBrush* pBlackBrush_;

    HRESULT hr;
    RECT rc;
    HWND hwnd_;

    float dpiScaleX_, dpiScaleY_;

public:
    SimpleText() {
        hr = CreateDeviceResources();

        if (SUCCEEDED(hr))
        {
            pRT_->BeginDraw();

            pRT_->SetTransform(D2D1::IdentityMatrix());

            pRT_->Clear(D2D1::ColorF(D2D1::ColorF::White));

            // Call the DrawText method of this class.
            hr = DrawText();

            if (SUCCEEDED(hr))
            {
                hr = pRT_->EndDraw(
                );
            }
        }

        if (FAILED(hr))
        {
            DiscardDeviceResources();
        }
    }
    void CreateDeviceIndependentResources() {

        hr = D2D1CreateFactory(
            D2D1_FACTORY_TYPE_SINGLE_THREADED,
            &pD2DFactory_);

        if (SUCCEEDED(hr))
        {
            hr = DWriteCreateFactory(
                DWRITE_FACTORY_TYPE_SHARED,
                __uuidof(IDWriteFactory),
                reinterpret_cast<IUnknown**>(&pDWriteFactory_)
            );
        }

        wszText_ = L"Hello World using  DirectWrite!";
        cTextLength_ = (UINT32)wcslen(wszText_);

        if (SUCCEEDED(hr))
        {
            hr = pDWriteFactory_->CreateTextFormat(
                L"Gabriola",                // Font family name.
                NULL,                       // Font collection (NULL sets it to use the system font collection).
                DWRITE_FONT_WEIGHT_REGULAR,
                DWRITE_FONT_STYLE_NORMAL,
                DWRITE_FONT_STRETCH_NORMAL,
                72.0f,
                L"en-us",
                &pTextFormat_
            );
        }
        // Center align (horizontally) the text.
        if (SUCCEEDED(hr))
        {
            hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
        }

        if (SUCCEEDED(hr))
        {
            hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
        }
    }

    HRESULT CreateDeviceResources() {
        GetClientRect(hwnd_, &rc);

        D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

        if (!pRT_)
        {
            // Create a Direct2D render target.
            hr = pD2DFactory_->CreateHwndRenderTarget(
                D2D1::RenderTargetProperties(),
                D2D1::HwndRenderTargetProperties(
                    hwnd_,
                    size
                ),
                &pRT_
            );

            // Create a black brush.
            if (SUCCEEDED(hr))
            {
                hr = pRT_->CreateSolidColorBrush(
                    D2D1::ColorF(D2D1::ColorF::Black),
                    &pBlackBrush_
                );
            }
        }
        return hr;
    }

    void DiscardDeviceResources() {
        SafeRelease(&pRT_);
        SafeRelease(&pBlackBrush_);
    }


    HRESULT DrawText() {
        D2D1_RECT_F layoutRect = D2D1::RectF(
            static_cast<FLOAT>(rc.left) / dpiScaleX_,
            static_cast<FLOAT>(rc.top) / dpiScaleY_,
            static_cast<FLOAT>(rc.right - rc.left) / dpiScaleX_,
            static_cast<FLOAT>(rc.bottom - rc.top) / dpiScaleY_
        );


        pRT_->DrawText(
            wszText_,        // The string to render.
            cTextLength_,    // The string's length.
            pTextFormat_,    // The text format.
            layoutRect,       // The region of the window where the text will be rendered.
            pBlackBrush_     // The brush used to draw the text.
        );
        return hr;
    }
};


// *********************************************************************************


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_CVVVV, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CVVVV));

    MSG msg;

    SimpleText s;
    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CVVVV));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_CVVVV);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

I am sorry if I am asking for too much. But I am honestly stuck, and very surprisingly, I was not able to find this implemented anywhere on the net(hope I did not miss something that was obviously there).

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
  • Have you tried debugging? – Alan Birtles Sep 07 '20 at 06:22
  • Yes my friend, I think im missing some fundamental understanding, which i dont know what, as im unable to push furhter :( – Vrishin Vigneshwar Sep 07 '20 at 06:24
  • When you debugged where did the null pointer error happen? – Alan Birtles Sep 07 '20 at 06:25
  • Crom, that's a lot of code. I recommend narrowing down the source of the error by playing a few rounds of divide and conquer. Quite often this reveals the bug by giving it less space to hide. Use [mre] as inspiration. – user4581301 Sep 07 '20 at 06:25
  • 1
    @VrishinVigneshwar -- Did you use the debugger, not just look at the code for mistakes? If not, please use it. There is no way you or anyone else (even a professional) would write the code you have now, and not have the debugger available to them. – PaulMcKenzie Sep 07 '20 at 06:34
  • 1
    When people are asking for debugger information, what they are asking you to do is star the program in whatever debugger comes with your development system and let it run until it crashes. The debugger will halt and allow you to inspect the crash site. This usually isn't where the actual bug is, but it give you information that you can use to determine what was null and armed with that information you can backtrack to where it became null, or if it was ever set to a useful object in the first place. – user4581301 Sep 07 '20 at 06:42
  • Thanks to all of you! All of you have suggested me to use the debugger properly. I shall take your advise and try once again to find the problem :) Thank you – Vrishin Vigneshwar Sep 07 '20 at 08:19

0 Answers0