0

I'm trying to create a screen locker, similar to Windows UAC, like shown in this tutorial. I am having difficulty creating the background maximized window, with reduced light, and a screenshot of the desktop.

Here is all the code I have tried so far:

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.
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 4
    Unless you are also creating a custom desktop like UAC does, then the easiest approach would be to simply create a full screen borderless captionless `TForm` that has a solid black background and a non-opaque `AlphaBlendValue`, show that window first, and then show your actual dialog on top of it. Close both window when done. No need to grab a screenshot of the desktop window at all. – Remy Lebeau Nov 29 '16 at 02:20
  • @RemyLebeau, i'm trying make something similar to [this software](http://image.prntscr.com/image/d7657864b8074633b36e39f5ecfece6f.png) where gray area is my background and GUI interface is my window dialog. –  Nov 29 '16 at 02:50
  • What difficulty are you having? What does your code do, and what do you want it to do instead? – Rob Kennedy Nov 29 '16 at 03:25
  • Difficulty creating the background maximized window, with reduced light, and a screenshot of the desktop for background maximized window. –  Nov 29 '16 at 04:40
  • 1
    Two advises... First, be specific with your problem description. What you have answered Rob with is what you are trying to achieve in general, not the immediate problem you observe. You should have replied with, f.i., I don't see any window created (considering you don't know how to debug for now. When you learn it, you could be even more specific). – Sertac Akyuz Nov 29 '16 at 17:09
  • 1
    Second, start checking for errors. Step by step.. The first API you call is `CreateWindowEx`. Refer to its documentation, learn how you can check for an error condition. Once you do that, you'll find out it complains with `ERROR_CANNOT_FIND_WND_CLASS`. Then refer to the function's documentation again to see what could it mean. Etc.. – Sertac Akyuz Nov 29 '16 at 17:10

1 Answers1

0

creating the background maximized window - very easy

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

on WM_NCCREATE we need capture screen

//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 can be enough simply

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);
}

then, after you create background maximized window - hwnd, need create dialog with hwnd as parent. say

    ShowWindow(hwnd, SW_SHOW);
    MessageBoxW(hwnd,...);
    DestroyWindow(hwnd);
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • i'm needing of a `Delphi` example. How could be `HGDIOBJ` in Delphi? –  Nov 29 '16 at 13:01
  • @Saulo - `HGDIOBJ` is pointer size. this of course not Delphi code, but show general conception – RbMm Nov 29 '16 at 13:09
  • i understood this ideia, but not know "translate this code above to Delphi". I don't understand practically nothing about these variable types in C++ where could find something similar in Delphi. If someone here can help me with this code above, thank you. –  Nov 29 '16 at 14:03