Old 20th June 2022, 22:13   #41
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
This has no manifest at all.

PHP Code:
!include MUI2.nsh
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE English

!macro DPI txt
System
::Call 'USER32::SetProcessDPIAware()i.r0'
System::Call 'SHCORE::GetProcessDpiAwareness(p0,*i0r1)'
${IfThen} $${|} StrCpy $1 PROCESS_SYSTEM_DPI_AWARE ${|}
System::Call 'USER32::GetDpiForSystem()i.r2'
System::Call 'USER32::IsProcessDPIAware()i.r3'
MessageBox MB_OK "${txt}: result=$0 get=$1 sysdpi=$2 aware=$3"
!macroend

Function .onInit
!insertmacro DPI Inst
FunctionEnd

Function un.onInit
!insertmacro DPI Uninst
FunctionEnd

Section
WriteUninstaller 
"$exedir\UnTest.exe"
ExecShell '' "$exedir\UnTest.exe"
Quit
SectionEnd

Section 
-un.Test
Quit
SectionEnd

ManifestDPIAware notset
RequestExecutionLevel none 
You can set this to User to avoid UAC but it will get a manifest
XPStyle off 
I'm not expecting this to work better than with a manifest but the return values of the functions should be interesting.

Windows 10 gives me: Uninst: result=1 get=PROCESS_SYSTEM_DPI_AWARE sysdpi=120 aware=1

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 21st June 2022, 12:30   #42
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
It has a remnant manifest still. I don't know why.

PHP Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
          manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0"
                      processorArchitecture="*"
                      name="Nullsoft.NSIS.exehead"
                      type="win32"/>
    <description>Nullsoft Install System v3.08</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32"
                              name="Microsoft.Windows.Common-Controls"
                              version="6.0.0.0"
                              processorArchitecture="*"
                              publicKeyToken="6595b64144ccf1df"
                              language="*"/>
        </dependentAssembly>
    </dependency>
</assembly>
I doubt the manifest matters. The results are interesting.

I did:
PHP Code:
ManifestDPIAware notset
RequestExecutionLevel none
XPStyle off
#ManifestSupportedOS all ; (commented out) 
WIN 11:
HTML Code:
Installer - result=1 get=PROCESS_SYSTEM_DPI_AWARE sysdpi=120 aware=1
Uninstaller - result=1 get=0 sysdpi=96 aware=0
test ($exedir\UnTest.exe) - result=1 get=PROCESS_SYSTEM_DPI_AWARE sysdpi=120 aware=1
Generating "Untest.exe" overrides the usual uninstaller built at runtime. It was three separate tests, actually.

a) instdir/bin/uninst.exe
b) exedir/UnTest.exe

Yes, an interesting result indeed. "Untest.exe" as the proxy uninstaller is DPI-aware. Who would have thought that?

This was the third test:

c) instdir/bin/UnTest.exe

WIN 11:
HTML Code:
test - result=1 get=PROCESS_SYSTEM_DPI_AWARE sysdpi=120 aware=1
Does this mean something in my uninstaller triggers "aware=0"?

It was a good test to do. I was about to give up. 'Thank you!'

The DPI issue remains current for the moment. Windows 10 and Windows 11 treat the uninstallers differently. In my "uninst.exe" there may be a problem with certain Exe files that are sometimes flagged as dangerous by Defender. They are not dangerous, but could that be an issue?
rgreen is offline   Reply With Quote
Old 21st June 2022, 12:49   #43
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
I don't understand why instdir/bin/uninst.exe would be special. Is it not generated by WriteUninstaller like everything else? Or could it be compatibility related to the filename? Any why would it still have the manifest? XPStyle on it looks like. Maybe you can create a minimal example .nsi that reproduces the problem?

"result=1 get=0" means the Set call claims to succeed but somehow it still did not apply it to the process.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 21st June 2022, 13:33   #44
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
The uninstaller is normal, depending on where you run it. Windows 11, abnormal.

PHP Code:
"uninst.exe" (ansi) <> "uuninst.exe" (unicode)
DetailPrint "$(DETAIL_DATA)"
SetOutPath "$INSTDIR\bin"
WriteUninstaller "$INSTDIR\bin\${uninstx}" 
I had a code for writing a text string at the end of the file. That is disabled and can't be it.

It may after all be my Windows 11, which is hard to test. My only choice, it would seem, is to disable as much of the installer and uninstaller, until the behavior changes.

UnTest.exe clearly does work, so haystack here I come. I hope there's a needle.
rgreen is offline   Reply With Quote
Old 21st June 2022, 16:11   #45
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Solved it. Thanks very much for (and to) your help, Anders.

If in the installation that names the folder in which "uninst.exe" resides 'bin', the uninstaller is not dpi-aware run from the location. Instead calling the folder 'binary' or probably anything else during installation fixes the dpi-awareness problem.

How is this possible?

Why is it wrong to name the folder 'bin' in Windows 11?
rgreen is offline   Reply With Quote
Old 22nd June 2022, 00:17   #46
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
To do the right thing, I believe I should test this some more on my system.

A possibility is that the Properties for "uninst.exe" were configured to run the file in compatibility mode with DPI handled by Windows.

High DPI scaling override, tick the box inside properties, i.e.: "Override high DPI scaling behavior. Scaling performed by > Application, System, System Enhanced." ... Well, it's a theory. The folder perhaps cached the Properties setting. Not a good theory, however, since I never touched the Properties. To boot, both file and folder were repeatedly uninstalled while testing.

At present, I cannot reproduce the problem by renaming the folder back to 'bin'. The issue seems gone. The uninstaller is now dpi-aware.

I hope to reproduce it by reverting to the install script where the name was originally 'bin'. Maybe it was a combination of all factors combined.

Surely this is connected with NSIS and possibly manifests, so trying to get to the bottom of it might serve some purpose.

It will take awhile before I can get back to the older version. A day or two.

No need to reply.
rgreen is offline   Reply With Quote
Old 23rd June 2022, 20:32   #47
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Smile

Tests : ManifestDPIAware notset

11
HTML Code:
22000: get=PROCESS_SYSTEM_DPI_AWARE sysdpi=144 aware=1
10
HTML Code:
19044: get=PROCESS_SYSTEM_DPI_AWARE sysdpi=144 aware=1
7
HTML Code:
7601: get=0 sysdpi=error aware=1
Vista
HTML Code:
6002: get=0 sysdpi=error aware=1
XP (virtual machine)
HTML Code:
2600: get=0 sysdpi=error aware=error
Graceful errors -- that's good.

On the older OSes, 7 & Vista, switching on dpi-awareness does not much.

They are dpi-aware to the extent that DPI defaults to 96 regardless of screen resolutions and font sizes, and DWM scales bitmaps.

Larger header images are displayed where an actual value for 'sysdpi=' exists, otherwise stretching can be applied to 96 dpi images that are the default based on the application's size.

Windows 11 still won't allow 'bin/uninst.exe' to run at anything other than 96 dpi. I have renamed my folder 'un' as a workaround.

The macro is fantastic. Thank you so much for it.

I don't know about the "ManifestDPIAware system" setting. Wouldn't it be easier for every monitor to just apply scaling according to DPI?

HTML Code:
System::Call 'USER32::GetDpiForSystem()i.r2'
If not 96 -> scale.

But what the hay, I'm sure there's situation where it is useful to set "system".
rgreen is offline   Reply With Quote
Old 24th June 2022, 10:04   #48
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
GetProcessDpiAwareness and GetDpiForSystem are not going to work on older systems (the functions don't even exist). No functions exist on XP. The get dpi function in the plug-in posted in this thread will work. Use the manifest to turn DPI aware on.

ManifestDPIAware system is exactly the same as ManifestDPIAware true.

Why do you want the uninstaller in a subfolder anyway?

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 24th June 2022, 13:16   #49
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
No reason. The install mirrors the tree structure of a website containing any number of folders, but the installer can go anywhere.

'bin' is merely a habit.

===

There are a few more quirks in Windows at different DPI settings.

I found `System::Call 'SHCORE::GetProcessDpiAwareness(p0,*i0r1)'` useful in setting the dpi-awareness only for standard sizes. 120, 144, 168, 192.

168 dpi is as bad as 120 dpi when it comes to the application window size. It is more narrow than at 96 dpi.

No one can say what future Windows versions will bring, but because 168 and 120 dpi alter the aspect-ratio by a lot, the developers might decide to streamline all DPI sizes, so there is a nice gradient when you switch to a higher or lower monitor setting. For designers this would mean adapting.

All things considered, "ManifestDPIAware false" is the safest choice, letting Windows re-scale everything up from 96 dpi. I had wondered about using "ManifestDPIAware true" in the past. It seemed like a fair choice, but having investigated it, the "false" setting, as I now think, has a lot going for it.

To switch dpi-aware on and off, I used a variable '$DPI_SCALE'. The default 96 dpi image is 's.bmp' or 'sUN.bmp' (uninstaller).

MACRO
PHP Code:
!macro DPIX UN
  StrCpy $DPI_SCALE 
"DWM" # ; user variable
  
System::Call 'SHCORE::GetProcessDpiAwareness(p0,*i0r1)'
  
${IfThen} $${|} StrCpy $1 PROCESS_SYSTEM_DPI_AWARE ${|}
  
System::Call 'USER32::GetDpiForSystem()i.r2'
  
System::Call 'USER32::IsProcessDPIAware()i.r3'
  
example 6002get=0 sysdpi=error aware=(Vista)
  
#MessageBox MB_OK "${TEMP1}: get=$1 sysdpi=$2 aware=$3"
    
StrCpy $SYS_DPI $#
    
StrCpy $DPI_AWARE $#

  
${If} $== "PROCESS_SYSTEM_DPI_AWARE" process okay
  
${AndIf} $== aware
    
${If} $== 192
    
${OrIf} $== 168
    
${OrIf} $== 144
    
${OrIf} $== 120
        StrCpy $DPI_SCALE 
"" #
      
${If} $== 192
        File 
"/oname=$PluginsDir\modern-header.bmp" "xl${UN}.bmp" 192
      
${ElseIf} $== 168
        File 
"/oname=$PluginsDir\modern-header.bmp" "l${UN}.bmp" 168
      
${ElseIf} $== 144
        File 
"/oname=$PluginsDir\modern-header.bmp" "m${UN}.bmp" 144
      
${ElseIf} $== 120
        File 
"/oname=$PluginsDir\modern-header.bmp" "n${UN}.bmp" 120
      
${EndIf}
      ${
IfNot$DPI_SCALE == "DWM"
        
!insertmacro MUI_HEADERIMAGE_INITHELPER_LOADIMAGEWITHMACRO \
          
MUI_LOADANDXALIGNIMAGE "NoStretchNoCrop"
      
${EndIf}
    ${EndIf}
  ${EndIf}
!
macroend 
INSTALLER
PHP Code:
Function .onInit
  
DPI-aware on-switch provided ManifestDPIAware is "notset"
  
GetWinVer ${TEMP1Build
  IntCmp 
${TEMP110240 0 jump 0 ; require Windows 10
  
dpi font-scaling was eratic on earlier Windows
  System
::Call 'USER32::SetProcessDPIAware()i.r0'
  
jump:
  ...
FunctionEnd

Function onGUIInit_func
  
Re-scaled bitmaps
  
!insertmacro DPIX ""
  
...
FunctionEnd 
UNINSTALLER
PHP Code:
Function un.onInit
  GetWinVer 
${TEMP1Build
  IntCmp 
${TEMP110240 0 jump 0 Windows 10+
  
System::Call 'USER32::SetProcessDPIAware()i.r0'
  
jump:
  ...
FunctionEnd

Function un.onGUIInit_func
  
Re-scaled bitmaps
  
!insertmacro DPIX "UN"
  
...
FunctionEnd 
May it help someone.
rgreen is offline   Reply With Quote
Old 24th June 2022, 21:54   #50
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
The macro needs to know the plugins folder path, I forgot, at the top. Sorry. My bad.

PHP Code:
!define /redef PATH "$PLUGINSDIR\modern-header.bmp" ; for inst.exe and uninst.exe 
rgreen is offline   Reply With Quote
Old 24th June 2022, 21:56   #51
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
Just checking IsProcessDPIAware is probably enough. And for anyone else, use the plug-in instead of GetDpiForSystem. Your usage of GetDpiForSystem is incorrect, it does not exist in Win 10 RTM, it was added in the Anniversary Update.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 24th June 2022, 22:30   #52
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Good to know. Change 10240 to 14393?

{erratic with R's}

An innocent question. 'SysCompImg.dll' checks for dpi-awareness.

SysCompImg::GetSysDpi

For me that's really the crux. I'm happy to replace DPI detection with the plugin, which is very handy and useful, but if your system is dpi-unaware via the manifest missing the DPI declaration or "ManifestDPIAware notset", you wouldn't be able to use the plugin?

DPI-awareness relies on `System::Call 'USER32::SetProcessDPIAware()i.r0'`. ?
rgreen is offline   Reply With Quote
Old 24th June 2022, 23:04   #53
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
To expand a little. My small header image (96 dpi) stretches to fit, that it must, in order for Windows to rescale it at higher DPI settings; older versions of Windows, like 7 and Vista, require the image to stretch. Only the alternate high dpi images, unavailable to 7 and Vista, disable stretching. I guess they could stretch, but my experience was that stretching distorted them sometimes. They'd have to exactly fit the UI frame.

To sum it up as follows, to determine whether stretch-to-fit should be enabled, dpi-aware is not set to true automatically. DWM does not stretch images when/if dpi-aware is "true".
rgreen is offline   Reply With Quote
Old 24th June 2022, 23:17   #54
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
SysCompImg::GetSysDpi first tries GetDpiForSystem and if it's not there it falls back to the GetDC code I posted earlier in this thread. For systems where DPI awareness is a thing it reports the DPI of the process. On older systems there is just one global DPI value and it returns that (< Vista). The global is usually 96 on old systems but can be set to 120. The plug-in does not care how you became aware.

Awareness requires "ManifestDPIAware true" or System::Call 'USER32::SetProcessDPIAware()i.r0' in .onInit. Microsoft recommends the manifest method but calling the function depending on a condition is the only way to make it dynamic. NSIS might display the unpacking dialog before .onInit in large installers and that could in theory break SetProcessDPIAware FYI.

If you are OK with losing some of the left side of the image you could try the AspectFitHeight image stretch mode.

If you choose to be unaware, "ManifestGdiScaling true" is supposed to make the text less blurry in some cases (192 dpi). This setting is undocumented because it was never tested enough to see if there are unwanted side-effects. See https://blogs.windows.com/windowsdev...-desktop-apps/

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 25th June 2022, 00:22   #55
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Thanks. I prefer the dynamic solution, but I'm flexible as to how best it can be achieved.

Example (small default image)

A) (dynamic)
22000: get=0 sysdpi=96 aware=0

[Image stretched @ 144 dpi]

B)
22000: get=PROCESS_SYSTEM_AWARE sysdpi=144 aware=1

[Image scaled @ 144 dpi]

In case they they don't show up, there are supposed be 81x81 pixel gif images. 'A' is smooth, 'B' pixelated.

No. They can't be previewed. I'll forego the links. It seems pretty clear that dynamic is better.

Quote:
If you are OK with losing some of the left side of the image you could try the AspectFitHeight image stretch mode.
Getting the exact dimensions right when placing an image is hard what with HiDPI being so variable in Windows. My images are too large. "NoStretchNoCrop" I like.
rgreen is offline   Reply With Quote
Old 25th June 2022, 00:51   #56
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Quote:
Originally Posted by Anders View Post
NSIS might display the unpacking dialog before .onInit in large installers and that could in theory break SetProcessDPIAware
That is worrisome, although on fast systems, Windows 10/11, less worrisome. An unpacking dialog happened on Windows 7 recently (to me), due to the embedded large images.
rgreen is offline   Reply With Quote
Old 25th June 2022, 01:11   #57
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
MSDN says
Quote:
Although it is not recommended, it is possible to set the default DPI awareness programmatically. Once a window (an HWND) has been created in your process, changing the DPI awareness mode is no longer supported.
but I don't know if not supported means it wont work or if they just don't approve of it.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 25th June 2022, 01:38   #58
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
My understanding and experience also is that the window is created first, dpi-awareness not yet set, which defaults to "false" on older systems, and then the process that turns on dpi-awareness kicks in and switching it back off is no longer supported.

They'd probably want discourage a programmatic on-off switch. Heeding such warnings to the letter would result in dpi-awareness being set to "false" more often than not, as it is the safest mode. You can't go wrong with it.
rgreen is offline   Reply With Quote
Old 25th June 2022, 01:54   #59
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Correction on "dpi-awareness not yet set, which defaults to "false" on older systems". It defaults to "true", except on XP. Ambiguously dpi-aware "true" on older systems does not mean they can detect the dpi setting, or so it seems.

`System::Call 'USER32::GetDpiForSystem()i.r2'` returns an error. I think there was much confusion in the early days as what dpi-aware actually meant. I should know, being one of those confused.
rgreen is offline   Reply With Quote
Old 25th June 2022, 09:35   #60
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,528
How many times do I have to say it? Use the plug-in, not GetDpiForSystem. GetDpiForSystem is 20 years newer than XP.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 25th June 2022, 16:53   #61
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Okay, from now on.

`System::Call 'SHCORE::GetProcessDpiAwareness(p0,*i0r1)'` is pretty good too for detecting the process, and `System::Call 'USER32::SetProcessDPIAware()i.r0'` for starting said process. I agree, since 7 and Vista can get the DPI via the plugin, it's a gamechanger.
rgreen is offline   Reply With Quote
Old 7th July 2022, 19:05   #62
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Sorry to be hogging attention with this issue. Two weeks on it is still the same on Windows 11. It is sort of my problem. I'd let it alone, it not being crucial to my existence. It just can't be right though.

C:\Gallery\bin\uninst.exe always runs at 96 dpi. Always.

C:\Users\RG\AppData\Local\Gallery\bin\uninst.exe works.
C:\Gallery\un\uninst.exe works.
C:\Galleria\bin\uninst.exe works.

All other OSes work with C:\Gallery\bin\uninst.exe.

What's going on? Caching could be the cause, as Anders suggested.

Is there a test you can run, a way to empty the cache?

Thanks, and again, I do apologize. I know this is nuts.
rgreen is offline   Reply With Quote
Old 8th July 2022, 08:06   #63
SyneRyder
Junior Member
 
Join Date: Aug 2021
Posts: 4
Watching this thread from afar, my first thought would be, have you done a binary comparison (with a tool like Beyond Compare) on the C:\Gallery\bin\uninst.exe file to check that it really is exactly the same file as in the other locations? If the file differs somehow, there's more at play than just the file location.

If you could take the working exe from C:\Galleria\bin\uninst.exe, move it to C:\Gallery\bin\ and suddenly its behavior changes, then it becomes more plausible that there's something special about that folder on Windows 11. Or at least, special about it on your system - you could try firing up a brand new Windows 11 virtual machine to test if it also happens on a brand new Windows 11 install.

It probably shouldn't be installing in C:\Gallery anyway. How does it behave when installed in C:\Program Files\(company name)\Gallery\ ?
SyneRyder is offline   Reply With Quote
Old 8th July 2022, 19:01   #64
rgreen
Junior Member
 
Join Date: Jun 2022
Posts: 29
Beyond Compare generates the following report:

HTML Code:
Version Compare
Produced: 08/07/2022 17:45:34
   
Left file: C:\Gallery\bin\uninst.exe     Right file: C:\Gallery\un\uninst.exe  
19 same item(s)  
2 important difference item(s)
I don't believe they are very important.

Differences:

Data: 5,484,709 bytes (left)
Data: 5,484,709 bytes (right)

Unknown (Compiled): 08/07/2022 17:28:02 (left)
Unknown (Compiled): 08/07/2022 03:21:04 (right)

It cannot be the uninst.exe binary.

I tried renaming the folder containing 'uninst.exe' from 'bin' to 'un', and it worked as long as it pointed to 'C:\Gallery\un' in the registry.

Vice versa: renaming the folder 'un' to 'bin, ditto in the registry, it ran at 96 dpi again.

It's the file-name-folder-name combo.

Installing to 'C:\Program Files\RG\Gallery', where the uninstaller file is 'C:\Program Files\RG\Gallery\bin\uninst.exe', tosses up nothing that unusual. 'uninst.exe' executes at 144 dpi. It works.

'C:\Gallery\bin\uninst.exe' is dpi-unaware.

I have been looking at this line of code:

PHP Code:
!define TEMP $INSTDIR\bin Temporary location of encrypted archives 
changed it to:

PHP Code:
!define TEMPUS $INSTDIR\bin Temporary location of encrypted archives 
Result: 96 dpi.

I don't want to divert - even further divert - this thread, an edifying the thread, from HiDPI in NSIS. If I discover that it is an actual NSIS bug, which I seriously doubt it is, I will post in a new thread. Thanks everyone.
rgreen is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
dpi, plug-in

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump