LNK2001 в Как сделать WNDPROC или DLGPROC членом моего класса C++?

VS10: MCBS: Привет. В свете этого обсуждения возникла проблема попытка реализации Hello World метода Рэймонда Чена в Как я могу сделать WNDPROC или DLGPROC член моего класса C++? используя код для "Hello World":

error LNK2001: unresolved external symbol "private: long __thiscall
BaseWnd::WndProc(struct HWND__ *,unsigned int,unsigned int,long)" 
(?WndProc@BaseWnd@@AAEJPAUHWND__@@IIJ@Z)

Код выглядит следующим образом:

// ...Written by Oleg Pudeyev, (c) 2003
#include <windows.h>
HINSTANCE appHinst;

class BaseWnd
{
public:
BaseWnd();

// This is the static callback that we register
static LRESULT CALLBACK s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// The static callback recovers the "this" pointer and then calls this member function.
LRESULT BaseWnd::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

};

BaseWnd::BaseWnd(void)
{
    WNDCLASSW wc = {
        // Request redraws as we're centering the string
        CS_HREDRAW|CS_VREDRAW,
        BaseWnd::s_WndProc,
        // No per-class data
        0,
        // No per-window data
        0,
        appHinst,
        LoadIcon(0, IDI_APPLICATION),
        LoadCursor(0, IDC_ARROW),
        HBRUSH(COLOR_BACKGROUND),
        0,
        L"BaseWnd"
    };
RegisterClassW(&wc);
HWND hwnd = CreateWindowW(L"BaseWnd", L"Hello, World!", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, appHinst, this);
ShowWindow(hwnd, SW_SHOW);
}

LRESULT BaseWnd::WndProc(HWND hwnd, UINT Umsg, WPARAM wParam, LPARAM lParam)
{
switch (Umsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_PAINT:
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
RECT r;
GetClientRect(hwnd, &r);
SetBkMode(ps.hdc, TRANSPARENT);
DrawTextW(ps.hdc, L"Hello, World!", -1, &r, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
EndPaint(hwnd, &ps);
break;

default:
// Use default handling for messages we don't process
return DefWindowProc(hwnd, Umsg, wParam, lParam);
}
return 0;
}

LRESULT CALLBACK BaseWnd::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BaseWnd *pThis; // our "this" pointer will go here

if (uMsg == WM_NCCREATE) {
// Recover the "this" pointer which was passed as a parameter to CreateWindow(Ex).
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<BaseWnd*>(lpcs->lpCreateParams);
// Put the value in a safe place for future use
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
} else {
// Recover the "this" pointer from where our WM_NCCREATE handler stashed it.
pThis = reinterpret_cast<BaseWnd*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}

if (pThis) {
// Now that we have recovered our "this" pointer, let the member function finish the job.
//Removal of this line removes the LNK2001
return pThis->WndProc(hwnd, uMsg, wParam, lParam);
}

// "this" pointer unknown, so just do the default thing. Hopefully, didn't need to customize behavior yet.
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPTSTR cmdline, int showcmd)
{
appHinst = hinst;
BaseWnd p;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

Что-то не так с тем, как вызывается конструктор BaseWnd, или с настройкой класса, или, возможно, с датой в статье Рэймонда, с версией С++ 11, которая не справляется?

Редактировать: Заменил WndProc абсолютным квалификатором BaseWnd::WndProc и сделал вызывающий нарушение статический обратный вызов обратным вызовом. Отлично, есть другие проблемы с кодом, с которыми мы можем работать.
Edit2: Последней частью головоломки было возвращение исходного CS_HREDRAW|CS_VREDRAW Пудеева в структуру WNDCLASS.


person Laurie Stearn    schedule 20.03.2016    source источник


Ответы (2)


По-видимому, я думаю, что определение масштаба - нет.

LRESULT CALLBACK WndProc
{
 ↓
LRESULT CALLBACK BaseWnd::WndProc
{
person nariuji    schedule 20.03.2016
comment
В этом компиляторе LRESULT CALLBACK BaseWnd::WndProc(HWND hwnd, UINT Umsg, WPARAM wParam, LPARAM lParam) возникает ошибка C2264 в определении функции и модификаторы различных типов C2373. - person Laurie Stearn; 20.03.2016
comment
Вы делаете что-то не так. Отредактируйте свой вопрос и покажите, что вы вводите. Объявление и определение должны быть как LRESULT CALLBACK, так и они должны быть LRESULT. - person Barmak Shemirani; 20.03.2016
comment
@Barmak: Спасибо, посмотри, что ты имеешь в виду, говоря о возвращении к API. Это сложная штука. :) - person Laurie Stearn; 20.03.2016
comment
О, в этом случае я думаю, что CALLBACK вообще не нужен. - person nariuji; 20.03.2016

Ошибка должна быть понятной. BaseWnd::WndProc объявлено, но не определено. См. @nariuji

Также BaseWnd нужен общедоступный конструктор, потому что вы собираетесь вызвать его позже:

class BaseWnd
{
//******* make this public:
public:
BaseWnd();
...
};

WNDCLASSW wc должен быть инициализирован нулем:

WNDCLASSW wc = { 0 };

Когда вы создаете окно, оно невидимо. Вы должны сделать его видимым с помощью ShowWindow или изменить стиль на WS_VISIBLE | WS_OVERLAPPEDWINDOW

HWND hwnd = CreateWindowW(L"BaseWnd", L"Hello, World!", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, appHinst, this);
ShowWindow(hwnd, SW_SHOW); //*** add this

Объявление указателя ничего не делает. Вам также нужен цикл сообщений:

WinMain(...)
{
    //BaseWnd *pthis; //***remove this line
    BaseWnd wnd;//***add this line
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    ...
}
person Barmak Shemirani    schedule 20.03.2016
comment
Спасибо Бармак, на самом деле попробовал их до публикации. :( Та же ошибка. но определение BaseWnd::WndProc: что вы предлагаете? - person Laurie Stearn; 20.03.2016
comment
Это должно работать, если выдает ошибку, это другая ошибка. На самом деле @nariuji обнаружил другую ошибку. Смотрите обновление. - person Barmak Shemirani; 20.03.2016