Thanks Pierre!
Bob Mechler
Announcement
Collapse
No announcement yet.
DOSBOX location control from PBWIN
Collapse
X
-
Both previous program are updated
to react corectly even if second monitor
is made the main monitor via Windows monitor property options.
Pierre
Leave a comment:
-
Create a centered dialog on second monitor
Also,
For the fun of it, following code will create a dialog that will
start centered on the second monitor, if any.
Pierre
Code:#COMPILE EXE '#Win 8.03# #DIM ALL #INCLUDE "Win32Api.inc" '#2005-01-27# %Label1 = 201 GLOBAL hDlg AS DWORD %DISPLAY_DEVICE_MODESPRUNED = &h8000000 %DISPLAY_DEVICE_REMOVABLE = &h20 TYPE MonitorInfoAddr ArrayAddress AS DWORD MonitorCount AS DWORD END TYPE TYPE MonitorInfoData hMonitor AS DWORD hdcMonitor AS DWORD Clip AS RECT END TYPE TYPE DISPLAY_DEVICE_EX 'Old DISPLAY_DEVICE in Win32api cb AS DWORD DeviceName AS ASCIIZ * 32 DeviceString AS ASCIIZ * 128 StateFlags AS DWORD DeviceID AS ASCIIZ * 128 DeviceKey AS ASCIIZ * 128 END TYPE '______________________________________________________________________________ FUNCTION MonInfoEnumProc(BYVAL hMonitor AS DWORD, BYVAL hdcMonitor AS DWORD, _ BYREF Clip AS RECT, BYVAL dwData AS DWORD) AS LONG LOCAL pMonitorDataAddr AS MonitorInfoAddr POINTER LOCAL Looper AS LONG STATIC LastMonitor AS DWORD REDIM PRESERVE MonitorData(0 TO LastMonitor) AS STATIC MonitorInfoData 'This FOR/NEXT is needed to reset data only if EnumDisplayMonitors is called more than once FOR Looper = 0 TO LastMonitor IF MonitorData(Looper).hMonitor = hMonitor THEN LastMonitor = 0 REDIM PRESERVE MonitorData(0 TO LastMonitor) AS STATIC MonitorInfoData EXIT FOR END IF NEXT MonitorData(LastMonitor).hMonitor = hMonitor MonitorData(LastMonitor).hdcMonitor = hdcMonitor MonitorData(LastMonitor).Clip = Clip pMonitorDataAddr = dwData @pMonitorDataAddr.MonitorCount = LastMonitor + 1 @pMonitorDataAddr.ArrayAddress = VARPTR(MonitorData(0)) INCR LastMonitor FUNCTION = %TRUE END FUNCTION '______________________________________________________________________________ CALLBACK FUNCTION DlgProc END FUNCTION '______________________________________________________________________________ FUNCTION PBMAIN() LOCAL MonitorDataAddr AS MonitorInfoAddr LOCAL MonitorData AS MONITORINFOEX LOCAL DisplayDevice AS DISPLAY_DEVICE_EX LOCAL SecondaryMonitor AS LONG LOCAL Looper AS LONG LOCAL Buffer AS STRING LOCAL MainRect AS RECT LOCAL MainSizeX AS LONG LOCAL MainSizeY AS LONG EnumDisplayMonitors(BYVAL %NULL, BYVAL %NULL, BYVAL CODEPTR(MonInfoEnumProc), VARPTR(MonitorDataAddr)) DIM MonitorData(0 TO MonitorDataAddr.MonitorCount - 1) AS MonitorInfoData AT MonitorDataAddr.ArrayAddress Buffer = "" FOR Looper = 0 TO MonitorDataAddr.MonitorCount - 1 Buffer = Buffer & _ "Monitor " & STR$(Looper) & $CRLF & _ "Monitor handle is" & STR$(MonitorData(Looper).hMonitor) & $CRLF & _ "Monitor hdc is" & STR$(MonitorData(Looper).hdcMonitor) & $CRLF & _ "Left:" & STR$(MonitorData(Looper).Clip.nLeft) & $CRLF & _ "Top:" & STR$(MonitorData(Looper).Clip.nTop) & $CRLF & _ "Right:" & STR$(MonitorData(Looper).Clip.nRight) & $CRLF & _ "Bottom:" & STR$(MonitorData(Looper).Clip.nBottom) & $CRLF & $CRLF NEXT FOR Looper = 0 TO MonitorDataAddr.MonitorCount - 1 MonitorData.cbSize = SIZEOF(MonitorData) 'Ask for MONITORINFOEX GetMonitorInfo BYVAL MonitorData(Looper).hMonitor, BYVAL VARPTR(MonitorData) IF (MonitorData.dwFlags AND %MONITORINFOF_PRIMARY) = 0 THEN SecondaryMonitor = Looper EXIT FOR END IF NEXT DIALOG NEW %HWND_DESKTOP ,"Centered on secondary monitor !", , , 210, 150, _ '200 150 %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, %NULL TO hDlg SetClassLong hDlg, %GCL_HICON, LoadIcon(BYVAL %NULL, BYVAL %IDI_INFORMATION) CONTROL ADD LABEL, hDlg, %Label1, Buffer, 15, 10, 170, 130 IF MonitorDataAddr.MonitorCount = 2 THEN GetWindowRect hDlg, MainRect 'Get dialog position and size MainSizeX = MainRect.nRight - MainRect.nLeft MainRect.nLeft = MonitorData(SecondaryMonitor).Clip.nLeft + _ ((MonitorData(SecondaryMonitor).Clip.nRight - _ MonitorData(SecondaryMonitor).Clip.nLeft) / 2) - _ MainSizeX / 2 MainRect.nRight = MainRect.nLeft + MainSizeX MainSizeY = MainRect.nBottom - MainRect.nTop MainRect.nTop = MonitorData(SecondaryMonitor).Clip.nTop + _ ((MonitorData(SecondaryMonitor).Clip.nBottom - _ MonitorData(SecondaryMonitor).Clip.nTop) / 2) - _ MainSizeY / 2 MainRect.nBottom = MainRect.nTop + MainSizeY SetWindowPos hDlg, %HWND_TOP, MainRect.nLeft, MainRect.nTop, 0, 0, _ %SWP_NOSIZE OR %SWP_NOZORDER OR %SWP_SHOWWINDOW END IF DIALOG SHOW MODAL hDlg CALL DlgProc '--------------------------------------------------------------------- EnumDisplayDevices Buffer = "" FOR Looper = 0 TO MonitorDataAddr.MonitorCount - 1 DisplayDevice.cb = SIZEOF(DisplayDevice) EnumDisplayDevices(BYVAL %NULL, Looper, BYVAL VARPTR(DisplayDevice), BYVAL %NULL) 'Nonzero if succees Buffer = Buffer & _ "DeviceName: " & DisplayDevice.DeviceName & $CRLF & _ "DeviceString: " & DisplayDevice.DeviceString & $CRLF & _ "DeviceID: " & DisplayDevice.DeviceID & $CRLF & _ "DeviceKey: " & DisplayDevice.DeviceKey & $CRLF & _ "StateFlags: " & HEX$(DisplayDevice.StateFlags) & $CRLF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) THEN Buffer = Buffer & "DISPLAY_DEVICE_ATTACHED_TO_DESKTOP" & $CRLF END IF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_PRIMARY_DEVICE) THEN Buffer = Buffer & "DISPLAY_DEVICE_PRIMARY_DEVICE" & $CRLF END IF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_MIRRORING_DRIVER) THEN Buffer = Buffer & "DISPLAY_DEVICE_MIRRORING_DRIVER" & $CRLF END IF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_MODESPRUNED) THEN Buffer = Buffer & "DISPLAY_DEVICE_MODESPRUNED" & $CRLF END IF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_REMOVABLE) THEN Buffer = Buffer & "DISPLAY_DEVICE_REMOVABLE" & $CRLF END IF IF (DisplayDevice.StateFlags AND %DISPLAY_DEVICE_VGA_COMPATIBLE) THEN Buffer = Buffer & "DISPLAY_DEVICE_VGA_COMPATIBLE" & $CRLF END IF Buffer = Buffer & $CRLF NEXT MSGBOX Buffer,, "EnumDisplayDevices on primary monitor" END FUNCTION '______________________________________________________________________________
Last edited by Pierre Bellisle; 12 Sep 2007, 12:42 PM. Reason: Updated for swapped primary/secondary monitor
Leave a comment:
-
Code updated for multi monitor
Bob,
If you feel like cheating,
I updated above code to work in a multi monitors environnement...
Pierre
Leave a comment:
-
Pierre,
Works fine with a single display but hugs right corner of monitor 1 if I move
the program to the second monitor. Looks promising though. I'll play with the return values of the dialog position and see what I can do.
Bob Mechler
Leave a comment:
-
Center SHELLed dialog, multi monitor aware
Bob,
You may also try the following...
Pierre
Code:#COMPILE EXE '#Win 8.03# #DIM ALL #INCLUDE "Win32Api.inc" '#2005-01-27# GLOBAL hDlg AS DWORD GLOBAL hShell AS DWORD %ButtonShell = 101 %Label1 = 201 %Label2 = 202 '______________________________________________________________________________ FUNCTION EnumWindowProc(BYVAL hTry AS LONG, BYVAL ProcessId AS DWORD) AS LONG LOCAL zCaption AS ASCIIZ * %Max_Path LOCAL zClass AS ASCIIZ * %Max_Path LOCAL LenClass AS LONG LOCAL LenCaption AS LONG LOCAL ProcessIdTry AS DWORD hShell = 0 'LenCaption = GetWindowText(hTry, zCaption, %MAX_PATH) 'Get the caption of the dialog 'IF UCASE$(zCaption) = "MYCAPTION" THEN ' hShell = hTry 'ELSE ' FUNCTION = %TRUE 'END IF 'LenClass = GetClassName(hTry, zClass, %MAX_PATH) 'Get the class of the dialog 'IF UCASE$(zClass) = "MYCLASS" THEN ' hShell = hTry 'ELSE ' FUNCTION = %TRUE 'END IF GetWindowThreadProcessId hTry, ProcessIdTry 'Get ProcessId of try window IF ProcessId = ProcessIdTry THEN 'Found our process id ? hShell = hTry ELSE FUNCTION = %TRUE 'True, so Function will recall itself until last window found END IF END FUNCTION '______________________________________________________________________________ CALLBACK FUNCTION DlgProc LOCAL ProcessId AS DWORD LOCAL Looper AS LONG LOCAL DesktopRect AS RECT LOCAL MainRect AS RECT LOCAL ShellRect AS RECT LOCAL ShellSizeX AS LONG LOCAL ShellSizeY AS LONG LOCAL hMonitor AS DWORD LOCAL MonitorData AS MONITORINFOEX LOCAL sBuffer AS STRING SELECT CASE CBMSG CASE %WM_INITDIALOG CASE %WM_COMMAND SELECT CASE LOWRD(CBWPARAM) CASE %ButtonShell IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN ProcessId = SHELL(HANDLES, "Notepad.exe", %SW_HIDE) 'Change to valid stuff... 'Since it will take some time for Windows to create the SHELLed dialog, 'the use of this FOR/NEXT loop will wait up to 10 seconds. FOR Looper = 1 TO 100 'Try for 10 seconds (100 * 0.1 second) EnumWindows CODEPTR(EnumWindowProc), ProcessId IF hShell THEN EXIT FOR SLEEP 100 'Give Windows time to create dialog, 0.1 second delay NEXT IF hShell THEN 'SystemParametersInfo could be used on single monitor system 'SystemParametersInfo %SPI_GETWORKAREA, 0, BYVAL VARPTR(DesktopRect), 0 'Get desktop size 'Multi monitor... 'Get handle of the monitor where our dialog is hMonitor = MonitorFromWindow(BYVAL hDlg, BYVAL %MONITOR_DEFAULTTONEAREST) '%MONITOR_DEFAULTTOPRIMARY %MONITOR_DEFAULTTONEAREST sBuffer = "Monitor handle is" & STR$(hMonitor) 'Get monitor info MonitorData.cbSize = SIZEOF(MonitorData) 'Ask for MONITORINFOEX GetMonitorInfo BYVAL hMonitor, BYVAL VARPTR(MonitorData) IF MonitorData.dwFlags = %MONITORINFOF_PRIMARY THEN sBuffer = sBuffer & ", it is the primary monitor" ELSE sBuffer = sBuffer & ", it is the secondary monitor" END IF sBuffer = sBuffer & $CRLF & "Device name is " & MonitorData.szDevice CONTROL SET TEXT CBHNDL, %Label1, sBuffer sBuffer = "Size is - " & _ "Left:" & STR$(MonitorData.rcWork.nLeft) & _ ", Top:" & STR$(MonitorData.rcWork.nTop) & _ ", Right:" & STR$(MonitorData.rcWork.nRight) & _ ", Bottom:" & STR$(MonitorData.rcWork.nBottom) CONTROL SET TEXT CBHNDL, %Label2, sBuffer DesktopRect = MonitorData.rcWork GetWindowRect hDlg, MainRect 'Get main dialog position and size GetWindowRect hShell, ShellRect 'Get shelled dialog position and size 'Calculate new shelled dialog position... ShellSizeX = ShellRect.nRight - ShellRect.nLeft ShellRect.nLeft =(MainRect.nLeft + (MainRect.nRight - MainRect.nLeft) / 2) - _ (ShellSizeX / 2) ShellRect.nRight = ShellRect.nLeft + ShellSizeX ShellSizeY = ShellRect.nBottom - ShellRect.nTop ShellRect.nTop =(MainRect.nTop + (MainRect.nBottom - MainRect.nTop) / 2) - _ (ShellSizeY / 2) ShellRect.nBottom = ShellRect.nTop + ShellSizeY 'Make sure right side of dialog is visible... IF ShellRect.nRight > DesktopRect.nRight THEN ShellRect.nLeft = DesktopRect.nRight - (ShellRect.nRight - ShellRect.nLeft) ShellRect.nRight = ShellRect.nLeft + ShellSizeX END IF 'Make sure bottom side of dialog is visible... IF ShellRect.nBottom > DesktopRect.nBottom THEN ShellRect.nTop = DesktopRect.nBottom - (ShellRect.nBottom - ShellRect.nTop) ShellRect.nBottom = ShellRect.nTop + ShellSizeY END IF 'Make sure left side of dialog is visible... IF ShellRect.nLeft < DesktopRect.nLeft THEN ShellRect.nLeft = DesktopRect.nLeft ShellRect.nRight = ShellSizeX END IF 'Make sure top side of dialog is visible... IF ShellRect.nTop < DesktopRect.nTop THEN ShellRect.nTop = DesktopRect.nTop ShellRect.nBottom = ShellSizeY END IF 'Set new shelled dialog position SetWindowPos hShell, %HWND_TOP, ShellRect.nLeft, ShellRect.nTop, 0, 0, _ 'ShellSizeX, ShellSizeY, _ %SWP_NOSIZE OR %SWP_NOZORDER OR %SWP_SHOWWINDOW ShowWindow hShell, %SW_SHOWNORMAL END IF END IF END SELECT END SELECT END FUNCTION '______________________________________________________________________________ FUNCTION PBMAIN() DIALOG NEW %HWND_DESKTOP ,"Center shelled program", , , 200, 100, _ %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, %NULL TO hDlg SetClassLong hDlg, %GCL_HICON, LoadIcon(BYVAL %NULL, BYVAL %IDI_INFORMATION) CONTROL ADD LABEL, hDlg, %Label1, "Center shelled program.", 10, 10, 180, 18 CONTROL ADD LABEL, hDlg, %Label2, "Single and multi monitor version.", 10, 30, 180, 18 CONTROL ADD BUTTON, hDlg, %ButtonShell, "Shell program", 70, 50, 60, 20 DIALOG SHOW MODAL hDlg CALL DlgProc END FUNCTION '______________________________________________________________________________
Last edited by Pierre Bellisle; 12 Sep 2007, 12:44 PM. Reason: Added multi monitor capability, update for swapped primary/secondary monitor
Leave a comment:
-
Eric,
I've downloaded the shareware version of DosBox and will evaluate.
We are starting to heavily use SQL Tools professional and find it an excellent, excellent tool that will allow us to move to SQL with our procedural style programs.
Thanks,
Bob Mechler
Leave a comment:
-
Bob --
It's possible that my company's "DOSBox Tools" product would solve your problems...
-- Eric Pearson
Leave a comment:
-
... If I shell to a dos window from a PBwin program, how do I center that dos window over the program that shelled to it?
I know this works for "GUI" child processes, but I'm not sure it works for console processes, or if CMD.EXE actually obeys when it is the child.
Leave a comment:
-
DOSBOX location control from PBWIN
Some of our customers have Dos custom programs that they have not seen fit to upgrade to PBWIN. We are implementing sticky window positioning so that when a dialog is move to a second screen or any position other than center screen, the next PBWIN program called from a menu will appear in the same position. Also while that program is open any popup program that returns values to the underlying maintenance screen will center itself in the larger parent screen. I'm not use MDI but have gotten all the screens in PBWin to work this way by capturing the Windows position with WM_MOVE and then passing it to the next program called. If the target program has a smaller footprint, I do a little math and center the top left so that it will be centered in the calling program.
The Dos programs that are called from a custom menu, I don't know how to control their position from a PBwin program. If only Dos programs are running they retain their position in a multiple monitor scenario on their own.
A long explanation to ask this question. If I shell to a dos window from a PBwin program, how do I center that dos window over the program that shelled to it?
BOB MECHLERTags: None
Leave a comment: