Win32透明全屏仅在窗口大小溢出桌面时才有效

时间:2019-04-05 06:39:34

标签: c++ winapi opengl dwm

我正在尝试在桌面上制作一个全屏透明窗口,以便可以使用opengl进行渲染。
我不想让屏幕溢出,但到目前为止,这似乎是我唯一的方法。这是一个非常肮脏的hack 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,&pfd),&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,&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(&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(&msg,NULL,0,0,PM_REMOVE))DispatchMessage(&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 个答案:

答案 0 :(得分:0)

在运行代码时,实际上并没有任何透明度,因此我无法理解为什么需要使屏幕溢出。但是,这就是我如何更改您的代码以使其对我有用,而又不会溢出屏幕的方式。

// 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, &pfd), &pfd);
  hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC);
}

void EnableTransparency() {
  SetLayeredWindowAttributes(hWnd, NULL, NULL, NULL);
  const MARGINS margins = { -1 };
  DwmExtendFrameIntoClientArea(hWnd, &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(&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(&msg, NULL, 0, 0, PM_REMOVE))DispatchMessage(&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,因为我们没有使用任何这些分层的窗口功能,但是我们需要调用该函数以使窗口可见。