【问题标题】:LNK2001 in "How can I make a WNDPROC or DLGPROC a member of my C++ class?"“如何使 WNDPROC 或 DLGPROC 成为我的 C++ 类的成员?”中的 LNK2001
【发布时间】:2016-03-20 06:53:16
【问题描述】:

VS10:MCBS:您好, 鉴于此,discussion 在尝试使用 Pudeyev 的 code for "Hello World"How can I make a WNDPROC or DLGPROC a member of my C++ class? 中实现 Raymond Chen 的方法的 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 构造函数的调用方式或类设置是否存在问题 - 或者可能是 Raymond 文章中的日期,无法应对的 c++11 修订版?

编辑:将 WndProc 替换为绝对限定符 BaseWnd::WndProc 并使有问题的静态回调成为回调。太好了,我们可以使用的代码的其他问题。
编辑 2:拼图的最后一块是将 Pudeyev 的原始 CS_HREDRAW|CS_VREDRAW 返回到 WNDCLASS 结构。

【问题讨论】:

    标签: c++ class constructor wndproc


    【解决方案1】:

    显然我认为没有范围的定义。

    LRESULT CALLBACK WndProc
    {
     ↓
    LRESULT CALLBACK BaseWnd::WndProc
    {
    

    【讨论】:

    • 在这个编译器LRESULT CALLBACK BaseWnd::WndProc(HWND hwnd, UINT Umsg, WPARAM wParam, LPARAM lParam) 中得到一个函数定义中的 C2264 错误和一个 C2373 不同的类型修饰符。
    • 你做错了什么。编辑您的问题并显示您要输入的内容。声明和定义都应该是LRESULT CALLBACK,或者它们都应该是LRESULT
    • @Barmak:谢谢,看看你说的回到 API 是什么意思。这是棘手的事情。:)
    • 哦,在这种情况下,我猜一开始可能不需要 CALLBACK。
    【解决方案2】:

    错误应该是不言自明的。 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);
        }
        ...
    }
    

    【讨论】:

    • 感谢 Barmak,在发帖之前实际上已经尝试过了。 :(同样的错误。但定义BaseWnd::WndProc:你有什么建议?
    • 它应该可以工作,如果它给出一个错误,那就是另一个错误。实际上@nariuji 发现了另一个错误。查看更新。
    猜你喜欢
    • 2012-09-16
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2021-08-17
    • 2020-06-27
    • 1970-01-01
    • 2010-09-23
    • 2012-06-22
    相关资源
    最近更新 更多