error LNK2001: unresolved external symbol

Started by
34 comments, last by falcon93 12 years, 9 months ago
Hi all!

I get some strange errors when I try to declare some methods as static. I've searched on google for it, but havn't managed to solve it. Here's the error messages:


error LNK2001: unresolved external symbol "public: static struct IDirect3DDevice9 * Graphics::d3ddev" ([email="?d3ddev@Graphics@@2PAUIDirect3DDevice9@@A"]?d3ddev@Graphics@@2PAUIDirect3DDevice9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static struct IDirect3D9 * Graphics::d3d" ([email="?d3d@Graphics@@2PAUIDirect3D9@@A"]?d3d@Graphics@@2PAUIDirect3D9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static struct Graphics::CUSTOMVERTEX * Graphics::vertices" ([email="?vertices@Graphics@@2PAUCUSTOMVERTEX@1@A"]?vertices@Graphics@@2PAUCUSTOMVERTEX@1@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static struct IDirect3DVertexBuffer9 * Graphics::v_buffer" ([email="?v_buffer@Graphics@@2PAUIDirect3DVertexBuffer9@@A"]?v_buffer@Graphics@@2PAUIDirect3DVertexBuffer9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static struct _D3DSURFACE_DESC Graphics::surface" ([email="?surface@Graphics@@2U_D3DSURFACE_DESC@@A"]?surface@Graphics@@2U_D3DSURFACE_DESC@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static struct IDirect3DTexture9 * Graphics::texture" ([email="?texture@Graphics@@2PAUIDirect3DTexture9@@A"]?texture@Graphics@@2PAUIDirect3DTexture9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK2001: unresolved external symbol "public: static void * Graphics::pVoid" ([email="?pVoid@Graphics@@2PAXA"]?pVoid@Graphics@@2PAXA[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj


error LNK1120: 7 unresolved externals C:\Users\Simon Blom\Desktop\AvoidBall\Debug\AvoidBall.exe



GraphicsEngine.h
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9.h>


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


#pragma once


class GraphicsEngine
{

public:
static void Initialize(HWND hWnd);
static void InitGraphics(void);
static void Update(void);
static void Draw(void);

public:
static LPDIRECT3D9 d3d;
static LPDIRECT3DDEVICE9 d3ddev;
static LPDIRECT3DVERTEXBUFFER9 v_buffer;
static IDirect3DTexture9* texture;
static D3DSURFACE_DESC surface;
static VOID* pVoid;

public:
static struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
static CUSTOMVERTEX vertices[4];

};
[/source]


GraphicsEngine.cpp
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"


void GraphicsEngine::Initialize(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

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


void GraphicsEngine::InitGraphics(void)
{
D3DXCreateTextureFromFileEx(d3ddev, L"texture.jpg", 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);
texture->GetLevelDesc(0, &surface);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);

vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = 100;
vertices[0].Y = 100;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = 100 + 25;
vertices[1].Y = 100;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = 100 + 25;
vertices[2].Y = 100 + 25;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = 100;
vertices[3].Y = 100 + 25;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;
}


void GraphicsEngine::Update(void)
{
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}


void GraphicsEngine::Draw(void)
{
d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]


Please help :(
Advertisement
I'm a little bit confused by the error messages. In your code it it says GraphicsEngine but in the error messages they only say Graphics. Are you sure you use GraphicsEngine and not Graphics in other parts of your code.

Also, what is a static struct supposed to do? I don't think there is such a thing in C++.
Hello ...

Try this: before the function: void GraphicsEngine::Initialize(HWND hWnd), you need to define those static member variables


#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"

LPDIRECT3D9 GraphicsEngine :: d3d = NULL;
LPDIRECT3DDEVICE9 GraphicsEngine :: d3ddev = NULL;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine :: v_buffer = NULL;
IDirect3DTexture9* GraphicsEngine :: texture = NULL;
D3DSURFACE_DESC GraphicsEngine :: surface;
VOID* GraphicsEngine :: pVoid = NULL;

void GraphicsEngine::Initialize(HWND hWnd)
{
}
When you declare class fields as static you will have to provide an actual instantiation. In your cpp file, add "[font=Consolas,]LPDIRECT3D9 [/font][font=Consolas,]GraphicsEngine::[/font][font=Consolas,]d3d = 0;" (0 because it is a pointer, use an appropriate default value) and so on for all your static fields.[/font]
[font=Consolas,]
[/font]
[font=Consolas,]Also, as Wooh points out, don't put static infront of your struct CUSTOMVERTEX { ... };[/font]
[font=Consolas,]
[/font]
[font=Consolas,]Lastly, put "#pragma once" at the very top of the .h file. It tells the compiler "only look at this file the first time you encounter it." It will make your compiles faster.[/font]
[font=Consolas,]
[/font]
[font=Consolas,]But you might want to reconsider your approach. Making every field and member of a class static is not really a good idea. It's (IMO) better to create a normal class and then have a single global instance. (Disregarding the whole using globals good/bad discussion for now.) [/font]
[font=Consolas,] [/font]
[font=Consolas,]
[/font]
Thanks very much for helping me :)



I'm a little bit confused by the error messages. In your code it it says GraphicsEngine but in the error messages they only say Graphics. Are you sure you use GraphicsEngine and not Graphics in other parts of your code.

Also, what is a static struct supposed to do? I don't think there is such a thing in C++.


Yeah, the class was named Graphics before. It however seemed that Graphics was a reserved keyword and therefore I changed back to GraphicsEngine. I copied all errors before I changed back, thats why :wink:

Removed the static from the struct.





Hello ...

Try this: before the function: void GraphicsEngine::Initialize(HWND hWnd), you need to define those static member variables


#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"

LPDIRECT3D9 GraphicsEngine :: d3d = NULL;
LPDIRECT3DDEVICE9 GraphicsEngine :: d3ddev = NULL;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine :: v_buffer = NULL;
IDirect3DTexture9* GraphicsEngine :: texture = NULL;
D3DSURFACE_DESC GraphicsEngine :: surface;
VOID* GraphicsEngine :: pVoid = NULL;

void GraphicsEngine::Initialize(HWND hWnd)
{
}



I've added the above declarations, and the errors has now lowered to an amount of 3 (see below) :D





When you declare class fields as static you will have to provide an actual instantiation. In your cpp file, add "[font="Consolas,"]LPDIRECT3D9 [/font][font="Consolas,"]GraphicsEngine::[/font][font="Consolas,"]d3d = 0;" (0 because it is a pointer, use an appropriate default value) and so on for all your static fields.[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]Also, as Wooh points out, don't put static infront of your struct CUSTOMVERTEX { ... };[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]Lastly, put "#pragma once" at the very top of the .h file. It tells the compiler "only look at this file the first time you encounter it." It will make your compiles faster.[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]But you might want to reconsider your approach. Making every field and member of a class static is not really a good idea. It's (IMO) better to create a normal class and then have a single global instance. (Disregarding the whole using globals good/bad discussion for now.) [/font]


Ok, I've tried to declare them and setting them to both null and 0. It lowered my amount of errors, but there's still 3 errors left (se below). The static in front of the struct has also been removed.

Thank you very much for actually making me understand what "#pragma once" does, that line has always been strange to me, untill now :P

How would you advise me to do? Why I thought static methods would be good is becouse I can reach them even from the player-class and enemy-class (see image in my first post). How would you have done if you wanted to access the Draw method from classes that is "below" the GraphicsEnigne?


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


So, here's my current code and errors:


GraphicsEngine.h:
[source lang="cpp"]
#pragma once


#include <d3d9.h>
#include <d3dx9.h>


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


class GraphicsEngine
{

public:
static void Initialize(HWND hWnd);
static void InitGraphics(void);
static void Update(void);
static void Draw(void);

public:
static LPDIRECT3D9 d3d;
static LPDIRECT3DDEVICE9 d3ddev;
static LPDIRECT3DVERTEXBUFFER9 v_buffer;
static IDirect3DTexture9* texture;
static D3DSURFACE_DESC surface;
static VOID* pVoid;

public:
struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
static CUSTOMVERTEX vertices[4];

};
[/source]


GraphicsEngine.cpp:
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"


LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC surface;
VOID* GraphicsEngine::pVoid = 0;


void GraphicsEngine::Initialize(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

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


void GraphicsEngine::InitGraphics(void)
{
D3DXCreateTextureFromFileEx(d3ddev, L"texture.jpg", 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);
texture->GetLevelDesc(0, &surface);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);

vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = 100;
vertices[0].Y = 100;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = 100 + 25;
vertices[1].Y = 100;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = 100 + 25;
vertices[2].Y = 100 + 25;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = 100;
vertices[3].Y = 100 + 25;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;
}


void GraphicsEngine::Update(void)
{
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}


void GraphicsEngine::Draw(void)
{
d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]



error LNK2001: unresolved external symbol "public: static struct GraphicsEngine::CUSTOMVERTEX * GraphicsEngine::vertices" ([email="?vertices@GraphicsEngine@@2PAUCUSTOMVERTEX@1@A"]?vertices@GraphicsEngine@@2PAUCUSTOMVERTEX@1@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\GraphicsEngine.obj



error LNK2001: unresolved external symbol "public: static struct _D3DSURFACE_DESC GraphicsEngine::surface" ([email="?surface@GraphicsEngine@@2U_D3DSURFACE_DESC@@A"]?surface@GraphicsEngine@@2U_D3DSURFACE_DESC@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\GraphicsEngine.obj

Thats strange as I can't initialize the surface to either 0 or null :/




error LNK1120: 2 unresolved externals C:\Users\Simon Blom\Desktop\AvoidBall\Debug\AvoidBall.exe
Hi,



//You have to specify to which class surface belongs (i.e GraphicsEngine), you forgot to put that in your code.
D3DSURFACE_DESC GraphicsEngine :: surface;

// Put this line with the rest of the static members in your cpp file
CUSTOMVERTEX GraphicsEngine :: vertices[4];


This will solve your errors.

LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC GraphicsEngine::surface = 0;
VOID* GraphicsEngine::pVoid = 0;
GraphicsEngine::CUSTOMVERTEX GraphicsEngine::vertices[4] = 0;


I've added that now, but i still can't set the surface to 0 or null, and neither can I set the vertices[4] to 0 or null? :(
Well...

D3DSURFACE_DESC is not a pointer, so you cannot set it to NULL. vertices is an array of structures, so you cannot set that to be NULL either.
You can use memset or ZeroMemory though on them. But you will have to do that in your Initialize()function.

LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC GraphicsEngine::surface;
VOID* GraphicsEngine::pVoid = 0;
GraphicsEngine::CUSTOMVERTEX GraphicsEngine::vertices[4];


I made it like this, and now it works. I'll drop a reply when I've done some cleanup in GraphicsEngine, but now it works to build atleast, and I even get no warnings. Thanks :)
It appears you are writing a namespace, not a class.


Why I thought static methods would be good is becouse I can reach them even from the player-class and enemy-class (see image in my first post). How would you have done if you wanted to access the Draw method from classes that is "below" the GraphicsEnigne?
[/quote]
For complex games, objects do not render themselves. But that aside, a simple way is the following:

void Player::Draw(GraphicsEngine &graphics) const
{
// Using "this" pointer for clarity
graphics.drawSprite(this->position, this->texture, /* ... */);
}

Whatever you end up doing, you should almost certainly not be exposing all those variables as public.

Be aware that using preprocessor constants inside a class doesn't have any significance, as the preprocessor does not understand or respect C++ scoping rules. Try making it a const <type> (DWORD?) instead.

This topic is closed to new replies.

Advertisement