0

我正在尝试创建一个类似于 Windows UAC 的屏幕储物柜,如本教程中所示。我很难创建背景最大化的窗口,减少光线和桌面的屏幕截图。

这是我到目前为止尝试过的所有代码:

program Project1;

uses
  Winapi.Windows, Winapi.Messages, Vcl.Graphics, Vcl.Forms;

function MainWndProc(hWindow: HWND; Msg: UINT; wParam: wParam;
  lParam: lParam): LRESULT;

var
  ps: TPaintStruct;
  ScreenDC: HDC;
  ScreenHandle: HWnd;
  ScreenBitmap: TBitmap;

begin
  Result := 0;

  case Msg of

    WM_PAINT:

    begin
        BeginPaint(hWindow, ps);

        ScreenHandle := GetDeskTopWindow;
        ScreenDC := GetDC(ScreenHandle);
        try
          ScreenBitmap := TBitMap.Create;
          try
            ScreenBitmap.Width := Screen.Width;
            ScreenBitmap.Height := Screen.Height;
            BitBlt(ScreenBitmap.Canvas.Handle, 0, 0,
                Screen.Width, Screen.Height, ScreenDC, 0, 0, SRCCOPY);
          finally
            ScreenBitmap.Free
          end
        finally
          ReleaseDC(ScreenHandle, ScreenDC)
        end;

        EndPaint(hWindow, ps);
      end;
    WM_DESTROY: PostQuitMessage(0);
    else
      begin
        Result := DefWindowProc(hWindow, Msg, wParam, lParam);
        Exit;
      end;
  end;
end;

var
  wc: TWndClass;
  hWindow: HWND;
  Msg: TMsg;
begin
  wc.lpszClassName := 'App';
  wc.lpfnWndProc   := @MainWndProc;
  wc.Style         := CS_VREDRAW or CS_HREDRAW;
  wc.hInstance     := hInstance;
  wc.hIcon         := LoadIcon(0, IDI_APPLICATION);
  wc.hCursor       := LoadCursor(0, IDC_ARROW);
  wc.hbrBackground := (COLOR_WINDOW + 1);
  wc.lpszMenuName  := nil;
  wc.cbClsExtra    := 0;
  wc.cbWndExtra    := 0;
  RegisterClass(wc);
  hWindow := CreateWindowEx(WS_EX_CONTROLPARENT or WS_EX_WINDOWEDGE,
    'AppClass',
    'CREATE_WND',
    WS_VISIBLE or WS_CLIPSIBLINGS or
    WS_CLIPCHILDREN or WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, 0,
    400, 300,
    0,
    0,
    hInstance,
    nil);

  ShowWindow(hWindow, CmdShow);
  UpDateWindow(hWindow);

  while GetMessage(Msg, 0, 0, 0) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
  Halt(Msg.wParam);
end.
4

1 回答 1

0

创建背景最大化窗口 - 非常简单

CreateWindowExW(WS_EX_TOPMOST, L"myclassname", 0, WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), HWND_DESKTOP, 0, (HINSTANCE)&__ImageBase, this);

我们WM_NCCREATE需要捕获屏幕

//HDC _hDC; - class member
//HGDIOBJ _o;

BOOL Capture()
{
    BOOL fOk = FALSE;

    if (HDC hdc = GetDC(HWND_DESKTOP))
    {
        if (_hDC = CreateCompatibleDC(hdc))
        {
            int cx = GetSystemMetrics(SM_CXSCREEN), cy = GetSystemMetrics(SM_CYSCREEN);
            if (HBITMAP hbmp = CreateCompatibleBitmap(hdc, cx, cy))
            {
                _o = SelectObject(_hDC, hbmp);

                static BLENDFUNCTION bf = { AC_SRC_OVER, 0, 0x80, AC_SRC_ALPHA };// 0x80 -> 50%

                fOk = AlphaBlend(_hDC, 0, 0, cx, cy, hdc, 0, 0, cx, cy, bf);
            }
        }
        ReleaseDC(HWND_DESKTOP, hdc);
    }
    return fOk;
}

WindowProc 简单就够了

LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_NCDESTROY:
        if (_hDC)
        {
            if (_o)
            {
                DeleteObject(SelectObject(_hDC, _o));
            }
            DeleteDC(_hDC);
        }
        //Release();
        break;
    case WM_NCCREATE:
        //AddRef();
        if (!Capture()) return FALSE;
        break;
    case WM_CLOSE:
        return 0;// prevent from close
    case WM_ERASEBKGND:
        return TRUE;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            if (BeginPaint(hwnd, &ps))
            {
                BitBlt(ps.hdc, 
                    ps.rcPaint.left, ps.rcPaint.top,
                    ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top,
                    _hDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                EndPaint(hwnd, &ps);
            }
        }
        break;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

static LRESULT CALLBACK _WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CScreenLocker* This;
    if (uMsg == WM_NCCREATE)
    {
        This = reinterpret_cast<CScreenLocker*>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
        SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(This));
    }
    else
    {
        This = reinterpret_cast<CScreenLocker*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
    }

    if (This)
    {
        //This->AddRef();
        LRESULT r = This->WindowProc(hwnd, uMsg, wParam, lParam);
        //This->Release();
        return r;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

然后,在您创建背景最大化窗口 - hwnd 后,需要创建以 hwnd 作为父级的对话框。说

    ShowWindow(hwnd, SW_SHOW);
    MessageBoxW(hwnd,...);
    DestroyWindow(hwnd);
于 2016-11-29T11:42:47.783 回答