locked
Direct2D 'Factory is nullprt'. RRS feed

  • Question

  • Hey everyone! I'm having trouble using Direct2D. I was following this tutorial from the MSDN, and when I test the application I get a exception thrown saying 'Factory is nullptr'. Here's what I wrote in order to create the factory, it's split into two parts:

    Firstly, I have a header with a function in my header, which is inside one of various structures,containing functions, which I use to simplify tools in the Window SDK:

    HRESULT Create_Factory(ID2D1Factory *Factory, D2D1_FACTORY_TYPE FactoryType)
    			{
    				Factory = NULL;
    
    				HRESULT HR = D2D1CreateFactory
    				(
    					FactoryType,
    					&Factory
    				);
    				return HR;
    			}

    When I needed to use this function, I used it as so:

    struct Graphics
    {
    	ID2D1Factory* Factory = NULL;
    	ID2D1DCRenderTarget* RenderTarget = NULL;
    	IDWriteTextFormat* TextFormat = NULL;
    }Graphics;	
    
    		PWED.DX2D.Setup.Create_Factory(Graphics.Factory, D2D1_FACTORY_TYPE_SINGLE_THREADED);

    Other things I did to try and resolve the issue are:

    • Check the linking/including of the Libraries and headers.
    • Download another version of DirectX SDK and attempt a build with it linked instead.
    • Look through other tutorials and samples to see if there's a different method to use DirectX.

    Headers and Libraries that I currently use:

    1. 'd2d1.h' / 'd2d1.lib'
    2. 'd3d10.h' / 'd3d10.lib'
    3. 'd2d1_1helper.h'
    4. 'dwrite.h'

    When looking at other sources , I've noticed there is a different method to using DirectX but that is more focused on Window App Store Applications, so I don't want to change on to that. Especially since it uses 'DXGI' as I've heard of which I'm not confident in using at the moment. So what should I do to solve this issue?


    • Edited by Edwin Busuulwa Monday, October 30, 2017 9:10 PM Sentence Structure error
    Monday, October 30, 2017 9:07 PM

Answers

  • When looking at other sources , I've noticed there is a different method to using DirectX but that is more focused on Window App Store Applications, so I don't want to change on to that. Especially since it uses 'DXGI' as I've heard of which I'm not confident in using at the moment. So what should I do to solve this issue?

    This is mostly because it is easy enough to figure out how to do this for desktop applications, since you just have to call a different function on the same interface. So that method can be used for desktop applications too.

    Anyway, if you are passing nullptr into that Create_Factory function, then yes of course it would also pass out nullptr.

    You see, your function prototype is:

    HRESULT Create_Factory(ID2D1Factory *Factory, D2D1_FACTORY_TYPE FactoryType);

    This means that while you are passing the object by pointer/reference, the pointer itself is being passed by value and copied. So when you update it with the D2D1CreateFactory call, only the copy is updated and the original value in the function that you called this from will still be null. This is the reason why D2D1CreateFactory takes a ** itself.

    So if we create a console application to show this off:

    #include <Windows.h>
    #include <d2d1.h>
    #include <cstdio>
    
    #pragma comment(lib, "d2d1.lib")
    
    HRESULT Create_Factory(ID2D1Factory *Factory, D2D1_FACTORY_TYPE FactoryType)
    {
    	D2D1_FACTORY_OPTIONS fo{};
    #ifdef _DEBUG
    	fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    	Factory = nullptr;
    
    	HRESULT HR = D2D1CreateFactory(FactoryType, fo, &Factory);
    	return HR;
    }
    
    int wmain()
    {
    	ID2D1Factory *fact = nullptr;
    	HRESULT hr;
    
    	hr = Create_Factory(fact, D2D1_FACTORY_TYPE_SINGLE_THREADED);
    
    	//fact will still be nullptr here
    	wprintf(L"0x%08x\n", fact);
    	return 0;
    }

    This will output null at the wprintf line, however:

    #include <Windows.h>
    #include <d2d1.h>
    #include <cstdio>
    
    #pragma comment(lib, "d2d1.lib")
    
    HRESULT Create_Factory(ID2D1Factory **Factory, D2D1_FACTORY_TYPE FactoryType) //notice ID2D1Factory **
    {
    	D2D1_FACTORY_OPTIONS fo{};
    #ifdef _DEBUG
    	fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    	*Factory = nullptr; //notice, dereferenced because we want to initialise the ID2D1Factor *
    
    	HRESULT HR = D2D1CreateFactory(FactoryType, fo, &Factory);
    	return HR;
    }
    
    int wmain()
    {
    	ID2D1Factory *fact = nullptr;
    	HRESULT hr;
    
    	hr = Create_Factory(&fact, D2D1_FACTORY_TYPE_SINGLE_THREADED); //notice &fact
    
    	wprintf(L"0x%08x\n", fact);
    	return 0;
    }

    This will output a non null pointer at the wprintf line.

    This is because for the second program, you are passing in the factory pointer by pointer/reference, so Create_Factory is able to change the pointer in the calling function.

    I also mirror what Chuck mentioned. I only had the Windows 10 SDK installed for this. There was no old DirectX SDKs installed to get this to work at all. It is also true that Direct2D also has no issues working with Direct3D 11, so there is no reason to use the d3d10 headers.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Tuesday, October 31, 2017 7:38 PM
    • Marked as answer by Edwin Busuulwa Thursday, November 16, 2017 11:00 PM
    Tuesday, October 31, 2017 7:33 PM

All replies

  • What is the HRESULT that comes back from D2D1CreateFactory? You also need to call CoInitializeEx before you call the factory--this is done automatically for UWP apps, which is why it's not in the MSDN material.

    Don't use the legacy DirectX SDK. The Windows 8.x SDK and the Windows 10 SDK already include Direct2D, DirectWrite, DirectX 11, etc. headers and libraries. See Where is the DirectX SDK?

    Also, don't use the deprecated Direct3D 10 API. There's no reason at all to use it. Just use DirectX 11. You may want to take a look a the DirectX Tool Kit tutorials. I don't use DIrect2D/DirectWrite as I'm focused on Direct3D 11.

    If you are looking for examples of using Direct2D/DirectWrite from a Win32 desktop app, see these samples:

    https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/Direct2D

    https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/DirectWrite



    Tuesday, October 31, 2017 4:11 PM
  • When looking at other sources , I've noticed there is a different method to using DirectX but that is more focused on Window App Store Applications, so I don't want to change on to that. Especially since it uses 'DXGI' as I've heard of which I'm not confident in using at the moment. So what should I do to solve this issue?

    This is mostly because it is easy enough to figure out how to do this for desktop applications, since you just have to call a different function on the same interface. So that method can be used for desktop applications too.

    Anyway, if you are passing nullptr into that Create_Factory function, then yes of course it would also pass out nullptr.

    You see, your function prototype is:

    HRESULT Create_Factory(ID2D1Factory *Factory, D2D1_FACTORY_TYPE FactoryType);

    This means that while you are passing the object by pointer/reference, the pointer itself is being passed by value and copied. So when you update it with the D2D1CreateFactory call, only the copy is updated and the original value in the function that you called this from will still be null. This is the reason why D2D1CreateFactory takes a ** itself.

    So if we create a console application to show this off:

    #include <Windows.h>
    #include <d2d1.h>
    #include <cstdio>
    
    #pragma comment(lib, "d2d1.lib")
    
    HRESULT Create_Factory(ID2D1Factory *Factory, D2D1_FACTORY_TYPE FactoryType)
    {
    	D2D1_FACTORY_OPTIONS fo{};
    #ifdef _DEBUG
    	fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    	Factory = nullptr;
    
    	HRESULT HR = D2D1CreateFactory(FactoryType, fo, &Factory);
    	return HR;
    }
    
    int wmain()
    {
    	ID2D1Factory *fact = nullptr;
    	HRESULT hr;
    
    	hr = Create_Factory(fact, D2D1_FACTORY_TYPE_SINGLE_THREADED);
    
    	//fact will still be nullptr here
    	wprintf(L"0x%08x\n", fact);
    	return 0;
    }

    This will output null at the wprintf line, however:

    #include <Windows.h>
    #include <d2d1.h>
    #include <cstdio>
    
    #pragma comment(lib, "d2d1.lib")
    
    HRESULT Create_Factory(ID2D1Factory **Factory, D2D1_FACTORY_TYPE FactoryType) //notice ID2D1Factory **
    {
    	D2D1_FACTORY_OPTIONS fo{};
    #ifdef _DEBUG
    	fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    	*Factory = nullptr; //notice, dereferenced because we want to initialise the ID2D1Factor *
    
    	HRESULT HR = D2D1CreateFactory(FactoryType, fo, &Factory);
    	return HR;
    }
    
    int wmain()
    {
    	ID2D1Factory *fact = nullptr;
    	HRESULT hr;
    
    	hr = Create_Factory(&fact, D2D1_FACTORY_TYPE_SINGLE_THREADED); //notice &fact
    
    	wprintf(L"0x%08x\n", fact);
    	return 0;
    }

    This will output a non null pointer at the wprintf line.

    This is because for the second program, you are passing in the factory pointer by pointer/reference, so Create_Factory is able to change the pointer in the calling function.

    I also mirror what Chuck mentioned. I only had the Windows 10 SDK installed for this. There was no old DirectX SDKs installed to get this to work at all. It is also true that Direct2D also has no issues working with Direct3D 11, so there is no reason to use the d3d10 headers.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Tuesday, October 31, 2017 7:38 PM
    • Marked as answer by Edwin Busuulwa Thursday, November 16, 2017 11:00 PM
    Tuesday, October 31, 2017 7:33 PM
  • Hey Darran and Chuck, thanks for the advice.What I've changed is my function which creates a factory, instead of what it was I use this as this:

    		ID2D1Factory * CreateFactory(D2D1_FACTORY_TYPE FactoryType)
    		{
    			ID2D1Factory * Factory = NULL;
    			D2D1CreateFactory(FactoryType, &Factory);
    
    			return Factory;
    		}

    As you can tell instead of returning of returning a HRESULT it returns the factory which is made by the original function and does no longer need a factory as a function parameter. Here's an example of how to use it:

    App.Graphics.Factory = DX2D::Setup::CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED);

    Also for Darran, if you still wanted to know, the old function would return S_OK, which is copied from the D2D1CreateFactory HRESULT.

    Thursday, November 16, 2017 11:22 PM