0

So I have a simple project with one main.cpp and BaseWindow class which is split into header and source file. https://learn.microsoft.com/en-us/windows/win32/learnwin32/managing-application-state-

this is the source files. Basically I have split the class my self since it was defined and implemented in main.cpp compiling as it was gave no errors and code work. After refactoring which I described above I get LINK2019 ERROR which is the unresolved external symbol. I went ahead and searched what could cause that, and it turns out that visuals studio is not linking BaseWindow.cpp

The ERROR

Severity Code Description Project File Line Suppression State Error LNK2019 unresolved external symbol "public: int cdecl BaseWindow::Create(wchar_t const *,unsigned long,unsigned long,int,int,int,int,struct HWND *,struct HMENU__ *)" (?Create@?$BaseWindow@VMainWindow@@@@QEAAHPEB_WKKHHHHPEAUHWND__@@PEAUHMENU__@@@Z) referenced in function wWinMain win32_API_Learning E:\Learning GameDev\Projects\win32_API_Learning\win32_API_Learning\main.obj 1

FILES:

BaseWindow.h

#pragma once

#include <windows.h>

template <class DERIVED_TYPE>
class BaseWindow
{
public:
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    BaseWindow() : m_hwnd(NULL) { }

    BOOL Create(
        PCWSTR lpWindowName,
        DWORD dwStyle,
        DWORD dwExStyle = 0,
        int x = CW_USEDEFAULT,
        int y = CW_USEDEFAULT,
        int nWidth = CW_USEDEFAULT,
        int nHeight = CW_USEDEFAULT,
        HWND hWndParent = 0,
        HMENU hMenu = 0
    );

    HWND Window() const { return m_hwnd; }

protected:

    virtual PCWSTR  ClassName() const = 0;
    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

    HWND m_hwnd;
};

BaseWindow.cpp

#include "BaseWindow.h"
#include <windows.h>


template <class DERIVED_TYPE>
LRESULT CALLBACK BaseWindow<DERIVED_TYPE>::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    DERIVED_TYPE* pThis = NULL;

    if (uMsg == WM_NCCREATE)
    {
        CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
        pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

        pThis->m_hwnd = hwnd;
    }
    else
    {
        pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    }
    if (pThis)
    {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    }
    else
    {
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}



template <class DERIVED_TYPE>
BOOL BaseWindow<DERIVED_TYPE>::Create(PCWSTR lpWindowName, DWORD dwStyle, DWORD dwExStyle /*= 0*/, int x /*= CW_USEDEFAULT*/, int y /*= CW_USEDEFAULT*/, int nWidth /*= CW_USEDEFAULT*/, int nHeight /*= CW_USEDEFAULT*/, HWND hWndParent /*= 0*/, HMENU hMenu /*= 0 */)
{
    WNDCLASS wc = { 0 };

    wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = ClassName();

    RegisterClass(&wc);

    m_hwnd = CreateWindowEx(
        dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
        nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
    );

    return (m_hwnd ? TRUE : FALSE);
}

main.cpp

#ifndef UNICODE
#define UNICODE
#endif 

#include <windows.h>
#include "BaseWindow.h"



class MainWindow : public BaseWindow<MainWindow>
{
public:
    PCWSTR  ClassName() const { return L"Sample Window Class"; }
    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(m_hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(m_hwnd, &ps);
    }
    return 0;

    default:
        return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
    }
    return TRUE;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    MainWindow win;

    if (!win.Create(L"Learn to Program Windows", WS_OVERLAPPEDWINDOW))
    {
        return 0;
    }

    ShowWindow(win.Window(), nCmdShow);

    // Run the message loop.

    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
Anton Stafeyev
  • 761
  • 1
  • 7
  • 20
  • Make sure the source files are part of your Visual Studio project. – drescherjm Dec 11 '19 at 17:52
  • 1
    This isn't really solvable without seeing your project. I expect one of the C++ source files was not compiled for some reason (missing, "Item Type" got changed somehow, etc.) – Fire Lancer Dec 11 '19 at 18:13
  • Intentionally put a syntax error in the file that implements your class and see if it is compiled in your output tab of Visual Studio. You probably need to right click on "Solution Explorer" and click Add->"Existing Item" and select your cpp file that implements your class. – drescherjm Dec 11 '19 at 18:18
  • @drescherjm it does show the syntax errors – Anton Stafeyev Dec 11 '19 at 18:31
  • @drescherjm added all files to the post – Anton Stafeyev Dec 11 '19 at 18:43
  • Templates need to be implemented in the header. [https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – drescherjm Dec 11 '19 at 18:53
  • @drescherjm man i almost went crazy :) reading it now. thanks – Anton Stafeyev Dec 11 '19 at 19:02

0 Answers0