Top.Mail.Ru
Ответы

Помогите пожалуйста с кодом C++ который создает окно на Windows.

Хочу создать окно самое обычное но без заголовка окна. Тень и рамка быть должны а вот заголовка у окна быть не должно. При этом в панели задач в миниатюре этого окна и заголовочное имя окна и иконка и крестик быть должны. Помогите пожалуйста я бьюсь с этим blYat простите безумные 7 часов в поисках такой возможности. Может кто написать код как пример? Сил нет уже

По дате
По рейтингу
Аватар пользователя
1мес

Понимаю твою боль, сам в свое время убил кучу времени на эту виндовс апи. Чтобы убрать заголовок но оставить стандартную тень и рамку, тебе нужно убрать стиль WS_CAPTION, но обязательно оставить WS_THICKFRAME и WS_SYSMENU, а затем в WM_NCCALCSIZE вернуть ноль. Вот рабочий пример самого скелета окна:

C++

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

if (uMsg == WM_NCCALCSIZE && wParam == TRUE) {

return 0;

}

if (uMsg == WM_DESTROY) {

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {

const wchar_t CLASS_NAME[] = L"SampleWindowClass";

WNDCLASS wc = {};

wc.lpfnWndProc = WindowProc;

wc.hInstance = hInstance;

wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

HWND hwnd = CreateWindowEx(

WS_EX_APPWINDOW,

CLASS_NAME,

L"Мое окно",

WS_OVERLAPPEDWINDOW & ~WS_CAPTION,

CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,

NULL, NULL, hInstance, NULL

);

ShowWindow(hwnd, nCmdShow);

MSG msg = {};

while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return 0;

}

Иконка и крестик в миниатюре панели задач тут сохраняются корректно за счет системного меню и правильных стилей. Пробуй, должно заработать.

Аватар пользователя
melee_31Тролль
1мес

Вот готовый, полностью рабочий пример кода на C++ (чистый Win32 API), который делает ровно то, что вы хотите. Создается окно без заголовка, но с нативной тенью, изменяемым размером (если захотите) и полным функционалом в панели задач:

C++

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
#include <windows.h>
#include <dwmapi.h>

#pragma comment(lib, "dwmapi.lib")

// Оконная процедура
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_NCCALCSIZE: {
        // ЭТО ГЛАВНЫЙ СЕКРЕТ:
        // Когда wParam == TRUE, мы возвращаем 0, тем самым заявляем системе,
        // что вся клиентская область окна равна размеру всего окна (включая область заголовка).
        // Система думает, что заголовка нет, но при этом сохраняет тень и рамку!
        if (wParam == TRUE) {
            // Если вы хотите, чтобы окно вообще не имело отступов рамки при изменении размера,
            // просто возвращаем 0. Рамка и тень останутся благодаря стилям окна.
            return 0;
        }
        break;
    }

    case WM_NCHITTEST: {
        // Так как мы убрали заголовок, окно теперь нельзя двигать за шапку.
        // Этот блок возвращает системе команду, что зажатие ЛКМ в верхней части окна
        // означает "перетаскивание окна" (HTCAPTION).
        // Сделайте область захвата сверху в 30 пикселей, чтобы можно было таскать за верх.
        POINT pt = { LOWORD(lParam), HIWORD(lParam) };
        ScreenToClient(hwnd, &pt);

        RECT rcClient;
        GetClientRect(hwnd, &rcClient);

        // Если курсор в верхней части окна (первые 35 пикселей) — позволяем таскать окно
        if (pt.y < 35 && pt.x > 35 && pt.x < rcClient.right - 35) {
            return HTCAPTION;
        }
        
        // Тут же можно добавить изменение размеров за края, если нужен стиль WS_THICKFRAME
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    case WM_CLOSE:
        DestroyWindow(hwnd);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    const wchar_t CLASS_NAME[] = L"BorderlessShadowWindowCls";

    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = CLASS_NAME;
    wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); // Иконка для панели задач
    wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);

    RegisterClassEx(&wc);

    // ВНИМАНИЕ НА СТИЛИ:
    // WS_POPUP или WS_OVERLAPPEDWINDOW с добавлением WS_THICKFRAME / WS_MAXIMIZEBOX / WS_MINIMIZEBOX.
    // Нам нужен стиль WS_THICKFRAME (или WS_DLGFRAME), чтобы DWM понимал, что у окна есть рамка и тень,
    // но стандартную шапку мы убираем через WM_NCCALCSIZE.
    DWORD style = WS_OVERLAPPEDWINDOW; 
    // Убираем WS_CAPTION, чтобы шапка исчезла физически, но оставляем рамку/тень
    style &= ~WS_CAPTION; 

    HWND hwnd = CreateWindowEx(
        0,                              // Дополнительные стили
        CLASS_NAME,                     // Имя класса
        L"Мое крутое окно без шапки",   // Заголовок (отображается в панели задач и миниатюре!)
        style,                          // Стили окна
        CW_USEDEFAULT, CW_USEDEFAULT,   // Положение X, Y
        800, 600,                       // Ширина, Высота
        nullptr,                        // Родительское окно
        nullptr,                        // Меню
        hInstance,                      // Приложение
        nullptr                         // Доп. параметры
    );

    if (hwnd == nullptr) {
        return 0;
    }

    // Дополнительно страхуем отрисовку тени на Windows 10/11
    MARGINS margins = { 1, 1, 1, 1 };
    DwmExtendFrameIntoClientArea(hwnd, &margins);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Цикл сообщений
    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

Что здесь происходит и почему это работает:

  1. Имя и иконка в панели задач: Задаются стандартным путем в функции CreateWindowEx (передачей текста L"Мое крутое окно без шапки") и структуре WNDCLASSEX (иконки hIcon). Поскольку мы используем стили винды (просто без шапки), ДWM и проводник Windows видят это окно как полноценное приложение: с крестиком при наведении на иконку в панели задач, миниатюрой и правильным именем.

  2. Тень и рамка: Достигаются за счет того, что мы оставляем системе системные рамки (WS_OVERLAPPEDWINDOW минус WS_CAPTION), но в сообщении WM_NCCALCSIZE «обманываем» Windows, заставляя её считать, что область заголовка имеет нулевую высоту. Рамка и тень от DWM остаются на месте, а серой шапки с кнопками свернуть/закрыть сверху больше нет.

  3. Как его двигать: Так как шапку мы стерли, зажать мышку и потащить окно не за что. В коде выше в обработчике WM_NCHITTEST прописано: если зажать левую кнопку мыши в верхней части окна (в пределах 35 пикселей), система думает, что вы держитесь за заголовок, и позволяет таскать окно по экрану.

Аватар пользователя
salty_6018Ученик
1мес

#include <windows.h>

#include <dwmapi.h>

#pragma comment(lib, "dwmapi.lib")

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

switch (uMsg) {

case WM_CREATE: {

// Включаем тень Aero/DWM для окна с кастомной неклиентской областью

MARGINS margins = { 0, 0, 0, 0 };

DwmExtendFrameIntoClientArea(hwnd, &margins);

// Принудительно обновляем рамки окна

SetWindowPos(hwnd, NULL, 0, 0, 0, 0,

SWP_ACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);

return 0;

}

case WM_NCCALCSIZE: {

// Если wParam == TRUE, мы сообщаем Windows, что клиентская область

// занимает всё окно, тем самым скрывая стандартный заголовок (WS_CAPTION).

if (wParam == TRUE) {

return 0;

}

break;

}

case WM_NCHITTEST: {

// Позволяет перетаскивать окно за любую его часть,

// так как стандартного заголовка больше нет

LRESULT hit = DefWindowProc(hwnd, uMsg, wParam, lParam);

if (hit == HTCLIENT) {

return HTCAPTION;

}

return hit;

}

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

const wchar_t CLASS_NAME[] = L"NoCaptionWindowClass";

WNDCLASS wc = { 0 };

wc.lpfnWndProc = WindowProc;

wc.hInstance = hInstance;

wc.lpszClassName = CLASS_NAME;

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

// Загрузите здесь вашу иконку, чтобы она отображалась в панели задач и миниатюре:

// wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_YOUR_ICON));

RegisterClass(&wc);

// Важно: оставляем WS_OVERLAPPEDWINDOW, чтобы Windows сгенерировала

// полноценную миниатюру в панели задач с заголовком и иконкой

HWND hwnd = CreateWindowEx(

0,

CLASS_NAME,

L"Имя окна для панели задач", // Это имя будет видно в миниатюре

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,

NULL,

NULL,

hInstance,

NULL

);

if (hwnd == NULL) {

return 0;

}

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

MSG msg = { 0 };

while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return 0;

}



Видео по теме