|
-
Apr 20th, 2019, 10:14 AM
#1
Thread Starter
Lively Member
Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I'm trying to deal with some older OCX controls that are unable to handle resizing on high res monitors. On my test machine pixels = 7.5 twips. I'm wondering if anyone has found an elegant/efficient way to deal with this problem.
I'm thinking maybe subclass the problem controls and intercept WM_SIZE to make adjustments but not sure if that would even work.
-
Apr 20th, 2019, 11:41 AM
#2
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Here is function I'm using for control move/resize that is High DPI compatibile.
thinBasic Code:
Public Sub MoveCtl( _
oCtl As Object, _
ByVal Left As Single, _
Optional Top As Variant, _
Optional Width As Variant, _
Optional Height As Variant)
Const FUNC_NAME As String = "MoveCtl"
Dim oCtlExt As VBControlExtender
On Error GoTo EH
If oCtl Is Nothing Then
Exit Sub
End If
If TypeOf oCtl Is VBControlExtender Then
Set oCtlExt = oCtl
If IsMissing(Top) Then
If oCtlExt.Left <> Left Then
oCtlExt.Move Left
End If
ElseIf IsMissing(Width) Then
If oCtlExt.Left <> Left Or oCtlExt.Top <> Top Then
oCtlExt.Move Left, Top
End If
ElseIf IsMissing(Height) Then
If oCtlExt.Left <> Left Or oCtlExt.Top <> Top Or oCtlExt.Width <> Limit(Width, 0) Then
If 1440 \ ScreenTwipsPerPixelX = 1440 / ScreenTwipsPerPixelX Then
oCtlExt.Move Left, Top, Limit(Width, 0)
ElseIf oCtlExt.Left <> Left Or oCtlExt.Top <> Top Then
oCtlExt.Move oCtlExt.Left, oCtlExt.Top, Limit(Width, 0)
oCtlExt.Move Left, Top
Else
oCtlExt.Move Left + ScreenTwipsPerPixelX, Top, Limit(Width, 0)
oCtlExt.Move Left
End If
End If
Else
If oCtlExt.Left <> Left Or oCtlExt.Top <> Top Or oCtlExt.Width <> Limit(Width, 0) Or oCtlExt.Height <> Limit(Height, 0) Then
If 1440 \ ScreenTwipsPerPixelX = 1440 / ScreenTwipsPerPixelX Then
oCtlExt.Move Left, Top, Limit(Width, 0), Limit(Height, 0)
ElseIf oCtlExt.Left <> Left Or oCtlExt.Top <> Top Then
oCtlExt.Move oCtlExt.Left, oCtlExt.Top, Limit(Width, 0), Limit(Height, 0)
oCtlExt.Move Left, Top
Else
oCtlExt.Move Left + ScreenTwipsPerPixelX, Top, Limit(Width, 0), Limit(Height, 0)
oCtlExt.Move Left
End If
End If
End If
Else
If IsMissing(Top) Then
If oCtl.Left <> Left Then
oCtl.Move Left
End If
ElseIf IsMissing(Width) Then
If oCtl.Left <> Left Or oCtl.Top <> Top Then
oCtl.Move Left, Top
End If
ElseIf IsMissing(Height) Then
If oCtl.Left <> Left Or oCtl.Top <> Top Or oCtl.Width <> Limit(Width, 0) Then
If 1440 \ ScreenTwipsPerPixelX = 1440 / ScreenTwipsPerPixelX Then
oCtl.Move Left, Top, Limit(Width, 0)
ElseIf oCtl.Left <> Left Or oCtl.Top <> Top Then
oCtl.Move oCtl.Left, oCtl.Top, Limit(Width, 0)
oCtl.Move Left, Top
Else
oCtl.Move Left + ScreenTwipsPerPixelX, Top, Limit(Width, 0)
oCtl.Move Left
End If
End If
Else
If oCtl.Left <> Left Or oCtl.Top <> Top Or oCtl.Width <> Limit(Width, 0) Or oCtl.Height <> Limit(Height, 0) Then
If 1440 \ ScreenTwipsPerPixelX = 1440 / ScreenTwipsPerPixelX Then
oCtl.Move Left, Top, Limit(Width, 0), Limit(Height, 0)
ElseIf oCtl.Left <> Left Or oCtl.Top <> Top Then
oCtl.Move oCtl.Left, oCtl.Top, Limit(Width, 0), Limit(Height, 0)
oCtl.Move Left, Top
Else
oCtl.Move Left + ScreenTwipsPerPixelX, Top, Limit(Width, 0), Limit(Height, 0)
oCtl.Move Left
End If
End If
End If
End If
Exit Sub
EH:
RaiseError FUNC_NAME
End Sub
. . . where ScreenTwipsPerPixelX = 1440 / GetDeviceCaps(hScreenDC, LOGPIXELSX) to be able to get 7.5
cheers,
</wqw>
-
Apr 20th, 2019, 12:54 PM
#3
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by zlander
I'm trying to deal with some older OCX controls that are unable to handle resizing on high res monitors. On my test machine pixels = 7.5 twips.
older OCX controls??? VB6 altogether is unable to handle non integer TwipsPerPixel values.
-
Apr 20th, 2019, 03:03 PM
#4
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
This is similar to the road I was headed down, but it's a pretty big application and the thought of replacing all of the move operations individually seemed somewhat barbaric. I thought there might be a simpler way to deal with it through subclassing.
In your code what is the Limit(Width, 0) function?
-
Apr 20th, 2019, 03:06 PM
#5
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Oh dear. I'm just getting started with this. Are there more horrors in store for me? Is there a thread here where this is discussed that I've missed?
-
Apr 20th, 2019, 04:13 PM
#6
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
There is LaVolpe's Being DPI Aware Tutorial that has everything explained (and more!:-))
Personally I get away with a couple of helper functions: IconScale to scale. . . icons, and other graphical elements and MoveCtl (this one is very simple barebone impl, check it out I promise) besides the usual replacements to ScreenTwipsPerPixelX/Y and OrigTwipsPerPixelX/Y properties (not impl in the link but you get the point).
These helpers and a manifest file/resource was pretty much all I needed for a project to become DPI aware, although Per Monitor awareness is much more work with display resolution/DPI becoming properties of the Form, not a global Screen object.
cheers,
</wqw>
-
Apr 20th, 2019, 04:37 PM
#7
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Thanks! I'll re-read the LaVolpe tutorial though it seemed like that focused on updating the controls themselves so that they behave properly. That would require some reverse engineering to apply to old OCX controls.
-
Apr 20th, 2019, 04:38 PM
#8
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I didn't get what the Limit(Width, 0) function does in your code.
-
Apr 20th, 2019, 04:40 PM
#9
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I think you should find what parts of your program are not behaving correctly.
Once you identify where are the problems, we could help with specific solutions.
I also recommend to read about the issue from other posts like the one from LaVolpe.
All conversions from twips to pixels and vice versa will be wrong. Among things affected are:
Screen.TwipsPerPixelX
Screen.TwipsPerPixelY
Object.ScaleX
Object.ScaleY
X and Y parameters in MouseMove/Down/Up events of VB controls
The size and position of some controls
For the X and Y parameters of the mouse events, for example a solution would be to have a correction factor. The correction factor would be APICalculatedTwipsPerPixelX / Screen.TwipsPerPixelX and multiply all X values with this factor.
If the program is large, be prepared to spend a good time.
-
Apr 20th, 2019, 05:05 PM
#10
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
In my initial forays into what I'm calling the barbaric approach I wrote a routine to pull in all of my .FRM and .BAS files and replace every instance of .LEFT, .RIGHT, .WIDTH, .HEIGHT and .MOVE with a single call to a dpi_move() sub. That resulted in over 1000 modifications to the code, so that should give you an idea of the size of the project.
I don't mind spending the time, but I was getting worried that perhaps this might be the first VB6 issue I've encountered that could not be fixed (which would be sad).
It does seem to me that subclassing might provide a more elegant approach since not all controls are affected apparently. I was looking at this Randy Birch code as a possible starting point:
http://vbnet.mvps.org/index.html?cod...spectratio.htm
-
Apr 20th, 2019, 05:07 PM
#11
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
The effort required will depend on what your program is doing and what sort of scaling flaws you are running into.
For recent versions of Windows 10 it can be as easy as one setting in your program's application manifest (or manually set via the Explorer Properties dialog). See the 2017 blog post:
Improving the high-DPI experience in GDI based Desktop Apps which has a long discussion and then some developer information near the bottom.
This isn't a cure-all, but for most non-graphics applications it can be an easy fix.
-
Apr 20th, 2019, 05:18 PM
#12
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I've been using the registry approach – is there any benefit to using the manifest approach instead?
HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" /v "<full path to Executable>" /t REG_SZ /d "~ HIGHDPIAWARE
-
Apr 20th, 2019, 05:19 PM
#13
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
zlander,
I can tell you the way I've dealt with this, but it's not a solution that everyone will be happy with. There are basically three ways we can change the size of things on our monitor. (I suppose a fourth is to write our program to make things bigger, but I'll leave that one out for now.)
- Change our monitor's hardware resolution, but this one isn't the best for clarity and sharpness.
- Change our DPI settings, but this one causes problems like you're having, as well as other GDI API problems and other graphics manipulation problems.
- Change the "Scale and Layout" setting, but this requires Windows 10.
Because of the problems associated with #2, I've told my clients to not use that option. When they needed larger things on the screen, before Windows 10, I told them to use the monitor's resolution settings. But now, with Windows 10, the "Scale and Layout" settings are very nice, and they don't tamper with the DPI setting (leaving it at 96), and it scales TrueType fonts, and it works hard at keeping pictures sharp. Microsoft has done a pretty good job of this, and they're continuing to work on it.
Anyway, that's my solution.
Good Luck,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Apr 20th, 2019, 05:23 PM
#14
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I consider myself that VB6 is not suited to work in non integer TwipsPerPixel settings. In my latest program I check for that and if the actual TwipsPerPixel is not an integer then I display a message telling that the program won't work right in such DPI setting, and that she/he could choose another one if wants this program to work right.
180 DPI would work right, because it is 8 TwipsPerPixel, Perhaps 206 DPI or 205 DPI would work acceptably. 7 TwipsPerPixel is 205.714285...
I still didn't have cases where people using my programs have set such hight DPI setting (or I didn't know)
But I said many times here in this forum that this is one of the main reasons why we need an update of VB6. The time when people use this higher DPI setting normally can come in some years.
A VB6 program probably can be adapted to work on such high DPI setting, like I said putting a correction factor on each MouseMove/Down/Up event and many other things (like replacing every ScaleX and ScaleY method). But that would be very cumbersome. It is not the RAD tool that I want to work with.
-
Apr 21st, 2019, 02:34 AM
#15
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by zlander
I didn't get what the Limit(Width, 0) function does in your code.
Here is an implementation of this function. A better name would be Clamp of course but at the time it was conceived I was not aware with the works of John Carmack (particularly Doom III source code where clamp was practially invented as a standard name for such a function)
cheers,
</wqw>
-
Apr 21st, 2019, 03:09 AM
#16
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by Eduardo-
I consider myself that VB6 is not suited to work in non integer TwipsPerPixel settings.
The flaw isn't in VB6, it is in OLE. VB6 is just a major client of OLE, of which it makes a great deal of use.
If the problem could be fixed there it would be lovely. But Microsoft either doesn't want to, or they realize that a "fix" could break tons of legacy code, or perhaps they already know there is no simple fix.
I don't think this can be fixed by a simple "update of VB6." In addition to the fractional pixels per twip problem there are plenty of other things to deal with too. That's why every UI library on Windows has its own set of problems with High DPI.
Attempting to "fix" this by changing VB6 probably means throwing so much away that you'd probably end up with something closer VB.Net or FreeBasic anyway... and you would still have issues.
So there aren't too many realistic answers. You either ignore it and suffer, deal with it properly with a lot of extra code, move to another language with a UI widget library less susceptible (and still add extra code), or where it works use the GDI Scaling we got in recent versions of Windows 10.
The blog post linked above goes into some of the limitations of GDI Scaling.
-
Apr 21st, 2019, 04:29 AM
#17
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Property Get Screen.TwipsPerPixelsX accesses internal VB6 struct where the value is 4-byte int and it is used all over the place directly as an int so this cannot be fixed by a simple in-memory patch. Turning this member to float and a simple recompile will be painless though.
Another interesting point is that there *is* Property Let Screen.TwipsPerPixelsX in the Screen object's vtable which is not exposed in the typelib. Unfortunately calling it just errors with "Property Let not implemented" or similar.
cheers,
</wqw>
-
Apr 21st, 2019, 07:00 AM
#18
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by wqweto
Property Get Screen.TwipsPerPixelsX accesses internal VB6 struct where the value is 4-byte int and it is used all over the place directly as an int so this cannot be fixed by a simple in-memory patch. Turning this member to float and a simple recompile will be painless though.
cheers,
</wqw>
I'm assuming (hoping) you mean that *I* should turn this into a float and not that Microsoft should. I'm using twip.x and twip.y which are single data type.
-
Apr 21st, 2019, 07:03 AM
#19
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
I haven't delved into the new GDI Scaling features yet. My goal is to get this app working and looking good on the latest Windows 10 1903 (May) release which is what I have installed on the test machine so I'll review GDI scaling more thoroughly now. I'll keep this thread open for a while and report back anything interesting I find.
-
Apr 21st, 2019, 07:06 AM
#20
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Clamp does have something going for it. What are we clamping here though? Does VB6 have a limitation I should know about? Is there a short integer wall somewhere that 3000 X 2000 will break?
-
Apr 21st, 2019, 08:09 AM
#21
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by dilettante
The flaw isn't in VB6, it is in OLE. VB6 is just a major client of OLE, of which it makes a great deal of use.
If the problem could be fixed there it would be lovely. But Microsoft either doesn't want to, or they realize that a "fix" could break tons of legacy code, or perhaps they already know there is no simple fix.
I don't think this can be fixed by a simple "update of VB6." In addition to the fractional pixels per twip problem there are plenty of other things to deal with too. That's why every UI library on Windows has its own set of problems with High DPI.
Attempting to "fix" this by changing VB6 probably means throwing so much away that you'd probably end up with something closer VB.Net or FreeBasic anyway... and you would still have issues.
So there aren't too many realistic answers. You either ignore it and suffer, deal with it properly with a lot of extra code, move to another language with a UI widget library less susceptible (and still add extra code), or where it works use the GDI Scaling we got in recent versions of Windows 10.
The blog post linked above goes into some of the limitations of GDI Scaling.
I don't know the issue so I cannot comment about that root in OLE of the problem, but I'm quite confident that it is now like you said that it is so difficult to fix on the VB6 side.
If Krool (or anybody) can make controls that do not suffer from this issue, why VB6 itself wouldn't?
And I don't think that the language need to change at all, I don't see a reason for that.
Perhaps you could explain why VB6 cannot have TwipsPerPixelsX/Y internally (and externally) as a Single value as it already does with the Printer object.
Does the Printer object not use OLE?
Or does OLE support non integer DPI just for printing?
-
Apr 21st, 2019, 08:17 AM
#22
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
For zlander: I would focus on experimenting with the new compatibility settings that Windows 10 offers and see if that can solve your problem. I'm talking about what dilettante mentioned in message #11.
For quick tests, right click on the exe and experiment with different compatibility settings, specially the ones related to de DPI settings.
I realize that you are looking for a simple solution and this could be perhaps the only one.
Once you identify a setting that works, you could manifest the exe with that setting so your users don't need to manually set the setting each one. About how to do that you may ask after you found the proper setting.
Last edited by Eduardo-; Apr 21st, 2019 at 09:10 AM.
-
Apr 21st, 2019, 08:20 AM
#23
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
@zlander: Forget about the off-topic -- clamp, float vs int on TwipsPerPixelsX. The main take away from this thread is that *all* you have to do to circumvent resizing woes in High DPI is to move your control *w/o* specifing size (width or height). This means that if you have to move+resize your picBox control to X, Y, W and H you do it in two steps:
- first, you resize (only) with picBox.Move X+ScreenTwipsPerPixelX, Y, W, H
- second, you position *w/o* resizing with picBox.Move X, Y
This way on the second step the run-time uses *correct* width and height and there are no sizing issues.
Now, everything else in my MoveCtl you've seen above is about reducing flicker from this 1 pixel to the right initial placement. (e.g. if the control is *not* resized there is no need to move it right-by-1-pixel in first step etc.)
cheers,
</wqw>
-
Apr 21st, 2019, 08:39 AM
#24
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
Those VB6 Screen object properties have more problems than just turning ScreenTwipsPerPixel_ from Long to Float. Try putting a monitor in portrait mode (turned 90 degrees) and then using those Screen properties. Things like Screen.Width and Screen.Height don't pick this up, so you wind up with a mess.
Personally, other than to gather up a list of available fonts, I've abandoned all use of the Screen object. However, in accord with the approach I outlined in post #13, I just have a global constant for TwipsPerPixel with a value of 15&. If I wanted, I could sort it out using the GetDpiForMonitor API call, but I don't. I use the GetMonitorInfo API call to get all my centering and positioning done.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Apr 21st, 2019, 12:40 PM
#25
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by wqweto
- first, you resize (only) with picBox.Move X+ScreenTwipsPerPixelX, Y, W, H
- second, you position *w/o* resizing with picBox.Move X, Y
This way on the second step the run-time uses *correct* width and height and there are no sizing issues.
I haven't tested this yet, but it seems too good to be true. Why would this work? What's the significance of adjusting .LEFT by 1 pixel in a .MOVE operation that would cause VB to set the .WIDTH and .HEIGHT properties correctly?
-
Apr 21st, 2019, 01:02 PM
#26
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by Eduardo-
I would focus on experimenting with the new compatibility settings that Windows 10 offers and see if that can solve your problem. I'm talking about what dilettante mentioned in message #11.
The trouble with the compatibility settings is they basically display one's program as if it were running at 96 DPI and while it doesn't look too bad it doesn't look great either. It also takes some of the thrill out of the 3:2 aspect ratio which gives you more vertical workspace. It's good to know the compatibity settings are there and being improved though in case HIGHDPIAWARE turns out to be a bridge too far.
-
Apr 21st, 2019, 02:12 PM
#27
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
 Originally Posted by zlander
Why would this work? What's the significance of adjusting .LEFT by 1 pixel in a .MOVE operation that would cause VB to set the .WIDTH and .HEIGHT properties correctly?
There is no significance. You can nudge it by 5 pixels if you want. The important part is to use Move method *without* passing width/height so that VB runtime queries *current* width/height (from some IOleXxx interface) when implementing move internally. This is the meat of the workaround -- don't pass width/height and the control positions and sizes ok in High DPI settings.
How you achieve it is up to you. I nudge it 1 pixels to the right and back. You can size it in-place (i.e. ctl.Move ctl.Left, ctl.Top, NewWidth, NewHeight) and then position it ctl.Move NewLeft, NewTop without passing width/height. Just make sure you actually reposition the control, i.e. NewLeft and NewTop are *not* the position the control is already at because when no repositioning is happening then no size fixing will take place too.
cheers,
</wqw>
-
Apr 21st, 2019, 02:35 PM
#28
Thread Starter
Lively Member
Re: Split Twip | 3000 X 2000 | Old OCX | Resizing Woes
OMG that appears to work. I'll have to give it a good workout to be sure, but this could me a miracle cure! You don't even have to apply the split twip offset. Thanks for sticking with me on this.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|