0

I need to get the desktop resolution from a Delphi program.
However, if the program is not DPI aware Windows will lie about the real screen resolution so all kind of problems will rise from here.

Since it is too much work to make the program fully DPI aware (and I try to AVOID the WMI solution) I am thinking using a quick dirty trick: I will create a microscopic DPI-aware console program that will read the real resolution.

The main program will use start this little program (hidden) every time it needs the resolution. Seems simple enough to do. Right?

Question 1: Do I have another (better) option?
Question 2: I tried to create that little program. Although is has something like 10 lines of code its EXE size is 2.1MB and its memory footprint is 5.4MB! Can I make it smaller? If the program is small enough (under 1MB RAM) I could leave it run all the time without pissing off the users.

Community
  • 1
  • 1
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • One solution would be the WMI thing but WMI is not available is all Windows computers. – Gabriel Oct 28 '15 at 17:31
  • I read it as the same, including mentioning writing a small utility. Sorry if you didn't make the difference clear. It's not *bullying*, and it's not *crap*. It's users who write very similar questions without clarifying why they're different clearly. Don't blame me if you didn't do your job of making the differences plain. – Ken White Oct 28 '15 at 17:50
  • 1
    I'm not sure why you're insisting on being rude and agressive here. First, you don't have the right to tell anyone to *stay away* - when you post here it's available to everyone to answer, edit, or vote to close. Don't like it? Don't post. Second, I wasn't *rude*. You posted what appeared to be a duplicate question, and I closed it as such; it's been reopened. Quit whining. Third, I've provided thousands of decent answers here, as you can see in my profile.If you don't want your questions closed, write better questions. If you don't want them edited, write better questions. – Ken White Oct 28 '15 at 17:57

2 Answers2

2

Question 1: Do I have another (better) option?

You can use WMI as per your earlier question: How to obtain the real screen resolution in a High DPI system?

Question 2: I tried to create that little program. Although is has something like 10 lines of code its EXE size is 2.1MB and its memory footprint is 5.4MB! Can I make it smaller?

The trick is to avoid using any VCL units, and minimising the number of RTL units that you use. Your goal should be to use the Windows unit only. Or even avoid it and create your own Windows API imports for just the functions that you need.

Another option would be to create this program with a different programming language, one that was better able to remove dead code. I'd probably do this with a short C program.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks David - I know about your previous answer - the one related to wmi. But if possible I try to avoid WMI. A large percent of the Windows computers will not have WMI properly working or will not have WMI at all. The second problem is the cross-platform compatibility. I am weighting both possibilities now (WMI vs external 'DOS' helper application) – Gabriel Oct 28 '15 at 17:51
  • 1
    There's no DOS here. A console app is a Windows program not a DOS program. Doesn't have to be a console app. Can be a GUI app that doesn't show GUI. After all, why make a console you don't need. Cross platform is not pertinent since DPI awareness is a Windows specific thing. I've personally never encountered a machine without WMI, but clearly you know your target machines. – David Heffernan Oct 28 '15 at 17:59
  • I know. It was a joke. This is why I put 'DOS' in quotes. Sorry for misunderstanding. The console programs look soooo much as DOS programs that you can hardly call them (in their cuteness 'console'). – Gabriel Oct 28 '15 at 18:02
  • 2
    It seems that WMI service is disabled by default: https://www.youtube.com/watch?v=JgsHfc-4TUE – Gabriel Oct 28 '15 at 18:08
0

This is 30KB with a plain icon, 15KB if you UPX it, compiled with Delphi 10 Seattle, and takes roughly 150-200ms in my system.

program ScreenSupport;

{$APPTYPE CONSOLE}

{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

uses
  Windows,
  Messages;

{$R *.res}

{$SetPEFlags $0200} // IMAGE_FILE_DEBUG_STRIPPED}      // $0200
{$SetPEFlags $0004} // IMAGE_FILE_LINE_NUMS_STRIPPED}  // $0004
{$SetPEFlags $0008} // IMAGE_FILE_LOCAL_SYMS_STRIPPED} // $0008
{$SetPEFlags $0001} // IMAGE_FILE_RELOCS_STRIPPED}     // $0001

Const WM_APP = $8000;
      msgSendScreenres = WM_APP+1;
      SM_CXVIRTUALSCREEN = 78;
      SM_CYVIRTUALSCREEN = 79;

function GetDesktopHeight: Integer;
begin
  Result := GetSystemMetrics(SM_CYVIRTUALSCREEN);
end;

function GetDesktopWidth: Integer;
begin
  Result := GetSystemMetrics(SM_CXVIRTUALSCREEN);
end;

procedure SendScreenRes(t: THandle);
begin
  if t = 0 then Exit;
  PostMessage(t,msgSendScreenres,GetDesktopWidth,GetDesktopHeight);
end;

function IsAnyParam(s: string): Boolean;
Var a: Integer;
begin
  Result := False;
  if ParamCount = 0 then Exit;
  for a := 1 to ParamCount do
   if ParamStr(a) = s then Exit(True);
end;

function StrToInt(const S: string): Integer;
Var E: Integer;
begin
  Val(S, Result, E);
end;

begin
// screen res requested
  if IsAnyParam('-screenres') then begin
    try
      SendScreenRes(StrToInt(ParamStr(2)));
    except
      Exit;
    end;
  end;
end.

To use it, call it from your main app:

Const msgSendScreenres = WM_APP+1;

ShellExecute(0,'open','ScreenSupport.exe',PChar('-screenres '+IntToStr(Form1.Handle)),'',SW_HIDE);

then add this on private declarations on the main unit

procedure WMScreenRes(var Msg: TMessage); message msgSendScreenres;

then catch it

procedure TForm1.WMScreenRes(var Msg: TMessage);
begin
  ScreenWidth  := Msg.WParam;
  ScreenHeight := Msg.LParam;
end;
hikari
  • 3,393
  • 1
  • 33
  • 72