Is there a known issue with MapWindowPoints() function?

Gaurab Das 0 Reputation points
2024-09-19T11:49:01.1933333+00:00

Hello team,

I'm running an application on a multi-monitor setup, one laptop and one monitor (both having 1920x1080 resolution), wherein monitor has been set as Main Display. The scaling on my monitor is 125% and laptop is 150%.

My application uses BitBlt() function to dynamically draw a horizontal black bar onto the screen, when user drags a splitter, up and down, present at the bottom of the screen. The black bar moves along with the mouse and gives user the idea about the new position where the splitter will be extended to.

The coordinates passed to BitBlt() function are retrieved from MapWindowPoints() function, which is then scaled by Scaling Factor of the monitor where app is running to get correct coordinates. But, for some reason, MapWindowPoints() is not returning expected coordinates and thus, the coordinates after scaling are also wrong and, the black bar is drawn at the wrong position (X-coordinate is messed up, Y-coordinate is correct).

Please note that, this issue is happening at only one specific use-case when scaling on one display is strictly higher than the scaling on Main Display (either laptop or monitor). In all remaining possible use-cases (when using just one display, or scaling on one display is less or equal to Main Display), it is working fine.

(By working fine, I mean black bar is drawn on top of splitter when we click on the splitter initially and moves along with the mouse).I'm attaching (Delphi) code below for reference -

function ToxCustomSplit.GetScaleFactorOfMonitor(): Double;
var
  OldContext: DPI_AWARENESS_CONTEXT;
  MonitorHandle: HMONITOR;
  DPI_X, DPI_Y: UINT;
begin
  OldContext := SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);

  MonitorHandle := Application.MainForm.Monitor.Handle;
  GetDpiForMonitor(monitorHandle, MDT_EFFECTIVE_DPI, DPI_X, DPI_Y);
  
  SetThreadDpiAwarenessContext(oldContext);

  Result := DPI_X / 96.0;
end;

function ToxCustomSplit.ClientToScreen(const Point: TPoint): TPoint;
var
  ScaleFactor: Double;
begin
  Result := Point;
  winapi.windows.MapWindowPoints(Handle,0,Result,1);

  ScaleFactor := GetScaleFactorOfMonitor();
  Result.X := Round(Result.X * ScaleFactor);
  Result.Y := Round(Result.Y * ScaleFactor);
end;

procedure ToxCustomSplit.PaintBar;
var
  MyDC: HDC;
  MyPoint, BlankPoint: TPoint;
  ScaleFactor: Double;
begin
  if GetAutoUpdate then
    exit;
  MyDC := GetDC(0);

  MyPoint.X := 0;
  MyPoint.Y := 0;
  BlankPoint.X := 0;
  BlankPoint.Y := 0;

  if FDirection < 1 then
    MyPoint.X := FNewPos.X - FOffSet.X;
  if FDirection > -1 then
    MyPoint.Y := FNewPos.Y - FOffSet.Y;

  MyPoint := ClientToScreen(MyPoint);
  BlankPoint := ClientToScreen(BlankPoint);

  ScaleFactor := GetScaleFactorOfMonitor();
  if FDirection < 1 then
    BitBlt(MyDC, MyPoint.X, BlankPoint.Y + VBarRect.top, FBarWidth, VBarRect.bottom - VBarRect.top, 0, 0, 0, DSTINVERT);
  if FDirection > -1 then
    BitBlt(MyDC, BlankPoint.X + Round(HBarRect.left*ScaleFactor), MyPoint.Y, Round((HBarRect.right - HBarRect.left)*ScaleFactor), FBarWidth, 0, 0, 0, DSTINVERT);

  ReleaseDC(0, MyDC);
end;

Please let me know if there's an issue with MapWindowPoints() function itself, or is something wrong with my code.

Thanks.

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,592 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.