Here is the code and the output. win_main.cpp
#include <Windows.h>
#include <tchar.h>
#include "d3d9_object.h"
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
WNDCLASSEX createWndClassEx(HINSTANCE);
HWND createWindow(const wchar_t *caption, HINSTANCE);
void exitWithFailure(const wchar_t *message, HINSTANCE);
const wchar_t gszWndClassName[] = L"MainWindowClassName";
WNDCLASSEX gWndClassEx;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int iCmdShow)
{
HWND hwnd = NULL;
MSG msg = { 0 };
BOOL bReturn;
WNDCLASSEX wndClassEx = createWndClassEx(hInstance);
if (!RegisterClassEx(&wndClassEx)) exitWithFailure(L"Cannot create window class", hInstance);
hwnd = createWindow(L"£d \u018Fditor", hInstance);
if (!hwnd)
exitWithFailure(L"Cannot create window", hInstance);
if (gpd39o->init(hwnd) == false)
exitWithFailure(L"Cannot initilize Direct3D", hInstance);
ShowWindow(hwnd, SW_MAXIMIZE);
UpdateWindow(hwnd);
if (!gpd39o->clear()) MessageBox(hwnd, L"Cannot clear device to color", L"Error!", MB_OK | MB_ICONERROR);
while ((bReturn = GetMessage(&msg, hwnd, 0, 0))) {
if (bReturn == -1) {
exitWithFailure(L"Message loop error", hInstance);
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
gpd39o->deinit();
UnregisterClass(gszWndClassName, hInstance);
return EXIT_SUCCESS;
}
void exitWithFailure(const wchar_t *message, HINSTANCE h)
{
MessageBox(NULL, message, L"Error!", MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
gpd39o->deinit();
UnregisterClass(gszWndClassName, h);
exit(EXIT_FAILURE);
}
LRESULT CALLBACK WndProc(HWND h, UINT m, WPARAM w, LPARAM l)
{
if (m == WM_DESTROY) {
PostQuitMessage(0);
return 0;
}
return DefWindowProc(h, m, w, l);
}
HWND createWindow(const wchar_t *c, HINSTANCE h)
{
DWORD winStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
return CreateWindowEx(WS_EX_APPWINDOW, gszWndClassName, c, winStyle,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, h, NULL);
}
WNDCLASSEX createWndClassEx(HINSTANCE h)
{
WNDCLASSEX w = { 0 };
w.cbSize = sizeof(WNDCLASSEX);
w.hInstance = h;
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpszClassName = (LPCWSTR)gszWndClassName;
w.lpfnWndProc = WndProc;
return w;
}
A class with all static members which causes problems.
#ifndef _D3D9_OBJECT_H_
#define _D3D9_OBJECT_H_
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9math.h>
#include "vertex_types.h"
/*
- sm_ - static member
- d39 - Direct3D9
- f - float
*/
class D3D9Object
{
public:
D3D9Object() { }
static bool init(HWND);
static void deinit();
static bool clear(int color = D3DCOLOR_XRGB(0, 0, 0), float fZDepth = 1.0f);
static IDirect3D9 * sm_pId39;
static IDirect3DDevice9 * sm_pd39Device;
~D3D9Object() { }
private:
static HWND sm_hWnd;
static float sm_fAspectRatio;
static HRESULT sm_hResult;
static bool createDevice();
static void setPresentParams(D3DPRESENT_PARAMETERS &);
static bool setDefaultRenderState();
};
extern D3D9Object * gpd39o;
#endif
d3d9_object.cpp #include "d3d9_object.h"
IDirect3D9 * D3D9Object::sm_pId39;
IDirect3DDevice9 * D3D9Object::sm_pd39Device;
HRESULT D3D9Object::sm_hResult;
HWND D3D9Object::sm_hWnd;
float D3D9Object::sm_fAspectRatio;
bool D3D9Object::init(HWND h)
{
if (!h) return false;
sm_hWnd = h;
if (!(sm_pId39 = Direct3DCreate9(D3D_SDK_VERSION))) return false;
if (!createDevice()) return false;
if (!setDefaultRenderState()) return false;
return true;
}
void D3D9Object::deinit()
{
if (sm_pId39) sm_pId39->Release();
if (sm_pd39Device) sm_pd39Device->Release();
sm_pId39 = NULL;
sm_pd39Device = NULL;
sm_hWnd = NULL;
}
bool D3D9Object::clear(int c, float z)
{
sm_hResult = sm_pd39Device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, c, z, 0);
return sm_hResult == D3D_OK;
}
bool D3D9Object::setDefaultRenderState()
{
sm_hResult = sm_pd39Device->SetRenderState(D3DRS_LIGHTING, FALSE);
if (sm_hResult != D3D_OK) return false;
sm_hResult = sm_pd39Device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
if (sm_hResult != D3D_OK) return false;
return true;
}
bool D3D9Object::createDevice()
{
if (sm_pd39Device || !sm_pId39) return false;
D3DPRESENT_PARAMETERS params = { 0 };
setPresentParams(params);
sm_fAspectRatio = (float)params.BackBufferWidth / (float)params.BackBufferHeight;
sm_hResult = sm_pId39->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, sm_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING,
¶ms, &sm_pd39Device);
if (sm_hResult != D3D_OK) {
sm_hResult = sm_pId39->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, sm_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
¶ms, &sm_pd39Device);
if (sm_hResult != D3D_OK) return false;
}
return true;
}
void D3D9Object::setPresentParams(D3DPRESENT_PARAMETERS &p)
{
ZeroMemory(&p, sizeof(D3DPRESENT_PARAMETERS));
p.hDeviceWindow = sm_hWnd;
p.BackBufferCount = 1;
p.SwapEffect = D3DSWAPEFFECT_FLIP;
p.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
p.EnableAutoDepthStencil = TRUE;
p.AutoDepthStencilFormat = D3DFMT_D16;
RECT r = { 0 };
GetClientRect(sm_hWnd, &r);
p.Windowed = true;
p.BackBufferWidth = r.right;
p.BackBufferHeight = r.bottom;
p.BackBufferFormat = D3DFMT_UNKNOWN;
}
D3D9Object gd39Object;
extern D3D9Object * gpd39o = &gd39Object;
And here is the output
1>------ Build started: Project: 3DEditor, Configuration: Debug Win32 ------
1> win_main.cpp
1> d3d9_object.h
1> d3d9_object.cpp
1> Generating Code...
1>Debug\d3d9_object.obj : warning LNK4042: object specified more than once; extras ignored
1>win_main.obj : error LNK2019: unresolved external symbol "public: static bool __cdecl D3D9Object::init(struct HWND__ *)" (?init@D3D9Object@@SA_NPAUHWND__@@@Z) referenced in function _WinMain@16
1>win_main.obj : error LNK2019: unresolved external symbol "public: static void __cdecl D3D9Object::deinit(void)" (?deinit@D3D9Object@@SAXXZ) referenced in function "void __cdecl exitWithFailure(wchar_t const *,struct HINSTANCE__ *)" (?exitWithFailure@@YAXPB_WPAUHINSTANCE__@@@Z)
1>win_main.obj : error LNK2019: unresolved external symbol "public: static bool __cdecl D3D9Object::clear(int,float)" (?clear@D3D9Object@@SA_NHM@Z) referenced in function _WinMain@16
1>C:\Users\User\documents\visual studio 2013\Projects\3DEditor\Debug\3DEditor.exe : fatal error LNK1120: 3 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Could you tell me what could cause LNK4042? I don't get where the object is specified multiple times. And I tried to google LNK2019, but all the topics I found were syntax issues. I checked everything I could find, but the code seems to be good (i'd be glad if it wasn't and you'd just point my mistake to me). Sometimes, when I do minor changes to the code the linker succeeds, but after several compilations it fails again. Also, before I added "clear" function it was working, I added this one little function, and it worked only once since then (before I added this function sometimes the linker did fail, but now it sometimes succeeds). I know there are other ways to implement singleton, but I have code similar to this, and it works fine. Thanks
Your build output shows that you somehow managed to force the compiler to actually compile
d3d9_object.h
file. This is completely unacceptable. You are not supposed to compile header files. Header files are supposed to be included into.cpp
files, not compiled by themselves.Because of that problem, your
d3d9_object.h
, after being force-fed to compiler, producesd3d9_object.obj
file, which clobbers (overwrites) the properd3d9_object.obj
file obtained fromd3d9_object.cpp
. This leads to LNK4042 and further linker errors.Don't attempt to compile
d3d9_object.h
. Find out how it managed to get compiled and fix the problem.