c ++ WinApi注册第二个窗口类错误

时间:2016-09-25 11:54:43

标签: c++ winapi

我正在尝试在c ++ winApi上创建第二个窗口,当我尝试注册第二个窗口类时出错。但是,这个类是注册的,如果我在第一个类上使用UnregisterClass,那么,类拼写正确。

#include "stdafx.h"
#include "rgr.h"
#include <stdio.h>

#define MAX_LOADSTRING 100    
// GLOBAL:
HINSTANCE hInst;

HWND childWnd;
WCHAR szTitle[MAX_LOADSTRING];                  
WCHAR szWindowClass[MAX_LOADSTRING];            

WCHAR childTitle[MAX_LOADSTRING];                  
WCHAR childWindowClass[MAX_LOADSTRING];
ATOM                MyRegisterClass(HINSTANCE hInstance);
ATOM                RegisterChildClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK    ChildProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                 _In_opt_ HINSTANCE hPrevInstance,
                 _In_ LPWSTR    lpCmdLine,
                 _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_RGR, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    /*UnregisterClass(szWindowClass, hInst);
    LoadStringW(hInstance, IDC_RGR, childWindowClass, MAX_LOADSTRING);*/
    RegisterChildClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RGR));

    MSG msg;

    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RGR));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_RGR);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    if (!RegisterClassEx(&wcex)) {
        MessageBox(NULL, L"Error registering MAIN class", L"ERROR", MB_OK); 
        return 0;
    }
}

ATOM RegisterChildClass(HINSTANCE hInstance)
{

    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = ChildProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RGR));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = childWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    if (!RegisterClassEx(&wcex)) {
        MessageBox(NULL, L"Error registering CHILD class", L"ERROR", MB_OK);
        return 0;
    }
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance;

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

    if (!hWnd)
    {
      return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        switch (wmId)
        {
            case IDM_OPEN:
            {
                childWnd = CreateWindow(szWindowClass, L"Save", WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CHILD , 100, 100, 100, 100, hWnd, (HMENU)107, hInst, NULL);

                if (!childWnd)
                {
                    return FALSE;
                }

                ShowWindow(childWnd, 1);
                UpdateWindow(childWnd);
                break;
            }
            case IDM_EXIT:
                DestroyWindow(childWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

我做错了什么?

1 个答案:

答案 0 :(得分:0)

A Window class ...

  

...是系统用作创建窗口的模板的一组属性。

有一个例外( lpszClassName ),WNDCLASSEX结构的所有成员都定义该类窗口的属性。类名用于标识窗口类。这解释为here

  

注册窗口类将窗口过程,类样式和其他类属性与类名相关联。

由于它用作ID,因此在整个过程中类名必须是唯一的。但是,在您的代码中,您尝试注册两个具有相同名称的窗口类(IDC_RGR引用的字符串资源)。第二次调用失败,GetLastError返回1410: ERROR_CLASS_ALREADY_EXISTS ("Class already exists.")

使用这个最小和完整的测试用例可以验证 1

#include <windows.h>

int main() {
    WNDCLASSEXW wcex = { sizeof( wcex ) };
    wcex.lpszClassName = L"TestWindowClass";
    if ( !::RegisterClassExW( &wcex ) ) {
        DWORD dwError = ::GetLastError();
        return dwError;
    }
    if ( !::RegisterClassExW( &wcex ) ) {
        DWORD dwError = ::GetLastError();
        return dwError;
    }
}

解决方案是为进程注册的每个窗口类使用唯一的窗口类名。请注意,您的代码中有很多错误我没有解决(例如CreateWindow调用中的不兼容窗口样式,不匹配的字符编码等)。

<小时/> 1 使用调试器单步执行代码。