我正在尝试创建一个简单的窗口,但是由于某种原因它无法正常工作。在过去的几个月中,我实际上已经尝试过了。甚至使用了一些旧代码,无论出于何种原因,它都根本无法运行。
实际上,registerclass函数从不返回任何东西,但这也发生在过去,但是我仍然能够创建一个窗口。这次没有任何作用
我尝试过:
这是我的代码:
WNDCLASSEXW lpClass = WNDCLASSEXW{ 0x00 };
lpClass.cbSize = sizeof(decltype(lpClass));
lpClass.style = (CS_HREDRAW | CS_VREDRAW);
lpClass.lpfnWndProc = ScreenProcess;
lpClass.hInstance = GetModuleHandleW(nullptr);
lpClass.lpszClassName = L"__TEST__";
lpClass.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
RegisterClassExW(&lpClass);
if (HWND hwnd = CreateWindowExW(WS_EX_APPWINDOW, lpClass.lpszClassName, L"abc", WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, nullptr, nullptr, lpClass.hInstance, nullptr))
{
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
}
printf("%d", GetLastError());
for (;;) {};
答案 0 :(得分:2)
您是否将窗口过程定义为这样?
LRESULT CALLBACK ScreenProcess(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
而不是无限循环,将其放置:
MSG msg{0};
while(GetMessage(&msg, nullptr, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
此外,cbSize
中的WNDCLASSEXW
应该是sizeof(WNDCLASSEXW)
。同时将CreateSolidBrush(RGB(0, 0, 0));
更改为GetStockObject(BLACK_BRUSH);
希望这会有所帮助!
答案 1 :(得分:1)
这是在VS2017中运行的代码版本(使用C ++ 17)。我添加了调试打印,以便您可以看到ScreenProcess()
收到鼠标移动等信息。我还添加了一个类(WindowsClassRegistrator
),用于处理您分配的资源之一,以展示如何扩展资源。现有的C结构可自动处理资源释放。
我在常见的Windows消息及其宏名称之间添加了一个映射,以使您更容易了解您实际进入WndProc
的内容。当您单击应用程序上的关闭按钮(在任务栏上)时,将收集并显示未知的Windows消息,以便您可以随时扩展要处理/显示的消息。
我还添加了断言函数模板,用于抛出带有适当错误消息的异常,您可以在所有WinAPI函数中使用它们,这些函数可以轻松地检查它们是否成功。
#include "pch.h" // if you use precompiled headers
#include <Windows.h>
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <Olectl.h> // OCM_BASE
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <stdexcept>
#include <map>
#include <unordered_set>
// --- bug hunting support functions start ---
std::string GetLastErrorString() {
DWORD le = GetLastError();
LPSTR lpBuffer = nullptr;
if (FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
0, le, 0,
reinterpret_cast<LPSTR>(&lpBuffer),
0, NULL
))
{
std::string rv(lpBuffer);
LocalFree(lpBuffer);
return rv;
}
else return std::to_string(le);
}
struct win_error : public std::runtime_error {
win_error(const std::string& prefix) :
std::runtime_error(prefix + ": " + GetLastErrorString())
{}
};
// assert that a function does NOT return a specific value
template<typename T>
inline T AssertNEQ(T value, const char* funcname, T got_value) {
if (value == got_value) throw win_error(funcname);
return got_value;
}
// assert that a function DOES return a specific value
template<typename T>
inline T AssertEQ(T value, const char* funcname, T got_value) {
if (value != got_value) throw win_error(funcname);
return got_value;
}
// --- bug hunting support functions end ---
class WindowsClassRegistrator : public WNDCLASSEXW {
ATOM wca;
public:
WindowsClassRegistrator(WNDPROC lpfnWndProc) :
WNDCLASSEXW{ 0 }, wca{}
{
this->cbSize = sizeof(WNDCLASSEXW);
this->style = CS_SAVEBITS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
this->lpfnWndProc = lpfnWndProc;
this->hInstance =
AssertNEQ<HMODULE>(NULL, "GetModuleHandleW", GetModuleHandleW(nullptr));
this->lpszClassName = L"__TEST__";
this->hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
this->wca =
AssertNEQ<ATOM>(NULL, "RegisterClassExW", RegisterClassExW(this));
}
WindowsClassRegistrator(const WindowsClassRegistrator&) = delete;
WindowsClassRegistrator(WindowsClassRegistrator&&) = delete;
WindowsClassRegistrator& operator=(const WindowsClassRegistrator&) = delete;
WindowsClassRegistrator& operator=(WindowsClassRegistrator&&) = delete;
~WindowsClassRegistrator() {
AssertNEQ<BOOL>(FALSE,
"UnregisterClassW", UnregisterClassW(GetAtomAsStr(), this->hInstance));
}
inline LPCWSTR GetAtomAsStr() const noexcept {
return reinterpret_cast<LPCWSTR>(this->wca);
}
inline HINSTANCE GetInstance() const noexcept {
return this->hInstance;
}
inline LPCWSTR GetClassName() const noexcept {
return this->lpszClassName;
}
};
std::multimap<UINT, std::string> messages = {
{WM_NULL, "WM_NULL"},
{WM_CREATE, "WM_CREATE"},
{WM_DESTROY, "WM_DESTROY"},
{WM_MOVE, "WM_MOVE"},
{WM_SIZE, "WM_SIZE"},
{WM_ACTIVATE, "WM_ACTIVATE"},
{WM_SETFOCUS, "WM_SETFOCUS"},
{WM_KILLFOCUS, "WM_KILLFOCUS"},
{WM_PAINT, "WM_PAINT"},
{WM_CLOSE, "WM_CLOSE"},
{WM_QUIT, "WM_QUIT"},
{WM_ERASEBKGND, "WM_ERASEBKGND"},
{WM_SHOWWINDOW, "WM_SHOWWINDOW"},
{WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
{WM_CANCELMODE, "WM_CANCELMODE"},
{WM_SETCURSOR, "WM_SETCURSOR"},
{WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE"},
{WM_VKEYTOITEM, "WM_VKEYTOITEM"},
{WM_CHARTOITEM, "WM_CHARTOITEM"},
{WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
{WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
{SPI_SETDRAGHEIGHT, "SPI_SETDRAGHEIGHT"},
{WM_HELP, "WM_HELP"},
{WM_CONTEXTMENU, "WM_CONTEXTMENU"},
{WM_GETICON, "WM_GETICON"},
{WM_NCCREATE, "WM_NCCREATE"},
{WM_NCDESTROY, "WM_NCDESTROY"},
{WM_NCCALCSIZE, "WM_NCCALCSIZE"},
{WM_NCHITTEST, "WM_NCHITTEST"},
{WM_NCPAINT, "WM_NCPAINT"},
{WM_NCACTIVATE, "WM_NCACTIVATE"},
{SPI_GETDOCKMOVING, "SPI_GETDOCKMOVING"},
{WM_KEYDOWN, "WM_KEYDOWN"},
{WM_KEYUP, "WM_KEYUP"},
{WM_CHAR, "WM_CHAR"},
{WM_SYSKEYDOWN, "WM_SYSKEYDOWN"},
{WM_SYSKEYUP, "WM_SYSKEYUP"},
{WM_SYSCHAR, "WM_SYSCHAR"},
{WM_SYSCOMMAND, "WM_SYSCOMMAND"},
{WM_MOUSEMOVE, "WM_MOUSEMOVE"},
{WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
{WM_LBUTTONUP, "WM_LBUTTONUP"},
{WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK"},
{WM_RBUTTONDOWN, "WM_RBUTTONDOWN"},
{WM_RBUTTONUP, "WM_RBUTTONUP"},
{WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK"},
{WM_MBUTTONDOWN, "WM_MBUTTONDOWN"},
{WM_MBUTTONUP, "WM_MBUTTONUP"},
{WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK"},
{WM_MOUSEWHEEL, "WM_MOUSEWHEEL"},
{WM_XBUTTONDOWN, "WM_XBUTTONDOWN"},
{WM_XBUTTONUP, "WM_XBUTTONUP"},
{WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT"},
{WM_IME_NOTIFY, "WM_IME_NOTIFY"},
{WM_HOTKEY, "WM_HOTKEY"},
{0x0313, ": https://stackoverflow.com/questions/10430377/winapi-undocumented-windows-message-0x0313-stable"},
{WM_PRINT, "WM_PRINT"},
{WM_APPCOMMAND, "WM_APPCOMMAND"},
};
std::unordered_set<UINT> unmapped_messages;
std::map<WPARAM, std::string> mk_down = {
{MK_CONTROL, "MK_CONTROL"},
{MK_LBUTTON,"MK_LBUTTON"},
{MK_MBUTTON,"MK_MBUTTON"},
{MK_RBUTTON,"MK_RBUTTON"},
{MK_SHIFT,"MK_SHIFT"},
{MK_XBUTTON1,"MK_XBUTTON1"},
{MK_XBUTTON2,"MK_XBUTTON2"}
};
constexpr int colw = 40;
std::string message_maker(const char* macro, UINT uMsg, UINT offset) {
std::stringstream ss;
ss << macro << " + " << std::hex << (uMsg - offset) << " (" << uMsg << ")";
return ss.str();
}
inline void DisplayMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) {
std::string message;
if (uMsg < WM_USER) {
// there may be duplicate macros for some messages, so show all of them
auto[rangefirst, rangelast] = messages.equal_range(uMsg);
if (rangefirst == rangelast) {
// unmapped message found, store it
unmapped_messages.emplace(uMsg);
rangefirst = messages.emplace(uMsg, ": " + std::to_string(uMsg) + " -- UNMAPPED MESSAGE");
rangelast = rangefirst;
++rangelast;
}
message = rangefirst->second;
while (++rangefirst != rangelast) message += " " + rangefirst->second;
}
else {
// https://docs.microsoft.com/en-us/windows/desktop/winmsg/ocm--base
#define REGISTERED_WINDOWS_MESSAGE_BASE (0xC000)
#define SYSRESERVED_BASE (0x10000)
if (uMsg < OCM__BASE)
message = message_maker("WM_USER", uMsg, WM_USER);
else if (uMsg < WM_APP)
message = message_maker("(WM_USER) OCM__BASE", uMsg, OCM__BASE);
else if (uMsg < REGISTERED_WINDOWS_MESSAGE_BASE)
message = message_maker("WM_APP", uMsg, WM_APP);
else if (uMsg < SYSRESERVED_BASE)
message = message_maker("Registered Window Message", uMsg, REGISTERED_WINDOWS_MESSAGE_BASE);
else
message = message_maker("Reserved by the system", uMsg, SYSRESERVED_BASE);
}
std::cout << std::setw(colw) << std::hex << message << std::setw(18) << wParam
<< std::setw(12) << lParam << "\n";
}
LRESULT CALLBACK ScreenProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static std::string old_mouse_message;
switch (uMsg) {
case WM_MOUSEMOVE:
{
std::stringstream ss;
std::string new_mouse_message;
int xPos, yPos;
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
ss << std::setw(colw) << "WM_MOUSEMOVE" << std::dec
<< " x=" << std::setw(6) << xPos << " y=" << std::setw(6) << yPos;
for (auto&[wp, key] : mk_down)
if (wp&wParam) ss << " " << key;
new_mouse_message = ss.str();
if (new_mouse_message != old_mouse_message) {
std::cout << new_mouse_message << "\n";
old_mouse_message = std::move(new_mouse_message);
}
}
return 0;
case WM_NCHITTEST:
return HTCLIENT;
case WM_SETCURSOR:
return TRUE;
case WM_DESTROY:
std::cout << std::setw(colw) << "WM_DESTROY" << " ";
PostQuitMessage(0);
std::cout << "PostQuitMessage() done\n";
return 0;
default:
DisplayMsg(uMsg, wParam, lParam);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int main() {
try {
WindowsClassRegistrator wcr(ScreenProcess);
// use WS_VISIBLE so that you don't have to call ShowWindow()
HWND hWnd =
AssertNEQ<HWND>(NULL, "CreateWindowExW",
CreateWindowExW(
WS_EX_APPWINDOW,
wcr.GetAtomAsStr(),
L"Title string",
WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
0, // width
0, // height
nullptr,
nullptr,
wcr.GetInstance(),
nullptr
)
);
MONITORINFO mi = { sizeof(mi) }; // mi.cbSize = sizeof(mi);
AssertNEQ<BOOL>(FALSE, "GetMonitorInfo",
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), &mi)
);
AssertNEQ<BOOL>(FALSE, "SetWindowPos",
SetWindowPos(hWnd, HWND_TOP,
mi.rcMonitor.left, mi.rcMonitor.top,
(mi.rcMonitor.right - mi.rcMonitor.left) / 4, // 1/4 of the screen width
(mi.rcMonitor.bottom - mi.rcMonitor.top), // height
SWP_NOOWNERZORDER | SWP_FRAMECHANGED)
);
// paint a rectangle in the window
AssertNEQ<BOOL>(FALSE, "Rectangle", Rectangle(
AssertNEQ<HDC>(NULL, "GetDC", GetDC(hWnd)),
10, 10, 100, 100)
);
MSG uMsg;
while (AssertNEQ<BOOL>(-1, "GetMessage", GetMessage(&uMsg, nullptr, 0, 0))) {
TranslateMessage(&uMsg); // assertion would depend on message type
DispatchMessage(&uMsg); // assertion would depend on message type
}
DisplayMsg(uMsg.message, uMsg.wParam, uMsg.lParam); // WM_QUIT
if (unmapped_messages.size()) {
std::cout << "\nYou have collected unmapped messages: \n";
for (const auto&[msg, text] : messages) {
std::cout << "/* 0x" << std::setw(4) << std::setfill('0') << msg << " */ ";
if (unmapped_messages.count(msg) || text[0] == ':') {
std::cout << "{0x" << std::setw(4) << std::setfill('0') << msg;
}
else {
std::cout << "{" << text;
}
std::cout << ", \"" << text << "\"},\n";
}
}
return static_cast<int>(uMsg.wParam);
}
catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << "\n";
}
return 1;
} // the registered windows class will be unregistered here, when wcr goes out of
// scope
答案 2 :(得分:0)
这是Visual Studio为您生成的默认Win32项目模板的修改后的单一源文件版本。我刚刚删除了与资源,加速器,菜单和“关于”框有关的内容。
#include <windows.h>
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[] = L"Test App"; // The title bar text
WCHAR szWindowClass[] = L"__TestAppWindowClass__"; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(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);
// TODO: Place code here.
// Initialize global strings
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex = { 0 };
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(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = szWindowClass;
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
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;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}