Search code examples
winapivb6setwindowlonggetwindowlong

VB6 SetWindowLong Causing Refresh Issue in Windows 7 64-bit


I am still supporting and old vb6 application that utilizes GetWindowLong and SetWindowLong to remove the ControlBox at runtime depending on a setting. This works great on all 32-bit systems but when it runs on a 64bit system the main window no longer refreshes properly. The problem seems to be input controls like TextBox, ListBox, or CommandButton. After being covered up by certain windows they don't display until they receive the focus and even then their borders don't show up properly.

I've read the MSDN documentation http://msdn.microsoft.com/en-us/library/ms633591%28v=vs.85%29.aspx that says these functions have been superseded by ...WindowLongPtr functions to be compatible with both 32-bit and 64-bit systems. From everything I've been able to read that is really talking about compiling both 32-bit and 64-bit version instead of running on the different platforms. I've tried changing my declare from

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

To

Public Declare Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

But I get the error "Can't find DLL entry point GetWindowLongPtrA in user32". So I tried leaving the Alias as "...WindowLongA" and that runs and as I would expect doesn't make any difference in the refresh problem.

Has anybody else seen this or have any suggestions.

Here is a sample of how the code is used.

Private Sub Form_Activate()
   ...
   Call SetControlBox(Me.hWnd, DisableFullScreen)
End Sub


Public Sub SetControlBox(ByVal hWnd As Long, ByVal Value As Boolean)
   ' Set WS_SYSMENU On or Off as requested.
   Call FlipBit(hWnd, WS_SYSMENU, Value)
End Sub

Public Function FlipBit(ByVal hWnd As Long, ByVal Bit As Long, ByVal Value As Boolean) As Boolean
   Dim nStyle As Long

   ' Retrieve current style bits.
   nStyle = GetWindowLongPtr(hWnd, GWL_STYLE)

   ' Attempt to set requested bit On or Off,
   ' and redraw
   If Value Then
      nStyle = nStyle Or Bit
   Else
      nStyle = nStyle And Not Bit
   End If
   Call SetWindowLongPtr(hWnd, GWL_STYLE, nStyle)
   Call Redraw(hWnd)

   ' Return success code.
   FlipBit = (nStyle = GetWindowLongPtr(hWnd, GWL_STYLE))
End Function

Public Sub Redraw(ByVal hWnd As Long)
   ' Redraw window with new style.
   Const swpFlags As Long = SWP_FRAMECHANGED Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOSIZE
   SetWindowPos hWnd, 0, 0, 0, 0, 0, swpFlags
End Sub

Thanks

dbl


Solution

  • Try adding SWP_NOACTIVATE (&H10) bit to your swpFlags constant.

    Btw, this redraws non-client area only. A name like RedrawNonclient would make it apparent.