Visual Studio не может разрешить статические функции

Вот код и вывод. 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;
}

Класс со всеми статическими членами, который вызывает проблемы.

#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,
        &params, &sm_pd39Device);
    if (sm_hResult != D3D_OK) {
        sm_hResult = sm_pId39->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, sm_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
            &params, &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;

А вот и вывод

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 ==========

Не могли бы вы сказать мне, что может вызвать LNK4042? Я не понимаю, где объект указан несколько раз. И я попытался Google LNK2019, но все темы, которые я нашел, были проблемы с синтаксисом. Я проверил все, что мог найти, но код, кажется, хороший (я был бы рад, если бы он не был, и вы просто укажете мне на мою ошибку). Иногда, когда я делаю небольшие изменения в коде, компоновщик срабатывает, но после нескольких компиляций он снова не работает. Кроме того, перед тем, как добавить "очистить" функцию, она работала, я добавил эту маленькую функцию, и с тех пор она работала только один раз (до того, как я добавил эту функцию, иногда компоновщик не работал, но теперь иногда это удается). Я знаю, что есть другие способы реализации синглтона, но у меня есть код, похожий на этот, и он отлично работает. Спасибо

1 ответ

Решение

Ваш вывод сборки показывает, что вам каким-то образом удалось заставить компилятор фактически скомпилировать d3d9_object.h файл. Это совершенно недопустимо. Вы не должны компилировать заголовочные файлы. Заголовочные файлы должны быть включены в .cpp файлы, не скомпилированные сами по себе.

Из-за этой проблемы ваш d3d9_object.hпосле принудительной загрузки в компилятор производит d3d9_object.obj файл, который забивает (перезаписывает) d3d9_object.obj файл, полученный из d3d9_object.cpp, Это приводит к LNK4042 и дальнейшим ошибкам компоновщика.

Не пытайтесь компилировать d3d9_object.h, Узнайте, как удалось его скомпилировать и устранить проблему.

Другие вопросы по тегам