Smarkus

[DirectX9 Bitmaps] Can someone help me out with a nullptr check?

Recommended Posts

//page 120
#include <Windows.h>
#include <windef.h>
#include <winuser.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//#pragma comment (lib,"d3d9.lib")	//library's link
//#pragma comment (lib,"d3dx9.lib")
//#pragma comment (lib,"dxguid.lib")
//#pragma comment (lib,"winmm.lib")	//システム時刻取得に必要 | マルチメディアライブラリ(Windows Multimedia Library)
//#pragma comment (lib,"dinput8.lib")

#define APPTITLE "CreateSurface"

#define KEY_DOWN(vk_code)((GetAsyncKeyState(vk_code)&0x8000)?1:0)
#define KEY_UP(vk_code)((GetAsyncKeyState(vk_code)&0x8000)?1:0)

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

//function prototypes
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);
ATOM MyRegisterClass(HINSTANCE);
int GameInit(HWND);
void GameRun(HWND);
void GameEnd(HWND);

//Direct3D Objects
LPDIRECT3D9 d3d = NULL;
LPDIRECT3DDEVICE9 d3ddev = NULL;
LPDIRECT3DSURFACE9 surface = NULL;
LPDIRECT3DSURFACE9 backbuffer = NULL;

LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_QUIT:
		GameEnd(hWnd);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

//helper function to set up windows properties
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	// create struucture
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);

	//fill the structure with information
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc		= (WNDPROC)WinProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInstance;
	wc.hIcon			= NULL;
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= APPTITLE;
	wc.hIconSm			= NULL;

	//set up the window with the class info
	return RegisterClassEx(&wc);
}

//Entry point for a windows program
int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int    nCmdShow)
{
	MSG msg;

	MyRegisterClass(hInstance);

	HWND hWnd;
	
	hWnd = CreateWindow(
		APPTITLE,
		APPTITLE,
		WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		SCREEN_WIDTH, SCREEN_HEIGHT,
		NULL, NULL,
		hInstance,
		NULL
	);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	
	if (!GameInit(hWnd))
	{
		return 0;
	}
	
	//Main Message loop
	int done = 0;

	while (!done)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				done = 1;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			GameRun(hWnd);
		}
	}
	return msg.wParam;
}

int GameInit(HWND hwnd)
{
	HRESULT result;

	//initialize Direct3D 
	d3d = Direct3DCreate9(D3D_SDK_VERSION); 
	
	if (d3d == NULL)
	{
		MessageBox(hwnd, "Error initializing Direct3D", "Error", MB_OK);
		return 0;
	}

	//set Direct3D presentation parameters 
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.Windowed = TRUE; 
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 
	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferWidth = SCREEN_WIDTH;
	d3dpp.BackBufferHeight = SCREEN_HEIGHT;
	d3dpp.hDeviceWindow = hwnd;

	//create Direct3D device 
	d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); 
	
	if (d3ddev = NULL)
	{
		MessageBox(hwnd, "Error creating Direct3D device", "Error", MB_OK); 
		return 0;
	}

	//set random number seed 
	srand(time(NULL));
	
	//Clear the backbuffer to black
	d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	//Create pointer to back buffer
	d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

	//create surface
	result = d3ddev->CreateOffscreenPlainSurface(
		100, 100,
		D3DFMT_X8R8G8B8,
		D3DPOOL_DEFAULT,
		&surface,
		NULL);

	if (result!=D3D_OK)
	{
		return 1;
	}

	//load surface from file
	result = D3DXLoadSurfaceFromFile(
		surface,
		NULL, NULL,
		"char.jpg",
		NULL,
		D3DX_DEFAULT,
		0, NULL);
	//make sure file was loaded fine
	if (result != D3D_OK)
	{
		return 1;
	}

	//draw surface to back buffer
	d3ddev->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE);

	//return okay
	return 1;
}

void GameRun(HWND hwnd)
{
	RECT rect;
	int r, g, b;

	if (d3ddev == NULL)
	{
		return;
	}

	if (d3ddev->BeginScene())
	{
		//Create pointer to the back buffer
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

		//draw surface to the back buffer
		d3ddev->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE);

		//stop rendering
		d3ddev->EndScene();
	}
	d3ddev->Present(NULL, NULL, NULL, NULL);

	//check for escape key to exit program
	if (KEY_DOWN(VK_ESCAPE))
	{
		PostMessage(hwnd, WM_DESTROY, 0, 0);
	}
}

void GameEnd(HWND hwnd)
{
	//free the surface
	surface->Release();

	if (d3ddev != NULL)
	{
		d3ddev->Release();
	}

	if (d3d != NULL)
	{
		d3d->Release();
	}
}

So this is the code. I'm following a book and I checked If I made any mistakes. The picture shows what the error is. Can someone help?

Also, what is the default location for a file/bitmap/jpg in my case?

gamdev.PNG

Share this post


Link to post
Share on other sites

Here goes one problem

if (d3ddev = NULL)
	{
		MessageBox(hwnd, "Error creating Direct3D device", "Error", MB_OK); 
		return 0;
	}

Use '==' to test for equivalancy. Which explains why you make it to the exception being thrown. I'm guessing this call is failing here. Make sure the values you are passing to this function are valid

d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

 

 

Edited by markypooch

Share this post


Link to post
Share on other sites
3 minutes ago, markypooch said:

Here goes one problem


if (d3ddev = NULL)
	{
		MessageBox(hwnd, "Error creating Direct3D device", "Error", MB_OK); 
		return 0;
	}

Which explains why you make it to the exception being thrown.

I'm guessing this call is failing here. Make sure the values you are passing to this function are valid


d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

 

 

Not sure if this is the problem, the book has the same code for device as mine. Is there anything that could possibly be wrong?

Share this post


Link to post
Share on other sites

Trust me on this one. All technical books have errata. In this case I'm very much assuming the technical editor missed this. Add the '==' to that if condition, and you should see that error message box popup telling you that device creation failed.

Share this post


Link to post
Share on other sites
4 minutes ago, Jamal Nasir said:

Not sure if this is the problem, the book has the same code for device as mine.

Then it must be a typo, consider the following:

struct Foobar {
	int x;
	void frobnicate() {
		cout << this->x;
	}
};

int main() {
	Foobar* f = new Foobar {3};
	if ( f = nullptr ) { // Compiler should warn about this line
		return -1;
	}

	f->frobnicate(); // This will always crash
	delete f;
}

 

Share this post


Link to post
Share on other sites
3 minutes ago, markypooch said:

Trust me on this one. All technical books have errata. In this case I'm very much assuming the technical editor missed this. Add the '==' to that if condition, and you should see that error message box popup telling you that device creation failed.

Oh awesome! It works now, thank you so much!

Share this post


Link to post
Share on other sites

Rather than testing for NULL after CreateDevice you really should be testing the HRESULT it returns, using the SUCCEEDED and FAILED macros, with failure HRESULTs giving you some more info on why it failed.

You also have a nasty memory leak in that code - you need a surface->Release for each GetBackBuffer call. In this case it won't destroy the backbuffer because GetBackBuffer will increment the reference count for it, so Release will just decrement it; it doesn't get destroyed until the reference count goes to 0.

Share this post


Link to post
Share on other sites
On 6/19/2017 at 0:14 PM, Smarkus said:

d3d = Direct3DCreate9(D3D_SDK_VERSION);

this creates a d3d device, and d3d points to it.

On 6/19/2017 at 0:14 PM, Smarkus said:

if (d3d = NULL)  { 

and then this sets d3d to NULL, then checks to see if d3d is zero or non-zero,  and executes the code block if its non-zero. Since it was just set to NULL (ie zero), its never non-zero, so the code block never executes, and you are always NULL-ing out your d3d device pointer. A guaranteed show stopper there.

this is because evaluating expressions inside the condition statement has a higher precedence (IE gets done first).

In the end its simply a typo quite common to c/c++.

lesson learned: always double check those == statements. its a typo that syntax checking can't pick up, which leads to a logic error. it can only be found by code inspection or testing (or both ?).

Share this post


Link to post
Share on other sites
18 hours ago, Adam_42 said:

I'd also recommend turning on the compiler warning that will catch this, by increasing the warning level to 4 in Visual Studio.

You could even go as far as turning that warning into an error by doing:


#pragma warning(error : 4706)

 

What might not be obvious is that you can make this an error even without bumping your warning level to 4 (although you should be compiling with warning level 2 or 3 at least, as well as with warnings-as-errors, anyway).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now