WinFBX window client area width

Windows specific questions.
Post Reply
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

WinFBX window client area width

Post by deltarho[1859] »

@JosepRoca

Hi José

Have you imposed a limit on the width of the client area of a window.

pWindow.SetClientSize( x, y )

x = 150 => width of 150
x = 140 => width of 140
x = 130 => width of 136
x = 120 => width of 136
x = 110 => width of 136

I hit a barrier at 136.

Thanks.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

I don't, but Windows does. It needs a minimum width to display things such the application icon and, depending of the styles used, the maximize/minimize button and the close button.

The SetClientSize calls the wrapper procedure AfxSetWindowClientSize (see below), which calls the API function AdjustWindowRectEx and does some tweaks to solve limitations of AdjustWindowRectEx regarding wrapped menus and scrollbars and the fact that it is not DPI aware. See: AdjustWindowRectEx function ( https://docs.microsoft.com/en-us/window ... ndowrectex )

Code: Select all

' ========================================================================================
' Adjusts the bounding rectangle of a window based on the desired size of the client area.
' Parameters:
' - hwnd = The window handle.
' - nWidth and nHeight = The desired size of the client area.
' - rxRatio and ryRatio = Scaling ratios.
' ========================================================================================
PRIVATE SUB AfxSetWindowClientSize (BYVAL hwnd AS HWND, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL rxRatio AS SINGLE = 1, BYVAL ryRatio AS SINGLE = 1)

   DIM rc AS RECT, rcTemp  AS RECT
   ' // Convert the client rectangle to a window rectangle.
   ' // The AdjustWindowRectEx function cannot take menu wrapping into account
   ' // because it doesn't know which menu we are using.
   SetRect(@rc, 0, 0, nWidth * rxRatio, nHeight * ryRatio)
   DIM hMenu AS HANDLE = GetMenu(hwnd)
   DIM dwStyle AS DWORD = GetWindowLongPtrW(hwnd, GWL_STYLE)
   AdjustWindowRectEx(@rc, dwStyle, (hMenu <> NULL), GetWindowLongPtrW(hwnd, GWL_EXSTYLE))
   ' // If there is a menu, we need to check how much wrapping occurs when we set
   ' // the window to the width specified by AdjustWindowRectEX and an infinite
   ' // amount of height. An infinite height allows us to see every single menu wrap.
   IF hMenu <> NULL THEN
      rcTemp = rc
      rcTemp.Bottom = &H7FFF   ' // "Infinite" height
      SendMessageW(hwnd, WM_NCCALCSIZE, 0, CAST(LPARAM, @rcTemp))
      ' // Adjust our previous calculation to compensate for menu wrapping.
      rc.Bottom = rc.Bottom + rcTemp.Top
   END IF
   ' // The AdjustWindowRectEx function does not take the WS_VSCROLL or WS_HSCROLL
   ' // styles into account. To account for the scroll bars, we need to call the
   ' // GetSystemMetrics function with SM_CXVSCROLL or SM_CYHSCROLL.
   IF (dwStyle AND WS_HSCROLL) = WS_HSCROLL THEN
      rc.Bottom = rc.Bottom + GetSystemMetrics(SM_CYHSCROLL)
   END IF
   IF (dwStyle AND WS_VSCROLL) = WS_VSCROLL THEN
      rc.Right = rc.Right + GetSystemMetrics(SM_CXVSCROLL)
   END IF
   DIM cx AS LONG = rc.Right - rc.Left
   DIM cy AS LONG = rc.Bottom - rc.Top
   SetWindowPos(hwnd, NULL, 0, 0, cx, cy, SWP_NOZORDER OR SWP_NOMOVE OR SWP_NOACTIVATE)

END SUB
' ========================================================================================
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

Thanks José.

I found some code by Paul Squires, and he was setting 120 and getting 120. When he created the window he used WS_POPUP among the styles whereas I did not.

With PowerBASIC WS_POPUP is included as a default style.

Image

I ported a function from PowerBASIC. What with parameters being ByRef by default in PowerBASIC and ByVal by default in FreeBASIC and FreeBASIC's strong type casting it took me half a morning to get no errors and, just as important, get the correct results. I am still getting seven warnings five of which are 'Passing scalar as pointer' and I reckon none of them are true. So how big is this function? Ten lines! Seven warnings in ten lines must be a record. Is the application working? Yep!

How you and Paul manage to write Windows GUIs in FreeBASIC and maintain your sanity is beyond me. It probably explains why there not many members writing Windows GUIs in FreeBASIC. Image

Added: I have decided to use '-w none' and be damned.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

> With PowerBASIC WS_POPUP is included as a default style.

PowerBASIC uses the Windows Dialog Engine, which is intended for dialog boxes, and defaults to a WS_POPUP style. SDK programmers use WS_OVERLAPPED for main windows. Of course, you can use WS_POPUP with CWindow by specifying this style in the Create method of by calling the WindowStyle property after Create.

> What with parameters being ByRef by default in PowerBASIC and ByVal by default in FreeBASIC [...]

I always have specified BYVAL or BYREF in all parameters, even with PowerBASIC.

> I am still getting seven warnings five of which are 'Passing scalar as pointer'

If you can post the code, I'm sure there is an easy solution. PBer's are used to always declare variables as LONG or DWORD. The key is to declare the variables with the appropriate type to match the API declarations.

> How you and Paul manage to write Windows GUIs in FreeBASIC and maintain your sanity is beyond me. It probably explains why there not many members writing Windows GUIs in FreeBASIC.

It was very annoying at the beginning, but you get used to it. Your main problem is that all that DDT stuff that you have learned is totally useless with SDK programming.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

I returned to the function above where I had seven warnings. I am no longer getting any warnings and this is the result.

Cast(hWnd, hWnd) and Cast(hFont, hFont) Image

The mind boggles.

I have been reading the source code in WinFBE and did a 'containing text' search on Cast in the inc files and found reams of them, about 3% of the lines with some files.

Code: Select all

FUNCTION GetTextWidth (BYVAL hWnd AS Dword, BYVAL txt AS WSTRING Ptr) AS LONG
  Dim hDC AS HDC, hFont AS DWORD, sz AS SIZE
  hDC = GetDc(Cast(hWnd, hWnd))
  hFont = SendMessage(Cast(Hwnd, hWnd), WM_GETFONT, 0, 0)
  Cast(hFont, hFont) = SelectObject(hDC, Cast(hFont, hFont))
  GetTextExtentPoint32 hDC, txt, LEN(*txt), @sz
  SelectObject hDC, Cast(hFont, hFont)
  ReleaseDC Cast(hWnd, hWnd), hDC
  FUNCTION = sz.cx
END FUNCTION
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

You don't need so many casts if you write the code properly, i.e.

Code: Select all

FUNCTION GetTextWidth (BYVAL hWnd AS HWND, BYVAL txt AS WSTRING Ptr) AS LONG
  Dim hDC AS HDC, hFont AS HFONT, sz AS SIZE
  hDC = GetDc(hWnd)
  hFont = CAST(HFONT, SendMessage(hWnd, WM_GETFONT, 0, 0))
  hFont = SelectObject(hDC, hFont)
  GetTextExtentPoint32 hDC, txt, LEN(*txt), @sz
  SelectObject hDC, hFont
  ReleaseDC hWnd, hDC
  FUNCTION = sz.cx
END FUNCTION
Besides, it will work with both 32 and 64-bit compilers.

Using hWnd AS Dword instead of hWnd AS HWND and hFont AS DWORD instead of hFont AS HFONT means that the code won't work in 64-bit, because handles are 4 bits in 32 bit, but 8 bytes in 64 bit. HWND is a typedef that evaluates to 4 or 8 bytes depending of the compiler. Same with HFONT. As I said above, "The key is to declare the variables with the appropriate type to match the API declarations."

The only time that we need to use CAST is in hFont = CAST(HFONT, SendMessage(hWnd, WM_GETFONT, 0, 0)), because SendMessage is a generic function that retuns an LRESULT.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

Hmmm, I now get five warnings.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

Five warning in this function (I don't think so, because I don't get any) or in other parts of the code? Maybe you have handles declared as DWORD or something like that.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

José wrote:(I don't think so, because I don't get any)
I don't now.

I still had

Code: Select all

Declare FUNCTION GetTextWidth ( As Dword, As WSTRING Ptr) As LONG
and that needed to be changed to

Code: Select all

Declare FUNCTION GetTextWidth ( As hWnd, As WSTRING Ptr) As LONG
That mistake threw up four warnings, not five as I said - there was another warning with some later code.

With Encrypternet, which is only a 1066 line source code, I used Cast 32 times, 3% of the code, and that compiled in 32-bit and 64-bit without errors or warnings, so I obviously got that right.

However, an inordinate amount of time was spent getting the casting right in addition to reading up on some APIs at MSDN which I had never used before.

I don't care what anyone says writing Windows GUIs in FreeBASIC is torturous.

Let the machine do the dirty work. -- Kernighan and Ritchie, "Elements of Programming Style"

I have a computer in front of me, and I am having to do the dirty work. Image

> there was another warning with some later code.

I used 'Dim hMutex As Long' and I should have used 'Dim hMutex As Handle'. So it is not just parameters we need to watch but the API's return value as well. That line was ported from PowerBASIC. Image
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

> With Encrypternet, which is only a 1066 line source code, I used Cast 32 times

You must be doing something wrong. I don't need to use cast so often.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

Yours truly wrote:I have been reading the source code in WinFBE and did a 'containing text' search on Cast in the inc files and found reams of them, about 3% of the lines with some files.
Clearly there is an art to it that few of us have managed to fully grasp.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: WinFBX window client area width

Post by Josep Roca »

To avoid many of the casting problems, declare the variables as the same type that you will find in the declarations in MSDN or in the FB .bi files. Just be aware that C++ INT does not traslate to FB INTEGER, but to INT_ or LONG, and UINT does not translate to FB UINTEGER, but to UINT_ or DWORD. This is because a peculiarity of FB INTEGER/UINTEGER data types that are interpreted as 32bit or 64-bit depending of the compiler that you're using.

If you declare handles and/or pointers as DWORD/LONG, you're going to have many problems, not only casting, but it won't work with 64-bit. It is not the same to work with a 32-bit only compiler like PB, that to write applications that can be compiled to 32 or 64 bit without changes in the code. If one day PB released a 64-bit compiler, trying to adapt existing PB applications would be a nightmare.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBX window client area width

Post by deltarho[1859] »

José wrote:If one day PB released a 64-bit compiler, trying to adapt existing PB applications would be a nightmare.
The phrase "rude awakening" comes to mind. I wonder if anyone over there has thought about that.
Post Reply