-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathmonitorModule.bas
More file actions
436 lines (354 loc) · 17.1 KB
/
Copy pathmonitorModule.bas
File metadata and controls
436 lines (354 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
Attribute VB_Name = "Module1"
' 23/01/2021 .01 monitorModule.bas DAEB added if then else if you can't get device context
Option Explicit
'Constants for the return value when finding a monitor
Public Enum dwFlags
MONITOR_DEFAULTTONULL = &H0 'If the monitor is not found, return 0
MONITOR_DEFAULTTOPRIMARY& = &H1 'If the monitor is not found, return the primary monitor
MONITOR_DEFAULTTONEAREST = &H2 'If the monitor is not found, return the nearest monitor
End Enum
Public Const MONITORINFOF_PRIMARY = 1
Public Type UDTMonitor
handle As Long
Left As Long
Right As Long
Top As Long
Bottom As Long
WorkLeft As Long
WorkRight As Long
WorkTop As Long
Workbottom As Long
Height As Long
Width As Long
WorkHeight As Long
WorkWidth As Long
IsPrimary As Boolean
End Type
Public Type RECT
Left As Long
Top As Long
Right As Long ' This is +1 (right - left = width)
Bottom As Long ' This is +1 (bottom - top = height)
End Type
'Structure for the position of a monitor
Public Type tagMONITORINFO
cbSize As Long 'Size of structure
rcMonitor As RECT 'Monitor rect
rcWork As RECT 'Working area rect
dwFlags As Long 'Flags
End Type
Private Declare Function EnumDisplayMonitors Lib "user32" (ByVal hDC As Long, lprcClip As Any, ByVal lpfnEnum As Long, dwData As Long) As Long
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex As Long) As Long
Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As Long) As Long
Private Declare Function UnionRect Lib "user32" (lprcDst As RECT, lprcSrc1 As RECT, lprcSrc2 As RECT) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hWnd As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function MonitorFromRect Lib "user32" (rc As RECT, ByVal dwFlags As dwFlags) As Long
Private Declare Function GetMonitorInfo Lib "user32" Alias "GetMonitorInfoA" (ByVal hMonitor As Long, MonInfo As tagMONITORINFO) As Long
Private rcMonitors() As RECT 'coordinate array for all monitors
Private rcVS As RECT 'coordinates for Virtual Screen
' vars to obtain correct screen width (to correct VB6 bug) STARTS
Public Const HORZRES = 8
Public Const VERTRES = 10
Public screenTwipsPerPixelX As Long ' .07 DAEB 26/04/2021 common.bas changed to use pixels alone, removed all unnecessary twip conversion
Public screenTwipsPerPixelY As Long ' .07 DAEB 26/04/2021 common.bas changed to use pixels alone, removed all unnecessary twip conversion
Public screenWidthTwips As Long
Public screenHeightTwips As Long
'Function EnumMonitors(F As Form) As Long
' Dim N As Long
' EnumDisplayMonitors 0, ByVal 0&, AddressOf MonitorEnumProc, N
' With F
' .Move .Left, .Top, (rcVS.Right - rcVS.Left) * 2 + .Width - .ScaleWidth, (rcVS.Bottom - rcVS.Top) * 2 + .Height - .ScaleHeight
' End With
' F.Scale (rcVS.Left, rcVS.Top)-(rcVS.Right, rcVS.Bottom)
' F.Caption = N & " Monitor" & IIf(N > 1, "s", vbNullString)
' F.lblMonitors(0).Appearance = 0 'Flat
' F.lblMonitors(0).BorderStyle = 1 'FixedSingle
' For N = 0 To N - 1
' If N Then
' Load F.lblMonitors(N)
' F.lblMonitors(N).Visible = True
' End If
' With rcMonitors(N)
' F.lblMonitors(N).Move .Left, .Top, .Right - .Left, .Bottom - .Top
' F.lblMonitors(N).Caption = "Monitor " & N + 1 & vbLf & _
' .Right - .Left & " x " & .Bottom - .Top & vbLf & _
' "(" & .Left & ", " & .Top & ")-(" & .Right & ", " & .Bottom & ")"
' End With
' Next
'End Function
Public gblRequiresCommitToDisc As Boolean
'---------------------------------------------------------------------------------------
' Procedure : fVirtualScreenWidth
' Author : beededea
' Date : 20/11/2025
' Purpose :
'---------------------------------------------------------------------------------------
'
Public Function fVirtualScreenWidth() As Long
' This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
Dim Pixels As Long: Pixels = 0
Const SM_CXVIRTUALSCREEN = 78
'
On Error GoTo fVirtualScreenWidth_Error
Pixels = GetSystemMetrics(SM_CXVIRTUALSCREEN)
fVirtualScreenWidth = Pixels * fTwipsPerPixelX
On Error GoTo 0
Exit Function
fVirtualScreenWidth_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fVirtualScreenWidth of Module Module1"
End Function
'---------------------------------------------------------------------------------------
' Procedure : fVirtualScreenHeight
' Author : beededea
' Date : 20/11/2025
' Purpose :
'---------------------------------------------------------------------------------------
'
Public Function fVirtualScreenHeight(Optional bSubtractTaskbar As Boolean = False) As Long
' This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
Dim Pixels As Long: Pixels = 0
Const CYVIRTUALSCREEN = 79
'
On Error GoTo fVirtualScreenHeight_Error
Pixels = GetSystemMetrics(CYVIRTUALSCREEN)
If bSubtractTaskbar Then
' The taskbar is typically 30 pixels or 450 twips, or, at least, this is the assumption made here.
' It can actually be multiples of this, or possibly moved to the side or top.
' This procedure does not account for these possibilities.
fVirtualScreenHeight = (Pixels - 30) * fTwipsPerPixelY
Else
fVirtualScreenHeight = Pixels * fTwipsPerPixelY
End If
On Error GoTo 0
Exit Function
fVirtualScreenHeight_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fVirtualScreenHeight of Module Module1"
End Function
' Author : Elroy from Vbforums
'Public Function fCurrentScreenWidth()
' ' This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
' Dim Pixels As Long: Pixels = 0
' Const SM_CXSCREEN = 0
' '
' Pixels = GetSystemMetrics(SM_CXSCREEN)
' fCurrentScreenWidth = Pixels * fTwipsPerPixelX
'End Function
' Author : Elroy from Vbforums
'Public Function fCurrentScreenHeight(Optional bSubtractTaskbar As Boolean = False)
' ' This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
' Dim Pixels As Long: Pixels = 0
' Const SM_CYSCREEN = 1
' '
' Pixels = GetSystemMetrics(SM_CYSCREEN)
' If bSubtractTaskbar Then
' ' The taskbar is typically 30 pixels or 450 twips, or, at least, this is the assumption made here.
' ' It can actually be multiples of this, or possibly moved to the side or top.
' ' This procedure does not account for these possibilities.
' fCurrentScreenHeight = (Pixels - 30) * fTwipsPerPixelY
' Else
' fCurrentScreenHeight = Pixels * fTwipsPerPixelY
' End If
'End Function
'---------------------------------------------------------------------------------------
' Procedure : fTwipsPerPixelX
' Author : Elroy from Vbforums
' Date : 23/01/2021
' Purpose : This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
'---------------------------------------------------------------------------------------
'
Public Function fTwipsPerPixelX() As Single
Dim hDC As Long: hDC = 0
Dim lPixelsPerInch As Long: lPixelsPerInch = 0
Const LOGPIXELSX = 88 ' Logical pixels/inch in X
Const POINTS_PER_INCH As Long = 72 ' A point is defined as 1/72 inches.
Const TWIPS_PER_POINT As Long = 20 ' Also, by definition.
'
On Error GoTo fTwipsPerPixelX_Error
' 23/01/2021 .01 monitorModule.bas DAEB added if then else if you can't get device context
hDC = GetDC(0)
If hDC <> 0 Then
lPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSX)
ReleaseDC 0, hDC
fTwipsPerPixelX = TWIPS_PER_POINT * (POINTS_PER_INCH / lPixelsPerInch) ' Cancel units to see it.
Else
fTwipsPerPixelX = Screen.TwipsPerPixelX
End If
On Error GoTo 0
Exit Function
fTwipsPerPixelX_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fTwipsPerPixelX of Module Module1"
End Function
'---------------------------------------------------------------------------------------
' Procedure : fTwipsPerPixelY
' Author : Elroy from Vbforums
' Date : 23/01/2021
' Purpose : This works even on Tablet PC. The problem is: when the tablet screen is rotated, the "Screen" object of VB doesn't pick it up.
'---------------------------------------------------------------------------------------
'
Public Function fTwipsPerPixelY() As Single
Dim hDC As Long: hDC = 0
Dim lPixelsPerInch As Long: lPixelsPerInch = 0
Const LOGPIXELSY = 90 ' Logical pixels/inch in Y
Const POINTS_PER_INCH As Long = 72 ' A point is defined as 1/72 inches.
Const TWIPS_PER_POINT As Long = 20 ' Also, by definition.
On Error GoTo fTwipsPerPixelY_Error
' 23/01/2021 .01 monitorModule.bas DAEB added if then else if you can't get device context
hDC = GetDC(0)
If hDC <> 0 Then
lPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSY)
ReleaseDC 0, hDC
fTwipsPerPixelY = TWIPS_PER_POINT * (POINTS_PER_INCH / lPixelsPerInch) ' Cancel units to see it.
Else
fTwipsPerPixelY = Screen.TwipsPerPixelY
End If
On Error GoTo 0
Exit Function
fTwipsPerPixelY_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fTwipsPerPixelY of Module Module1"
End Function
'---------------------------------------------------------------------------------------
' Procedure : fGetMonitorCount
' Author : beededea
' Date : 20/11/2025
' Purpose :
'---------------------------------------------------------------------------------------
'
Public Function fGetMonitorCount() As Long
On Error GoTo fGetMonitorCount_Error
EnumDisplayMonitors 0, ByVal 0&, AddressOf MonitorEnumProc, fGetMonitorCount
On Error GoTo 0
Exit Function
fGetMonitorCount_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure fGetMonitorCount of Module Module1"
End Function
'---------------------------------------------------------------------------------------
' Procedure : MonitorEnumProc
' Author : beededea
' Date : 20/11/2025
' Purpose :
'---------------------------------------------------------------------------------------
'
Private Function MonitorEnumProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, lprcMonitor As RECT, dwData As Long) As Long
On Error GoTo MonitorEnumProc_Error
ReDim Preserve rcMonitors(dwData)
rcMonitors(dwData) = lprcMonitor
UnionRect rcVS, rcVS, lprcMonitor 'merge all monitors together to get the virtual screen coordinates
dwData = dwData + 1 'increase monitor count
MonitorEnumProc = 1 'continue
On Error GoTo 0
Exit Function
MonitorEnumProc_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure MonitorEnumProc of Module Module1"
End Function
'---------------------------------------------------------------------------------------
' Procedure : adjustFormPositionToCorrectMonitor
' Author : Hypetia from TekTips https://www.tek-tips.com/userinfo.cfm?member=Hypetia
' Date : 01/03/2023
' Purpose : Called on startup - restores the form's saved position and puts it on screen
' if the form finds itself offscreen due to monitor position/resolution changes.
'---------------------------------------------------------------------------------------
'
Public Sub adjustFormPositionToCorrectMonitor(ByRef hWnd As Long, ByVal Left As Long, ByVal Top As Long)
Dim rc As RECT
' Dim Left As Long: Left = 0
' Dim Top As Long: Top = 0
Dim hMonitor As Long: hMonitor = 0
Dim mi As tagMONITORINFO
On Error GoTo adjustFormPositionToCorrectMonitor_Error
GetWindowRect hWnd, rc 'obtain the current form's window rectangle co-ords and assign it a handle
'move the window rectangle to position saved previously
OffsetRect rc, Left - rc.Left, Top - rc.Top
'find the monitor closest to window rectangle
hMonitor = MonitorFromRect(rc, MONITOR_DEFAULTTONEAREST)
'get info about monitor coordinates and working area
mi.cbSize = Len(mi)
GetMonitorInfo hMonitor, mi
'adjust the window rectangle so it fits inside the work area of the monitor
If rc.Left < mi.rcWork.Left Then OffsetRect rc, mi.rcWork.Left - rc.Left, 0
If rc.Right > mi.rcWork.Right Then OffsetRect rc, mi.rcWork.Right - rc.Right, 0
If rc.Top < mi.rcWork.Top Then OffsetRect rc, 0, mi.rcWork.Top - rc.Top
If rc.Bottom > mi.rcWork.Bottom Then OffsetRect rc, 0, mi.rcWork.Bottom - rc.Bottom
'gblDynamicSizingFlg = False
gblDoNotResize = True
'move the window to new calculated position
MoveWindow hWnd, rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top, 0
On Error GoTo 0
Exit Sub
adjustFormPositionToCorrectMonitor_Error:
With Err
If .Number <> 0 Then
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure adjustFormPositionToCorrectMonitor of Module Module1"
Resume Next
End If
End With
End Sub
'---------------------------------------------------------------------------------------
' Procedure : monitorProperties
' Author :
' Date : 23/01/2021
' Purpose : All this subroutne does at the moment is to set the screenTwipsPerPixel,
' all the other stuff is currently commented out. Might need it later.
'---------------------------------------------------------------------------------------
'
Public Function monitorProperties(frm As Form) As UDTMonitor
'Return the properties (in Twips) of the monitor on which most of Frm is mapped
' Dim hMonitor As Long: hMonitor = 0
' Dim MONITORINFO As tagMONITORINFO
' Dim Frect As RECT
' Dim ad As Double: ad = 0
' reads the size and position of the window
On Error GoTo monitorProperties_Error
If debugflg = 1 Then debugLog "%" & " func monitorProperties"
' GetWindowRect frm.hwnd, Frect
' hMonitor = MonitorFromRect(Frect, MONITOR_DEFAULTTOPRIMARY) ' get handle for monitor containing most of Frm
' if disconnected return handle (and properties) for primary monitor
' STARTS 23/01/2021 .01 common.bas DAEB calls twipsperpixelsX/Y function when determining the twips for high DPI screens
' only calling TwipsPerPixelX/Y once on startup
screenTwipsPerPixelX = fTwipsPerPixelX
screenTwipsPerPixelY = fTwipsPerPixelY
'MsgBox "Harry - send me this please screenTwipsPerPixelX - " & screenTwipsPerPixelX
' ENDS 23/01/2021 .01 common.bas DAEB calls twipsperpixelsX/Y function when determining the twips for high DPI screens
On Error GoTo GetMonitorInformation_Err
' MONITORINFO.cbSize = Len(MONITORINFO)
' GetMonitorInfo hMonitor, MONITORINFO
' With monitorProperties
' .handle = hMonitor
' 'convert all dimensions from pixels to twips
' .Left = MONITORINFO.rcMonitor.Left * screenTwipsPerPixelX
' .Right = MONITORINFO.rcMonitor.Right * screenTwipsPerPixelX
' .Top = MONITORINFO.rcMonitor.Top * screenTwipsPerPixelY
' .Bottom = MONITORINFO.rcMonitor.Bottom * screenTwipsPerPixelY
'
' .WorkLeft = MONITORINFO.rcWork.Left * screenTwipsPerPixelX
' .WorkRight = MONITORINFO.rcWork.Right * screenTwipsPerPixelX
' .WorkTop = MONITORINFO.rcWork.Top * screenTwipsPerPixelY
' .Workbottom = MONITORINFO.rcWork.Bottom * screenTwipsPerPixelY
'
' .Height = (MONITORINFO.rcMonitor.Bottom - MONITORINFO.rcMonitor.Top) * screenTwipsPerPixelY
' .Width = (MONITORINFO.rcMonitor.Right - MONITORINFO.rcMonitor.Left) * screenTwipsPerPixelX
'
' .WorkHeight = (MONITORINFO.rcWork.Bottom - MONITORINFO.rcWork.Top) * screenTwipsPerPixelY
' .WorkWidth = (MONITORINFO.rcWork.Right - MONITORINFO.rcWork.Left) * screenTwipsPerPixelX
'
' .IsPrimary = MONITORINFO.dwFlags And MONITORINFOF_PRIMARY
' End With
'
Exit Function
GetMonitorInformation_Err:
'Beep
If Err.Number = 453 Then
'should be handled if pre win2k compatibility is required
'Non-Multimonitor OS, return -1
'GetMonitorInformation = -1
'etc
End If
On Error GoTo 0
Exit Function
monitorProperties_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure monitorProperties of Module common"
End Function