调用函数来创建WinAPI按钮不会执行任何操作

时间:2017-08-06 16:56:39

标签: c++ winapi button

经过一段时间的WinAPI实验,我得到了一个按钮工作的窗口。代码被放入我的窗口程序中,看起来像这样:

std::vector<HWND> buttons;
HWND window;

LRESULT CALLBACK CSwindowProc(HWND window, unsigned int message, WPARAM shortParam, LPARAM longParam) {
    switch (message) {
    case WM_CREATE:
        buttons.push_back(
            CreateWindow(_T("BUTTON"), _T("OK"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                10, 10, 100, 100, window, NULL, (HINSTANCE)GetWindowLongPtr(window, GWL_HINSTANCE), NULL)
        );
        break;
    case WM_DESTROY: PostQuitMessage(0); break;
    default: return DefWindowProc(window, message, shortParam, longParam); break;
    }
    return 0;
}

请注意&#34;按钮&#34;是一个HWND向量和&#34;窗口&#34;只是用CreateWindow初始化的HWND。这些片段的上下文与此问题末尾的代码相同。

为了简化我的工作,我决定将按钮创建代码移动到一个新函数(CSnewButton)中。然后,我从窗口过程中删除了按钮创建代码,并添加了对CSnewButton()的调用。此时代码看起来像这样:

std::vector<HWND> buttons;
HWND window;

void CSnewButton() {
    buttons.push_back(
        CreateWindow(_T("BUTTON"), _T("OK"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
            10, 10, 100, 100, window, NULL, (HINSTANCE)GetWindowLongPtr(window, GWL_HINSTANCE), NULL)
    );
}

LRESULT CALLBACK CSwindowProc(HWND window, unsigned int message, WPARAM shortParam, LPARAM longParam) {
    switch (message) {
    case WM_CREATE:
        CSnewButton();
        break;
    case WM_DESTROY: PostQuitMessage(0); break;
    default: return DefWindowProc(window, message, shortParam, longParam); break;
    }
    return 0;
}

令人惊讶的是,窗口上的按钮不再存在。只需将代码从过程移动到过程调用的函数,按钮就会消失。 我很快做了一些调试以排除一些问题。我在函数中添加了一个消息框,并且出现了消息框,因此正在调用该函数。一旦添加到CSnewButton函数,C ++内联修饰符对我的情况没有帮助。我在编译时或运行时都看不到任何错误或警告。

所以我想我或者对C ++或者侵略性的C ++编译器有误解(我不会感到惊讶),对WinAPI的误解(可能是罪魁祸首)或者我的代码显然是非常不可思议的错误(我也不会感到惊讶。无论如何,我想知道为什么将按钮创建代码移动到函数中会夺走代码的功能,并解决这个问题(如果可能的话)。

展示问题的完整代码:

#include <windows.h>
#include <tchar.h>
#include <vector>

HINSTANCE instance;
HWND window;

std::vector<HWND> buttons;

//This function inexplicably does not create the button, however, if you were
//to take it's contents and paste them over a call to this function, it works
//fine.
void CSnewButton() {
    buttons.push_back(
        CreateWindow(_T("BUTTON"), _T("OK"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
            10, 10, 100, 100, window, NULL, (HINSTANCE)GetWindowLongPtr(window, GWL_HINSTANCE), NULL)
    );
}

LRESULT CALLBACK CSwindowProc(HWND window, unsigned int message, WPARAM shortParam, LPARAM longParam) {
    switch (message) {
    case WM_CREATE:
        CSnewButton(); // Issue Here
        break;
    case WM_DESTROY: PostQuitMessage(0); break;
    default: return DefWindowProc(window, message, shortParam, longParam); break;
    }
    return 0;
}

void CScreateWindow() {
    WNDCLASSEX cclass = {
        sizeof(WNDCLASSEX), CS_VREDRAW | CS_HREDRAW,
        CSwindowProc, 0, 0, instance, NULL, LoadCursor(NULL, IDC_ARROW),
        (HBRUSH)(COLOR_WINDOW + 1), NULL, _T("MyClass"), NULL
    };
    if (!RegisterClassEx(&cclass)) {
        MessageBox(NULL, _T("CSControlApp failed to register window."), _T("CSControlApp failure"), MB_OK | MB_ICONERROR); return;
    }
    window = CreateWindow(cclass.lpszClassName, _T("My Window"), WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 600, NULL, NULL, instance, NULL);
    if (!window) {
        MessageBox(NULL, _T("CSControlApp failed to create window."), _T("CSControlApp failure"), MB_OK | MB_ICONERROR); return;
    }
}

int CALLBACK WinMain(HINSTANCE h, HINSTANCE p, LPSTR cmd, int show) {
    instance = h;
    CScreateWindow();
    ShowWindow(window, show);
    UpdateWindow(window);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

1 个答案:

答案 0 :(得分:2)

这是一个C语言问题。你有两个具有相同名称的独立变量,你会感到困惑。

HWND window;  // This is a global variable

LRESULT CALLBACK CSwindowProc(HWND window, ...) // This is a parameter

当您CSWindowProcwindow时,您会获得参数。 外部 CsWindowProc当您说window时,您会获得全局变量,该变量尚未在您尝试使用它时初始化。 (CreateWindow中对CScreateWindow的调用尚未返回。)

您可以通过提供CSnewButton参数来解决问题:

void CSnewButton(HWND window)

并相应地调用它:

case WM_CREATE:
    CSnewButton(window);
    break;

为了避免将来出现类似的混淆,最好完全删除全局变量。