while implementing dwrite to draw a glyph of a font in c++ leads to nullptr error

373 Views Asked by At

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).

0

There are 0 best solutions below