Win32 прозрачный полноэкранный режим работает только в том случае, если размер окна превышает рабочий стол

#c #winapi #opengl #dwm

#c #winapi #opengl #dwm ( двм ) #c #dwm

Вопрос:

Я пытаюсь сделать полноэкранное прозрачное окно на рабочем столе, которое я могу отображать с помощью opengl.
Я не хочу переполнять экран, но пока, похоже, это единственный способ, которым я могу. Это довольно грязный взлом imo, и я надеюсь, что кто-нибудь знает о профессиональном решении.

Вот код:

 // libs needed to compile: opengl32 gdi32 dwmapi

#include <windows.h>
#include <GL/gl.h>
#include <dwmapi.h>

HDC hDC;
HGLRC hRC;
HWND hWnd;

bool running=true;

int w=GetSystemMetrics(SM_CXSCREEN),h=GetSystemMetrics(SM_CYSCREEN);

void CreateContext(){
    PIXELFORMATDESCRIPTOR pfd; hDC=GetDC(hWnd);
    SetPixelFormat(hDC,ChoosePixelFormat(hDC,amp;pfd),amp;pfd);
    hRC=wglCreateContext(hDC); wglMakeCurrent(hDC,hRC);
}

void EnableTransparency(){DWM_BLURBEHIND b={DWM_BB_ENABLE|DWM_BB_BLURREGION,TRUE,CreateRectRgn(0,0,-1,-1)}; DwmEnableBlurBehindWindow(hWnd,amp;b);}

LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){
    switch(uMsg){
    case WM_CLOSE: running=false; return 0;
    case WM_KEYDOWN: if(wParam==VK_ESCAPE){running=false;} return 0;
    }return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

void CreateWin(){
    WNDCLASS wc={};
    wc.lpfnWndProc=WndProc;
    wc.hInstance=GetModuleHandle(NULL);
    wc.hCursor=LoadCursor(NULL,IDC_ARROW);
    wc.lpszClassName="OpenGL";
    RegisterClass(amp;wc);

    hWnd = CreateWindow(wc.lpszClassName,"Title",WS_POPUP,0,-1,w,h 1,0,0,wc.hInstance,0); // increasing height by 1 pixel
    ShowWindow(hWnd,SW_SHOW);
    EnableTransparency();
    CreateContext();
}

void PumpMessages(){MSG msg; while(PeekMessage(amp;msg,NULL,0,0,PM_REMOVE))DispatchMessage(amp;msg);}

int main(){
    CreateWin();
    glViewport(0,0,w,h); // the visible screen area (excluding h 1 overflow)
    while(running){
        PumpMessages();
        glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); // fill solid black
        glBegin(GL_TRIANGLES); // transparent triangular window
        glColor4f(1,0,0,0.5f); glVertex3f( 0, 1,0); // red   (center)
        glColor4f(0,1,0,0.5f); glVertex3f(-1,-1,0); // green (left)
        glColor4f(0,0,1,0.5f); glVertex3f( 1,-1,0); // blue  (right)
        glEnd();
        SwapBuffers(hDC);
    }
    return 0;
}
  

Комментарии:

1. Вы должны использовать GetMonitorInfo() для определения размера и положения окна. Как мне переключить окно между обычным и полноэкранным?

2. @zett42 спасибо, но я уже в курсе этого. я ищу ответ только на эту конкретную проблему, которую я упростил для простоты.

3. только что нашел небольшое решение SetWindowRgn(hWnd,CreateRectRgn(0,1,w,h 1),false); , которое не позволит ему проникать за пределы рабочего стола. все еще грязный взлом, но это все, что у меня есть на данный момент.

Ответ №1:

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

 // libs needed to compile: opengl32 gdi32 dwmapi

#include <windows.h>
#include <GL/gl.h>
#include <dwmapi.h>

HDC hDC;
HGLRC hRC;
HWND hWnd;

bool running = true;

int w = GetSystemMetrics(SM_CXSCREEN), h = GetSystemMetrics(SM_CYSCREEN);

void CreateContext() {
  PIXELFORMATDESCRIPTOR pfd; hDC = GetDC(hWnd);
  SetPixelFormat(hDC, ChoosePixelFormat(hDC, amp;pfd), amp;pfd);
  hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC);
}

void EnableTransparency() {
  SetLayeredWindowAttributes(hWnd, NULL, NULL, NULL);
  const MARGINS margins = { -1 };
  DwmExtendFrameIntoClientArea(hWnd, amp;margins);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  switch (uMsg) {
  case WM_CLOSE: running = false; return 0;
  case WM_KEYDOWN: if (wParam == VK_ESCAPE) { running = false; } return 0;
  }return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

void CreateWin() {
  WNDCLASS wc = {};
  wc.lpfnWndProc = WndProc;
  wc.hInstance = GetModuleHandle(NULL);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.lpszClassName = "OpenGL";
  RegisterClass(amp;wc);

  hWnd = CreateWindowEx(WS_EX_LAYERED, wc.lpszClassName, "Title", WS_POPUP, 0, 0, w, h, 0, 0, wc.hInstance, 0);
  ShowWindow(hWnd, SW_SHOW);
  CreateContext();
  EnableTransparency();
}

void PumpMessages() { MSG msg; while (PeekMessage(amp;msg, NULL, 0, 0, PM_REMOVE))DispatchMessage(amp;msg); }

int main() {
  CreateWin();
  glViewport(0, 0, w, h); // the visible screen area
  while (running) {
    PumpMessages();
    glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); // fill solid black
    glBegin(GL_TRIANGLES); // transparent triangular window
    glColor4f(1, 0, 0, 0.5f); glVertex3f(0, 1, 0); // red   (center)
    glColor4f(0, 1, 0, 0.5f); glVertex3f(-1, -1, 0); // green (left)
    glColor4f(0, 0, 1, 0.5f); glVertex3f(1, -1, 0); // blue  (right)
    glEnd();
    SwapBuffers(hDC);
  }
  return 0;
}
  

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

Комментарии:

1. когда я запускаю это, ничего не отображается, но само окно по-прежнему полноэкранное, и вы можете видеть рабочий стол под ним. я снова попробовал свой собственный код выше, и теперь это просто мерцающий прозрачный треугольник на рабочем столе. я пробовал и при реальном размере экрана, и это больше не убирает рабочий стол, но рендеринг по-прежнему испорчен. это довольно запутанно. хотя другой код, который у меня есть, все равно будет искажать изображение при использовании точного разрешения. у вас есть источник примера получше?

2. обновление: я исправил свой пример выше. мне пришлось исправить EnableTransparency (), а также вызвать его перед createContext(). посмотрите, не возникнет ли у вас проблема с обновленным исходным кодом.

3. Ваш пример работает для меня сейчас, и я не вижу разницы, добавляю ли я 1 к высоте окна или нет. Чтобы было понятнее, я получаю сплошное черное окно с цветным прозрачным треугольником, через который я могу видеть. Чего именно вы пытаетесь достичь и в чем проблема, с которой вы столкнулись?

4. он крадет дисплей, так что под ним не отображается рабочий стол. когда вы убрали 1 из высоты, вы также убрали -1 из позиции y? дело не только в том, что это точный размер. он также должен занимать весь экран. (чтобы панель задач исчезла) кроме того, причина, по которой я переместил окно вверх, заключается в том, что окно просмотра находится внизу (поэтому вам не нужно перемещать окно просмотра вниз на 1 пиксель в полноэкранном режиме. потому что это было бы сомнительно)

5. Да, я сделал это, и все работает нормально. Тогда не уверен, что является причиной вашей проблемы.