Announcement

Collapse
No announcement yet.

DOSBOX location control from PBWIN

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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 MECHLER

  • #2
    ... 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?
    If you shell the DOS program with by means of the CreateProcess WinAPI function, I think you can specify the starting position and size of the command prompt in the STARTUPINFO structure.

    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.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Bob --

      It's possible that my company's "DOSBox Tools" product would solve your problems...

      -- Eric Pearson
      "Not my circus, not my monkeys."

      Comment


      • #4
        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

        Comment


        • #5
          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

          Comment


          • #6
            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

            Comment


            • #7
              Code updated for multi monitor

              Bob,

              If you feel like cheating,
              I updated above code to work in a multi monitors environnement...

              Pierre

              Comment


              • #8
                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

                Comment


                • #9
                  Both previous program are updated
                  to react corectly even if second monitor
                  is made the main monitor via Windows monitor property options.

                  Pierre

                  Comment


                  • #10
                    Thanks Pierre!

                    Bob Mechler

                    Comment

                    Working...
                    X