"How can I make a WNDPROC or DLGPROC a member of my C++ class?" 中的 LNK2001
LNK2001 in "How can I make a WNDPROC or DLGPROC a member of my C++ class?"
VS10:MCBS:你好,
鉴于此discussion encountered a problem attempting a Hello World implementation of Raymond Chen's method in How can I make a WNDPROC or DLGPROC a member of my C++ class? using Pudeyev's code for "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 构造函数的调用方式或 class 设置是否有问题 - 或者也许,即 Raymond 文章上的日期,无法应对的 c++11 修订版?
编辑:将 WndProc 替换为绝对限定符 BaseWnd::WndProc 并将有问题的静态回调设为回调。太好了,我们可以处理的代码的其他问题。
Edit2:拼图的最后一块是将 Pudeyev 的原始 CS_HREDRAW|CS_VREDRAW
返回到 WNDCLASS 结构。
错误应该是不言自明的。 BaseWnd::WndProc
已声明,但未定义。见@nariuji
另外 BaseWnd
需要一个 public 构造函数,因为您稍后会调用它:
class BaseWnd
{
//******* make this public:
public:
BaseWnd();
...
};
WNDCLASSW wc
必须初始化为零:
WNDCLASSW wc = { 0 };
创建 window 时它是不可见的。您必须使用 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);
}
...
}
显然我认为范围的定义是 none。
LRESULT CALLBACK WndProc
{
↓
LRESULT CALLBACK BaseWnd::WndProc
{
VS10:MCBS:你好, 鉴于此discussion encountered a problem attempting a Hello World implementation of Raymond Chen's method in How can I make a WNDPROC or DLGPROC a member of my C++ class? using Pudeyev's code for "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 构造函数的调用方式或 class 设置是否有问题 - 或者也许,即 Raymond 文章上的日期,无法应对的 c++11 修订版?
编辑:将 WndProc 替换为绝对限定符 BaseWnd::WndProc 并将有问题的静态回调设为回调。太好了,我们可以处理的代码的其他问题。
Edit2:拼图的最后一块是将 Pudeyev 的原始 CS_HREDRAW|CS_VREDRAW
返回到 WNDCLASS 结构。
错误应该是不言自明的。 BaseWnd::WndProc
已声明,但未定义。见@nariuji
另外 BaseWnd
需要一个 public 构造函数,因为您稍后会调用它:
class BaseWnd
{
//******* make this public:
public:
BaseWnd();
...
};
WNDCLASSW wc
必须初始化为零:
WNDCLASSW wc = { 0 };
创建 window 时它是不可见的。您必须使用 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);
}
...
}
显然我认为范围的定义是 none。
LRESULT CALLBACK WndProc
{
↓
LRESULT CALLBACK BaseWnd::WndProc
{