Announcement

Collapse
No announcement yet.

Works PB8, Fails PB9 ?? Need ideas

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

  • Works PB8, Fails PB9 ?? Need ideas

    I'm trying to move to PB9 but a program I've got is giving me a pain.

    Status:
    • Compiles and runs fine in PB8
    • Compiles clean in PB9 after cleaning up a few new KWs (like TIX)
    • In PB9 the program window does NOT get drawn topmost and does NOT have the focus.


    The program uses a keyboard hook (Not a GLOBAL hook).

    When run, either from the IDE or from a compiled EXE, the window opens below other windows, the Titlebar does not show the window as having focus and all typing still goes to whichever window had the KB focus before (like PBEdits).

    Clicking the window to give it the focus and all is well, the program runs just fine. It's just not getting control (and focus) when launched. This failure is ONLY with PB9, with PB8 all works normally.

    I can't post the whole program (its 9000+ lines) but I've finally managed to pare it down to a small sample which shows the failure. All it does is open a graphic window, accept keyboard chars and echo to the graphic window.

    Here's the problem code. Yes it looks weird since I've cut/pasted it together from the main code and then deleted as much code as possible to reduce the 'noise'.
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    UNION MsgDataLayout
       MsgWparam AS LONG
       MsgString AS STRING * 4
    END UNION
    %IDC_SPFLiteWindow = 120
    GLOBAL hWnd AS LONG
    GLOBAL hDC AS LONG
    GLOBAL FontName      AS STRING
    GLOBAL FontPitch     AS INTEGER
    GLOBAL FontHeight    AS INTEGER
    GLOBAL FontWidth     AS INTEGER
    GLOBAL ScrWidth      AS INTEGER
    GLOBAL ScrHeight     AS INTEGER
    GLOBAL ghKbrdHook    AS LONG
    GLOBAL KeyChr        AS STRING
    
    
    
    FUNCTION PBMAIN () AS LONG
    LOCAL x, y AS LONG, t AS STRING
       FontName = "Terminal": FontPitch = 12: ScrWidth = 60: ScrHeight = 30
    
       '---------- Create a hidden basic screen based on the Profile screen sizes
       DIALOG NEW PIXELS, 0, "PB8PB9 Problem", 200, 200, 20, 20, _
                          %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU TO hWnd
       CONTROL ADD GRAPHIC, hWnd, %IDC_SPFLiteWindow,"", 0, 0, 20, 20
    
       '---------- Get the Height/Width of the desired Font
       GRAPHIC ATTACH hWnd, %IDC_SPFLiteWindow               ' Using the graphic window
       GRAPHIC FONT FontName, FontPitch, 0                   ' Set the desired font
       GRAPHIC CHR SIZE TO FontWidth, FontHeight             ' Get size of a character in that font
    
       '---------- Destroy the old window & re-create now in the new size for the new font
       DIALOG END hWnd, 0                                    ' Shut the current Dialog & Re-Open
       x = ScrWidth * FontWidth + 3: y = Scrheight * FontHeight + 3 ' Calc window in desired font size
       '
       '------ The following statement in PB8 works fine, in PB9 window open up NOT ON TOP and without the Focus
       '
       DIALOG NEW PIXELS, 0, "PB8PB9 Problem", 100, 100, x, y, %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, TO hWnd
    
       CONTROL ADD GRAPHIC, hWnd, %IDC_SPFLiteWindow,"", 0, 0, x, y
       GRAPHIC ATTACH hWnd, %IDC_SPFLiteWindow               ' Set as the default graphic area
       GRAPHIC CLEAR 0                                       ' Clear the background
       GRAPHIC FONT FontName, FontPitch, 0
       SetWindowText(hWnd, "PB8PB9 Problem")                 ' Alter window title
       DIALOG SHOW MODAL hWnd CALL DlgCallback               '
       CONTROL SET FOCUS hWnd, %IDC_SPFLiteWindow
    END FUNCTION
    
    CALLBACK FUNCTION DlgCallback()
    '---------- MAIN DIALOG'S CALLBACK PROCEDURE
    LOCAL i, j AS INTEGER
    LOCAL Msg AS MsgDataLayout
    
       SELECT CASE AS LONG CBMSG
          CASE %WM_INITDIALOG
             ghKbrdHook = SetWindowsHookEx(%WH_KEYBOARD, CODEPTR(KeyBoardHook), _
                          0, GetCurrentThreadId)
    
          CASE %WM_DESTROY                                   ' Sent when the dialog is being destroyed
             UnhookWindowsHookEx ghKbrdHook                  ' Kill the Keyboard hook
    
          CASE %WM_USER                                      ' KeyBoardHook is sending us a Key
             Msg.MsgWparam = CBWPARAM                        ' Put wParam into the UNION
             KeyChr = TRIM$(Msg.MsgString)                   ' Convert string into KeyChr
             IF LEN(KeyChr) = 0 THEN KeyChr = " "            ' Don't TRIM away spaces
             CALL KeyBoard()                                 ' Let Keyboard routine have a go
    
       END SELECT
    END FUNCTION
    
    
    FUNCTION KeyBoardHook(BYVAL iCode AS INTEGER, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS DWORD
    '---------- Examine all keyboard traffic
    DIM KeyStateArray(0 TO 255) AS BYTE
    LOCAL KeyCode AS INTEGER
    LOCAL ScanCode AS INTEGER
    LOCAL ScanCodeL AS LONG
    LOCAL Chars AS STRING * 2
    LOCAL i AS LONG
    LOCAL KMsg AS MsgDataLayout
       IF iCode < 0  THEN
          FUNCTION = CallNextHookEx(ghKbrdHook, iCode, wParam, lParam)
          EXIT FUNCTION
       END IF
       CallNextHookEx(ghKbrdHook, iCode, wParam, lParam)
       IF iCode <> %HC_ACTION THEN EXIT FUNCTION             ' Exit if not a Keyboard action
       KeyChr = ""                                           ' Clear our ultimate answer
       KeyCode = wParam                                      ' Get the keycode
       ScanCodeL = lparam                                    ' Get the ScanCode
       SHIFT LEFT ScanCodeL, 8                               '
       SHIFT RIGHT ScanCodeL, 24                             '
       ScanCode = ScanCodeL                                  '
       IF KeyCode = 0 THEN EXIT FUNCTION                     ' Bail out if somehow nothing
       IF (lParam AND &H80000000) <> 0 THEN EXIT FUNCTION    ' Key UP?  Just exit
       '---------- Get flags set for special keys
       GetKeyboardState(BYVAL VARPTR(KeyStateArray(0)))      ' Get all key states etc
       i = ToAsciiEx(KeyCode, ScanCode, BYREF KeyStateArray(0), _
                           BYVAL VARPTR(Chars), 0, GetKeyboardLayout(0))
       IF i < 0 THEN                                         ' Diaetric Dead key?
          FUNCTION = 1                                       ' Set RC = 1
          EXIT FUNCTION                                      ' Just Exit
       END IF
       IF i = 2 THEN                                         ' If 2 then we had an unused dead key
          KMsg.MsgString = LEFT$(LEFT$(Chars,1)+"   ", 4)    ' Pass back the first key
          i = PostMessage(hWnd, %WM_USER, KMsg.MsgwParam, 0)
          i = 1: MID$(Chars, 1, 1) = MID$(Chars, 2, 1)       ' Make it look like only one key now
       END IF
    
       IF i = 1 THEN                                         ' We have an ASCII character
          IF KeyChr = "" THEN KeyChr = LEFT$(Chars,1)        ' If still "" then it's a 'normal' alpha type key
       END IF
    
       IF LEN(KeyChr) > 0 THEN
          KMsg.MsgString = LEFT$(KeyChr+"   ", 4)
          IF LEFT$(KeyChr,3) = "CHR" THEN KMsg.MsgString = MID$(KeyChr,4,1) + "   "
          i = PostMessage(hWnd, %WM_USER, KMsg.MsgwParam, 0)
          FUNCTION = 1
       ELSE
          FUNCTION = 0
       END IF
    END FUNCTION
    
    SUB KeyBoard()
    '---------- Keyboard processor
    STATIC col AS LONG
       col = col + FontWidth
       GRAPHIC SET POS (col, 100)
       GRAPHIC PRINT KeyChr;
    END SUB

  • #2
    I would say something with Create-->Destroy-->Recreate

    Some minor changes, and whola, works as expected in 8 and 9 on a Vista machine.

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    UNION MsgDataLayout
       MsgWparam AS LONG
       MsgString AS STRING * 4
    END UNION
    %IDC_SPFLiteWindow = 120
    GLOBAL hWnd AS LONG
    GLOBAL hDC AS LONG
    GLOBAL FontName      AS STRING
    GLOBAL FontPitch     AS INTEGER
    GLOBAL FontHeight    AS INTEGER
    GLOBAL FontWidth     AS INTEGER
    GLOBAL ScrWidth      AS INTEGER
    GLOBAL ScrHeight     AS INTEGER
    GLOBAL ghKbrdHook    AS LONG
    GLOBAL KeyChr        AS STRING
    
    
    
    FUNCTION PBMAIN () AS LONG
    LOCAL x, y AS LONG, t AS STRING
       FontName = "Terminal": FontPitch = 12: ScrWidth = 60: ScrHeight = 30
    
       '---------- Create a hidden basic screen based on the Profile screen sizes
       DIALOG NEW PIXELS, 0, "PB8PB9 Problem", 200, 200, 200, 200, _
                          %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU TO hWnd
       CONTROL ADD GRAPHIC, hWnd, %IDC_SPFLiteWindow,"", 0, 0, 200, 200
    
       '---------- Get the Height/Width of the desired Font
       GRAPHIC ATTACH hWnd, %IDC_SPFLiteWindow               ' Using the graphic window
       GRAPHIC FONT FontName, FontPitch, 0                   ' Set the desired font
       GRAPHIC CHR SIZE TO FontWidth, FontHeight             ' Get size of a character in that font
    
       '---------- Destroy the old window & re-create now in the new size for the new font
    '   DIALOG END hWnd, 0                                    ' Shut the current Dialog & Re-Open
    '   x = ScrWidth * FontWidth + 3: y = Scrheight * FontHeight + 3 ' Calc window in desired font size
    '   '
    '   '------ The following statement in PB8 works fine, in PB9 window open up NOT ON TOP and without the Focus
    '   '
    '   DIALOG NEW PIXELS, 0, "PB8PB9 Problem", 100, 100, x, y, %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, TO hWnd
    '
    '   CONTROL ADD GRAPHIC, hWnd, %IDC_SPFLiteWindow,"", 0, 0, x, y
       GRAPHIC ATTACH hWnd, %IDC_SPFLiteWindow               ' Set as the default graphic area
       GRAPHIC CLEAR 0                                       ' Clear the background
       GRAPHIC FONT FontName, FontPitch, 0
       SetWindowText(hWnd, "PB8PB9 Problem")                 ' Alter window title
       DIALOG SHOW MODAL hWnd CALL DlgCallback               '
       CONTROL SET FOCUS hWnd, %IDC_SPFLiteWindow
    END FUNCTION
    
    CALLBACK FUNCTION DlgCallback()
    '---------- MAIN DIALOG'S CALLBACK PROCEDURE
    LOCAL i, j AS INTEGER
    LOCAL Msg AS MsgDataLayout
    
       SELECT CASE AS LONG CBMSG
          CASE %WM_INITDIALOG
             ghKbrdHook = SetWindowsHookEx(%WH_KEYBOARD, CODEPTR(KeyBoardHook), _
                          0, GetCurrentThreadId)
    
          CASE %WM_DESTROY                                   ' Sent when the dialog is being destroyed
             UnhookWindowsHookEx ghKbrdHook                  ' Kill the Keyboard hook
    
          CASE %WM_USER                                      ' KeyBoardHook is sending us a Key
             Msg.MsgWparam = CBWPARAM                        ' Put wParam into the UNION
             KeyChr = TRIM$(Msg.MsgString)                   ' Convert string into KeyChr
             IF LEN(KeyChr) = 0 THEN KeyChr = " "            ' Don't TRIM away spaces
             CALL KeyBoard()                                 ' Let Keyboard routine have a go
    
       END SELECT
    END FUNCTION
    
    
    FUNCTION KeyBoardHook(BYVAL iCode AS INTEGER, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS DWORD
    '---------- Examine all keyboard traffic
    DIM KeyStateArray(0 TO 255) AS BYTE
    LOCAL KeyCode AS INTEGER
    LOCAL ScanCode AS INTEGER
    LOCAL ScanCodeL AS LONG
    LOCAL Chars AS STRING * 2
    LOCAL i AS LONG
    LOCAL KMsg AS MsgDataLayout
       IF iCode < 0  THEN
          FUNCTION = CallNextHookEx(ghKbrdHook, iCode, wParam, lParam)
          EXIT FUNCTION
       END IF
       CallNextHookEx(ghKbrdHook, iCode, wParam, lParam)
       IF iCode <> %HC_ACTION THEN EXIT FUNCTION             ' Exit if not a Keyboard action
       KeyChr = ""                                           ' Clear our ultimate answer
       KeyCode = wParam                                      ' Get the keycode
       ScanCodeL = lparam                                    ' Get the ScanCode
       SHIFT LEFT ScanCodeL, 8                               '
       SHIFT RIGHT ScanCodeL, 24                             '
       ScanCode = ScanCodeL                                  '
       IF KeyCode = 0 THEN EXIT FUNCTION                     ' Bail out if somehow nothing
       IF (lParam AND &H80000000) <> 0 THEN EXIT FUNCTION    ' Key UP?  Just exit
       '---------- Get flags set for special keys
       GetKeyboardState(BYVAL VARPTR(KeyStateArray(0)))      ' Get all key states etc
       i = ToAsciiEx(KeyCode, ScanCode, BYREF KeyStateArray(0), _
                           BYVAL VARPTR(Chars), 0, GetKeyboardLayout(0))
       IF i < 0 THEN                                         ' Diaetric Dead key?
          FUNCTION = 1                                       ' Set RC = 1
          EXIT FUNCTION                                      ' Just Exit
       END IF
       IF i = 2 THEN                                         ' If 2 then we had an unused dead key
          KMsg.MsgString = LEFT$(LEFT$(Chars,1)+"   ", 4)    ' Pass back the first key
          i = PostMessage(hWnd, %WM_USER, KMsg.MsgwParam, 0)
          i = 1: MID$(Chars, 1, 1) = MID$(Chars, 2, 1)       ' Make it look like only one key now
       END IF
    
       IF i = 1 THEN                                         ' We have an ASCII character
          IF KeyChr = "" THEN KeyChr = LEFT$(Chars,1)        ' If still "" then it's a 'normal' alpha type key
       END IF
    
       IF LEN(KeyChr) > 0 THEN
          KMsg.MsgString = LEFT$(KeyChr+"   ", 4)
          IF LEFT$(KeyChr,3) = "CHR" THEN KMsg.MsgString = MID$(KeyChr,4,1) + "   "
          i = PostMessage(hWnd, %WM_USER, KMsg.MsgwParam, 0)
          FUNCTION = 1
       ELSE
          FUNCTION = 0
       END IF
    END FUNCTION
    
    SUB KeyBoard()
    '---------- Keyboard processor
    STATIC col AS LONG
       col = col + FontWidth
       GRAPHIC SET POS (col, 100)
       GRAPHIC PRINT KeyChr;
    END SUB
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

    Comment


    • #3
      Hi Cliff,

      Yes, your changes work (after all why create/destroy/create a window?)

      Well in the main program, the destroy/create part is actually a sub that can be called once the program is running to resize the window. e.g. when the user switches to another font/size.

      So this routine is also called on normal startup once the program reads its INI variables and knows what's needed.

      Actually the initial create is needed only so I can do a GRAPHIC CHAR SIZE to get the font height/width. I couldn't find another way to get the font's cell size in pixels.

      So it looks like I'm missing something in the destroy/recreate part, maybe 'cus at startup the dummy window never actually has a DIALOG SHOW done for it.

      Basically I need to be able to build the window at startup the correct size to match the users selected Font parameters. And I need to be able to later on alter them as well.

      But you've pointed me at the area to have another look at.

      Thanks
      George

      Comment


      • #4
        I have tested PB9 variant on AMD and Intel processors and found that on Intel proc. it works fine without any changes, like PB8 version ...

        Comment


        • #5
          George,

          I found the same issue when PB9 first came out and submitted a report of same.

          My 'solution' was to create the 'dummy' dialog with only the %WS_DISABLED attribute. Then I could destroy it and create the 'real' thing more or less as you did (and for more or less the same reasons).

          Comment


          • #6
            I don't use DDT (so I could be completely wrong) but you are setting the focus after the call to show the Dialog as modal. I expect that the SetFocus call will not get executed until your Modal message pump ends (i.e. when the Dialog is closed).

            DIALOG SHOW MODAL hWnd CALL DlgCallback
            CONTROL SET FOCUS hWnd, %IDC_SPFLiteWindow

            Why not move the CONTROL SET FOCUS to your %WM_INITDIALOG message handler?
            Paul Squires
            FireFly Visual Designer (for PowerBASIC Windows 10+)
            Version 3 now available.
            http://www.planetsquires.com

            Comment


            • #7
              OK, we have a solution! These forums are the greatest.

              Aslan: Yes my system is an AMD Phenom Quad 4. But what on earth can be going on? I've never seen CPU type cause problems with ordinary programs.

              Bill: Your solution works just fine, both in the little test program and with the full main program.

              Paul: That set focus was one of my 'flailing around' attempts and I spotted it lying around after I'd uploaded the test code.

              I'm from the old 'poke and prod' school of debugging, even when I 'know' better. I figure if what's there SHOULD word but doesn't, then the reverse should be true - sometimes.

              Thank you all for your efforts.

              Comment


              • #8
                Although not specifically listed in the HISTORY.TXT, this problem seems to be fixed in 9.01.

                Comment


                • #9
                  I don't use DDT (so I could be completely wrong) but you are setting the focus after the call to show the Dialog as modal. I expect that the SetFocus call will not get executed until your Modal message pump ends (i.e. when the Dialog is closed).
                  You are not wrong. DIALOG SHOW MODAL is like the DialogBox() API: does not return until dialog is destoyed.

                  DIALOG SHOW MODELESS is the counterpart CreateDialog() and returns after WM_INITDIALOG has been processed.
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment

                  Working...
                  X