Search code examples
c++visual-studiolinker-errorsdirect2d

I tried to build my own Direct2D library, but I get lots of linker errors upon trying to use it


I wrote a static library for using Direct2D. It compiled fine, with no warnings; but when I tried to implement it in a sample project, I get loads of linker errors:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol __imp_TranslateMessage referenced in function "private: int __cdecl Ice2D::Ice2DApp::ProcessMessages(void)" (?ProcessMessages@Ice2DApp@Ice2D@@AEAAHXZ)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_DispatchMessageW referenced in function "private: int __cdecl Ice2D::Ice2DApp::ProcessMessages(void)" (?ProcessMessages@Ice2DApp@Ice2D@@AEAAHXZ)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_PeekMessageW referenced in function "private: int __cdecl Ice2D::Ice2DApp::ProcessMessages(void)" (?ProcessMessages@Ice2DApp@Ice2D@@AEAAHXZ)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_DefWindowProcW referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z)  Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_PostQuitMessage referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_RegisterClassExW referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_CreateWindowExW referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ)  Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_ShowWindow referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_SetCapture referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z)  Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_ReleaseCapture referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z)  Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_UpdateWindow referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_SetForegroundWindow referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_SetWindowTextW referenced in function "protected: void __cdecl Ice2D::Ice2DApp::SetWindowTitle(class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >)" (?SetWindowTitle@Ice2DApp@Ice2D@@IEAAXV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_GetClientRect referenced in function "private: long __cdecl Ice2D::Ice2DApp::CreateDeviceResources(void)" (?CreateDeviceResources@Ice2DApp@Ice2D@@AEAAJXZ) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_AdjustWindowRect referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ) Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_GetWindowLongPtrW referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_SetWindowLongPtrW referenced in function "private: __int64 __cdecl Ice2D::Ice2DApp::HandleMsg(struct HWND__ *,unsigned int,unsigned __int64,__int64)" (?HandleMsg@Ice2DApp@Ice2D@@AEAA_JPEAUHWND__@@I_K_J@Z)   Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK2019 unresolved external symbol __imp_LoadCursorW referenced in function "public: long __cdecl Ice2D::Ice2DApp::Initialize(void)" (?Initialize@Ice2DApp@Ice2D@@QEAAJXZ)  Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\Ice2D.lib(Ice2DApp.obj)    1   
Error   LNK1120 18 unresolved externals Ice2D_Sample    C:\Users\jkjt1\source\repos\C++\Ice2D_Sample\x64\Debug\Ice2D_Sample.exe 1   

Additionally, if I use the code without making it a library (i.e. copying all the source files into the project), it works just fine. The sample project I tried to compile is fairly simple and has only one .cpp file:

#include <Ice2DApp.h>

class SampleApp : public Ice2D::Ice2DApp
{
public:
    void Settings() override;
    void Setup() override;
    void Update() override;
    void Draw() override;
private:
    Ice2D::TextFormat font1;
    Ice2D::LinearBrush linBrush;
    Ice2D::RadialBrush radBrush;
    unsigned short int fps;
};

void SampleApp::Settings()
{
    // Settings for window creation
    SetWindowTitle(L"Sample Ice2D Window");
    SetWindowSize(600, 300);
}

void SampleApp::Setup()
{
    // Fill pointers and initialize game logic
    CreateTextFomat(L"arial", 36.0f, font1);
    Ice2D::GradientStop linStops[3] =
    {
        {0.0f, Ice2D::Color(Ice2D::Color::Red)},
        {0.5f, Ice2D::Color(Ice2D::Color::Yellow)},
        {1.0f, Ice2D::Color(Ice2D::Color::Green)}
    };
    Ice2D::GradientStop radStops[2] =
    {
        {0.0f, Ice2D::Color(Ice2D::Color::Yellow)},
        {1.0f, Ice2D::Color(Ice2D::Color::Purple)}
    };
    CreateLinearBrush(linStops, 3u, linBrush, { 10, 150 }, { 254, 150 });
    CreateRadialBrush(radStops, 2u, radBrush, { 0, 0 }, { 0, 0 }, { 30, 30 });
    SetLinearBrush(linBrush);
    SetRadialBrush(radBrush);
}

void SampleApp::Update()
{
    // Update game logic
    if (FrameCount() % 60 == 0)
    {
        fps = (unsigned short int)(1.0f / DeltaTime());
        SetTextColor(fps <= 60 ? Ice2D::Color::Red : Ice2D::Color::Black);
    }
    radBrush->SetCenter(MakePoint(mouse.GetPos()));
}

void SampleApp::Draw()
{
    // Execute Draw Commands
    BeginDraw();
    Clear(Ice2D::Color::CornflowerBlue);
    FillRect(10, 100, fps * 2 + 10, 200, BrushMode::Linear);
    DrawRect(10, 100, 500, 200, 2.0f);
    FillEllipse(MakePoint(mouse.GetPos()), 30, 30, BrushMode::Radial);
    RenderText(L"FPS: " + std::to_wstring(fps), font1, 10, 10, 300, 50);
    EndDraw();
}

int WINAPI WinMain(
    HINSTANCE /* hInstance */,
    HINSTANCE /* hPrevInstance */,
    LPSTR /* lpCmdLine */,
    int /* nCmdShow */)
{
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    if (SUCCEEDED(CoInitialize(NULL)))
    {
        SampleApp app1;

        if (SUCCEEDED(app1.Initialize()))
        {
            app1.Start();
        }
        CoUninitialize();
    }

    return 0;
}

I think the issue is either with how I compiled it or how I included it in the sample project. I've made sure that they're using the same compiler version and runtime library. I have tried dynamically linking, but that gives me a whole other set of issues (the .dll file was corrupt). I'm using Visual Studio 2022, by the way.


Solution

  • To anyone else having the same problem (and don't mind switching to a dynamically linked library), I fixed the problem by adding __declspec(dllexport) before any function I needed to access in the sample project. I used a macro to do this: #define ICE2D_API __declspec(dllexport).