Jose's Read Only Forum 2023

IT-Consultant: James C. Fuller => Discussion => Topic started by: Frederick J. Harris on November 19, 2016, 05:09:19 AM

Title: Possible Bug In VC19
Post by: Frederick J. Harris on November 19, 2016, 05:09:19 AM
Hi James,

I worked on it several hours today and it appears the VC19 built window is getting truncated to the tune of several pixels.  If you compare two windows side by side from VC19 and anything else the VC19 window is noticeably less in height.  Also, I realized MS keeps adding metrics to GetSystemMetrics.  I'm attaching my work from today.  It is the same app as your code.  I put piles of output log statements in a version to output the system metrics of piles of stuff.  Compare "Output_VC9.txt" to "Output_VC15.txt".  The only difference you'll see is ...

iCxPaddedBorder

...which is gotten through SM_CXPADDEDBORDER.  It comes out as 0 for VC9 and 4 for VC19.  Also, the caption/title bar is larger on VC19 even though GetSystemMetrics is showing no change between compilers.  Its time for me to go to bed but it would be interesting to output GetWindowRect() values between a VC19 window and anything else.  Attached is my app that generated those output files.  I tested with #define TCLib and #define Debug.  You'll be able to figure out what to do.  'till tomorrow.

Fred

PS - gmail won't let me send zip.  I'll post in Jose's Forum
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 19, 2016, 09:24:08 AM
See my answer there
http://www.objreader.com/index.php?topic=73.msg313#msg313
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 19, 2016, 02:23:07 PM
Fred,
VC9??

I tried with c++ cl 18. and it was the same as cl 19.
I do not have any older version to try.

James
Title: Re: Possible Bug In VC19
Post by: Frederick J. Harris on November 19, 2016, 03:33:55 PM
Quote
VC9??

I know the version numbers MS uses are confusing.  My Visual Studio 2008 actually installs its C/C++ files in a directory VC9.  However, if you look at the compiler version output during a typical command line compile, it states VC15.  So there are three somewhat unrelated numbers there.

With Visual Studio Community 2015 the the compiler version number output during a compile is 19!

I just saw your reply Patrice.  Thanks for that info.  Like James I wasn't familiar with that function.  What I was thinking one must do would be to use all the different values returned by GetSystemMetrics() to kind of 'back calculate' what the parameters of the CreateWindowEx() call should be for a specific Client Rectangle.  But that 'Adjust' function does it for you.

For me, I'm not very enamored of Visual Studio Community 2015.  I sweat blood for a week last winter due to a documented compiler bug when I was doing my TCLib work.  The documented bug had to do with Microsoft's attempt to create something like PowerBASIC's Dim At for Classes.   The C++ standard keeps changing, as its user base seems to want to morph it into C#, seems to me.   

Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 19, 2016, 04:01:27 PM

I'm going to do this (thanks to José Roca's AfxWin). Use zeros for width and height and then call this.
Can also be used for dpi aware app's.
I'd still would like to know what is going on!!
James


void    SetClientSize (HWND, long, int, float = 1, float = 1);

void SetClientSize (HWND hwnd, long nWidth, int nHeight, float rxRatio, float ryRatio)
{
    RECT     rc = {0};
    RECT     rcTemp = {0};
    // 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);
    HANDLE   hMenu = GetMenu(hwnd);
    DWORD    dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
    AdjustWindowRectEx( &rc, dwStyle, (hMenu != NULL), GetWindowLongPtr(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 )
    {
        rcTemp = rc;
        rcTemp.bottom = 0x7FFF; // "Infinite" height
        SendMessage(hwnd, (UINT)WM_NCCALCSIZE, (WPARAM)0, (LPARAM)&rcTemp);
        // Adjust our previous calculation to compensate for menu wrapping.
        rc.bottom +=   rcTemp.top;
    }

    // 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 & WS_HSCROLL) == WS_HSCROLL )
    {
        rc.bottom = rc.bottom + GetSystemMetrics( SM_CYHSCROLL);
    }
    if((dwStyle & WS_VSCROLL) == WS_VSCROLL )
    {
        rc.right = rc.right + GetSystemMetrics( SM_CXVSCROLL);
    }
    long     cx = rc.right - rc.left;
    long     cy = rc.bottom - rc.top;
    SetWindowPos(hwnd, NULL, 0, 0, cx, cy, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}


Title: Re: Possible Bug In VC19
Post by: Frederick J. Harris on November 20, 2016, 06:29:02 PM
I worked on it some more Jim, as I found the whole thing curious, but I had to get back to my work.  There are several things I'm not sure about.

For one, I find it curious that two different versions of Visual Studio (my VStudio 2008 and VStudio 2015) create graphical components with different metrics on the same operating system and same computer.  I was using a Win 10 Home HP Envy laptop.  And of course I have both versions of Visual Studio installed on that box.  I guess both have the SDK installed/available that came with each respective version, and with each version would also have the necessary *.lib files.  I can see how those might be different, but they are each linking with the same basic dlls not?  That is, gdi32.dll???  As one of the respondents at CodeGuru mentioned, there must be something going on with manifests or calls to the dlls to tell them to react different for one call from another.

Another thing I find strange is that when you compare the windows side by side the title bars are obviously of a different height.  I mean, its visually not even a close call.  On the VS2015 the title bar is unmistakingly deeper.  Yet the calls to GetSystemMetrics to retrieve that height reveals them the same for both windows.  I was able to piece everything together in terms of sizes with GetSystemMetrics calls for my VS 2008 windows, but not for the VS2015 windows.

In any case, the code Patrice and Jose provided seems to resolve the issue, so I don't know if there is any more point in wondering about it.
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 20, 2016, 06:42:25 PM
The answer is quite obvious, Visual Studio 2015 uses the latest SDK (the one from Windows 8+ 10)
while 2008 version uses the older SDK.

There are many new API starting with the SDK for Windows 8+, and of course they are not available with previous SDK build.
For example the touchscreen API is much simpler with the latest SDK.
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 20, 2016, 08:12:58 PM
Patrice,
  Yes different SDK's but they are all accessing the same User32.dll ?

I did a loadlibray and still got the same results???

James


typedef HWND (__stdcall *BCXFPROT1)(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID);

// **********[ DLL Declarations ]**********

    HMODULE  H_USER32 = LoadLibrary("User32.dll");
    if(H_USER32 == NULL) {
        MessageBox (GetActiveWindow(), "Failed to load library \nUser32.dll", "Load Library Error", 0 );
        return 1;
    }
    bc9CreateWindow = (BCXFPROT1)GetProcAddress(H_USER32, "CreateWindowExA");
    if(bc9CreateWindow == NULL) {
        MessageBox (GetActiveWindow(), "Failed to find process \nbc9CreateWindow", "Find Process Error", 0 );
        return 1;
    }

// ****************************************

hWin = bc9CreateWindow( dwStyleEx, szClassName, "What is your name? ", dwStyle, ( GetSystemMetrics( SM_CXSCREEN) - 246) / 2, ( GetSystemMetrics( SM_CYSCREEN) - 110) / 2, 246, 110, 0, 0, hInst, NULL);
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 20, 2016, 08:29:19 PM
Patrice,
  It is not a Win 8.1 10 sdk thing.
It fails with the VS 2012 express also.

James
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 20, 2016, 11:57:39 PM
I never had such problem when using AdjustWindowrRect, with 2010 (Pro), 2013 (Pro) , 2015 (Community),
and same with PB 9.05 and PB 10.04.

AdjustWindowRect has always served me well, since the first version of my WinLIFT skin engine long ago.
Title: Re: Possible Bug In VC19
Post by: Frederick J. Harris on November 21, 2016, 12:25:34 AM
Quote
It fails with the VS 2012 express also.

Its working for you now with AdjustWindowRectEx() isn't it?
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 21, 2016, 12:47:43 AM
Patrice,
  I did not mean your solution I meant my original failing code.
All works fine with both your's and José's solutions.
I am just trying to figure out why my original code fails and where the changes are documented. Fred said the original code worked fine with vs 2008. What changed and where is it documented?
James
Title: Re: Possible Bug In VC19
Post by: Frederick J. Harris on November 21, 2016, 04:55:22 AM
Maybe Patrice or Jose know where its documented, and maybe not.  I sure don't.

All the way back to my first coding of Windows with Windows 95 every new version of Windows changed the metrics of the various constituents of a window, e.g., the size of the title bar, the thickness of borders, etc.  And it just came to my attention in fooling around with this that the numbers of the various equates passed into GetSystemMetrics() keeps growing as things become more complicated.  I always figurred that if one needed to code an app at a high level of generalization (works on everything) one would have to make calls to all those GetSystemMetrics() values and code accordingly.  I guess that's why in trying to understand this I tried to understand it through the GetSystemMetrics() function figuring that one could find the differences there.  I couldn't quite piece it all together though for VS 2015.  Maybe if I worked harder and longer at it.  But if AdjustWindowRectEx() or AdjustWindowRect() takes care of it anyway, I'm not certain its worth the trouble.  After all we're kind of talking about proprietary stuff internal to Windows here.
Title: Re: Possible Bug In VC19
Post by: José Roca on November 21, 2016, 10:45:34 AM
AdjustWindowRect calls AdjustWindowRectEx passing 0 as the extended style:


BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect  (  LPRECT   lpRect,
      DWORD    dwStyle,
      BOOL     bMenu
   ) 
   
   {
   return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
}


AdjustWindowRextEx checks if the window is hooked and, if it is not, calls an internal function called RealAdjustWindowRectEx:


BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx   (  LPRECT   lpRect,
      DWORD    dwStyle,
      BOOL     bMenu,
      DWORD    dwExStyle
   ) 
   
   {
   BOOL Hook, Ret = FALSE;

   LoadUserApiHook();

   Hook = BeginIfHookedUserApiHook();

     /* Bypass SEH and go direct. */
   if (!Hook) return RealAdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);

   _SEH2_TRY
   {
      Ret = guah.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
   }
   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
   {
   }
   _SEH2_END;

   EndUserApiHook();

   return Ret;
}


And this is the RealAdjustWindowRectEx function:


BOOL WINAPI RealAdjustWindowRectEx  (  LPRECT   lpRect,
      DWORD    dwStyle,
      BOOL     bMenu,
      DWORD    dwExStyle
   ) 
   
   {
   SIZE BorderSize;

   if (bMenu)
   {
      lpRect->top -= GetSystemMetrics(SM_CYMENU);
     }
     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
     {
        if (dwExStyle & WS_EX_TOOLWINDOW)
           lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
        else
           lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
     }
     UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
     InflateRect(
        lpRect,
        BorderSize.cx,
        BorderSize.cy);
 
     return TRUE;
  }


And the UserGetWindowBorders procedure called by RealAdjustWindowRectEx:


VOID UserGetWindowBorders  (  DWORD    Style,
      DWORD    ExStyle,
      SIZE *   Size,
      BOOL     WithClient
   ) 
   
   {
   DWORD Border = 0;

   if (UserHasWindowEdge(Style, ExStyle))
      Border += 2;
   else if (ExStyle & WS_EX_STATICEDGE)
      Border += 1;
   if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
      Border += 2;
   if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
      Border ++;
   Size->cx = Size->cy = Border;
   if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
   {
      Size->cx += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
      Size->cy += GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
   }
   Size->cx *= GetSystemMetrics(SM_CXBORDER);
   Size->cy *= GetSystemMetrics(SM_CYBORDER);
}


What I don't know is if this code is still being used as is by the newest Windows versions or if they have changed it.
Title: Re: Possible Bug In VC19
Post by: José Roca on November 21, 2016, 10:54:49 AM
Because I was tired of seeing the size of the client window to change with each version of Windows, because of different sizes of gui elements such the caption, I wrote the function AfxSetWindowClientSize that is a wraper for AdjustWindowRectEx, but also taking into account possible menu wrapping and the WS_VSCROLL and WS_HSCROLL styles. I borrowed the code for menu wrapping from somewhere.
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 21, 2016, 11:20:13 AM
José,
  This PbWin10 SDK code does not truncate the window on my Win10 64 machine.

'======================================================================
' Declares
'----------------------------------------------------------------------
#COMPILE EXE
'----------------------------------------------------------------------
#IF %PB_REVISION < &H1000 ' if compiler PBWIN9 or earlier
    %USEMACROS = 1
#ENDIF
#INCLUDE "WIN32API.INC"
'----------------------------------------------------------------------
%IDC_EDIT100       = 100


'======================================================================
FUNCTION WINMAIN (BYVAL hInst AS DWORD, BYVAL hPrevInstance AS DWORD, _
                  BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
'----------------------------------------------------------------------
' Program entrance
'----------------------------------------------------------------------
  LOCAL hDlg AS DWORD, hCtl AS DWORD, hFont AS DWORD, _
        sBuf AS STRING, wc AS WndClassEx, szClassName AS ASCIIZ * 80

  hFont = GetStockObject(%DEFAULT_GUI_FONT)

  szClassName      = "MyClassName"
  wc.cbSize        = SIZEOF(wc)
  wc.style         = %CS_HREDRAW OR %CS_VREDRAW
  wc.lpfnWndProc   = CODEPTR(WndProc)
  wc.cbClsExtra    = 0
  wc.cbWndExtra    = 0
  wc.hInstance     = hInst
  wc.hIcon         = LoadIcon  (%NULL, BYVAL %IDI_APPLICATION)
  wc.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
  wc.hbrBackground = %COLOR_3DFACE + 1
  wc.lpszMenuName  = %NULL
  wc.lpszClassName = VARPTR(szClassName)
  wc.hIconSm       = LoadIcon  (%NULL, BYVAL %IDI_APPLICATION)
  CALL RegisterClassEx (wc)

  hDlg = CreateWindowEx(%WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT OR %WS_EX_WINDOWEDGE, szClassName, "What is your name?", _
              %WS_POPUP OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CAPTION OR _
              %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT OR %DS_MODALFRAME OR _
              %DS_CENTER, _
              (GetSystemMetrics(%SM_CXSCREEN) - 246) / 2, _
              (GetSystemMetrics(%SM_CYSCREEN) - 110) / 2, _
               246, 110, 0, 0, GetModuleHandle(""), BYVAL %NULL)

  hCtl = CreateWindowEx(%WS_EX_CLIENTEDGE, "Edit", BYVAL %NULL, _
              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %ES_AUTOHSCROLL, _
               21, 20, 201, 19, _
               hDlg, %IDC_EDIT100, GetModuleHandle(""), BYVAL %NULL)
  IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

  hCtl = CreateWindowEx(0, "Button", "OK", _
              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _
               51, 52, 60, 23, _
               hDlg, %IDOK, GetModuleHandle(""), BYVAL %NULL)
  IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

  hCtl = CreateWindowEx(0, "Button", "Cancel", _
              %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _
               126, 52, 60, 23, _
               hDlg, %IDCANCEL, GetModuleHandle(""), BYVAL %NULL)
  IF hFont THEN SendMessage hCtl, %WM_SETFONT, hFont, 0

  ShowWindow hDlg, nCmdShow
  UpdateWindow hDlg

  LOCAL Msg AS tagMsg
  WHILE GetMessage(Msg, %NULL, 0, 0)
      TranslateMessage Msg
      DispatchMessage Msg
  WEND

  FUNCTION = msg.wParam
END FUNCTION


'======================================================================
FUNCTION WndProc (BYVAL hWnd AS DWORD,  BYVAL wMsg AS DWORD, _
                  BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
'----------------------------------------------------------------------
' Main Window procedure
'----------------------------------------------------------------------
  SELECT CASE wMsg
  CASE %WM_CREATE
      'A good place to initiate things, declare variables,
      'create controls and read/set settings from a file, etc.
      '-------------------------------------------------------

  CASE %WM_COMMAND
      'Messages from controls and menu items are handled here.
      '-------------------------------------------------------
      SELECT CASE LOWRD(wParam)
      CASE %IDCANCEL  ' <- Esc key also triggers %IDCANCEL
          IF HIWRD(wParam) = %BN_CLICKED OR HIWRD(wParam) = 1 THEN
              SendMessage hWnd, %WM_DESTROY, wParam, lParam
              FUNCTION = 0 : EXIT FUNCTION
          END IF

      CASE %IDOK      ' <- Enter key usually triggers %IDOK
          IF HIWRD(wParam) = %BN_CLICKED OR HIWRD(wParam) = 1 THEN
              ' do whatever...
          END IF

      CASE %IDC_EDIT100
          SELECT CASE HIWRD(wParam)
          CASE %EN_UPDATE     ' Text is about to be changed
          CASE %EN_CHANGE     ' Text has changed
          CASE %EN_SETFOCUS   ' Control is getting focus
          CASE %EN_KILLFOCUS  ' Control is losing focus
          END SELECT

      END SELECT

  CASE %WM_CTLCOLORBTN, %WM_CTLCOLOREDIT, %WM_CTLCOLORLISTBOX, %WM_CTLCOLORSTATIC
      ' wParam is handle of control's display context (hDC)
      ' lParam is handle of control
      ' Example on how to set colors to a specific control:
      '-----------------------------------------------------
      'IF lParam = GetDlgItem(hWnd, CtlId) THEN
      '   SetBkColor wParam, GetSysColor(%COLOR_INFOBK)
      '   SetTextColor wParam, GetSysColor(%COLOR_INFOTEXT)
      '   FUNCTION = GetSysColorBrush(%COLOR_INFOBK)
      '   EXIT FUNCTION
      'END IF
      '-----------------------------------------------------

  CASE %WM_DESTROY
      ' is sent when program ends - a good place to delete any created objects and
      ' store settings in file for next run, etc. Must send PostQuitMessage to end
      ' properly in SDK-style dialogs. The PostQuitMessage function sends a WM_QUIT
      ' message to the program's (thread's) message queue, and then WM_QUIT causes
      ' the GetMessage function to return zero in WINMAIN's message loop.
      '----------------------------------------------------------------------------
      PostQuitMessage 0
      FUNCTION = 0 : EXIT FUNCTION

  CASE %WM_SIZE
      IF wParam <> %SIZE_MINIMIZED THEN
          ' LOWRD(lParam) = width of dialog's client area
          ' HIWRD(lParam) = height of dialog's client area
          ' Example that resizes a control to dialog's client area:
          '------------------------------------------------------
          'SetWindowPos GetDlgItem(hWnd, CtlId), 0, 0, 0, _
          '             LOWRD(lParam), HIWRD(lParam), _
          '             %SWP_NOMOVE OR %SWP_NOZORDER
      END IF

  END SELECT

  FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
END FUNCTION



No other compiler I have tried:
PbWin9
PbWin10
PbCC6
PbCC5
NUWEN GCC Distro
TDM-GCC Distro
PellesC 8
Tiny C 9.26
truncates the window except Visual Studio 2012 Express and Visual Studio 2015 Community.


James
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 21, 2016, 12:11:36 PM
Scrollbars must be part of the client area (they are drawn directly by the OS itself) except with a Skin engine.

Also the scrollbars could be turned on or off, or only the vertical or the horizontal could be visible.
Or they can be enabled only after the window has been shown, based on what should be shown in it.

Think of a POPUP LISTBOX with the WS_EX_TOOLWINDOW StyleEx and any combination of WS_VSCROLL and/or WS_HSCROLL, like with my zTrace utility.

...


Title: Re: Possible Bug In VC19
Post by: José Roca on November 21, 2016, 12:22:58 PM
And what happens if you want that the visible content won't be reduced by the scrollbars? If you don't care, then call AdjustWindowRextEx directly.
Title: Re: Possible Bug In VC19
Post by: James C. Fuller on November 21, 2016, 01:18:56 PM
Ok gentlemen you have convinced me:  "resistance is futile" :)
I tried adding WS_SCROLL | WS_HSCROLL to the style and of course it was as you said with all compilers.
I was worried my port of José's code would not work with the other compilers but all is well.
One item I feel should be in all c++ developers toolbox is the NUWEN distro:
https://nuwen.net/mingw.html
Take a check of his web site.

But the still unanswered question is when did the change take place with VS and where is it documented?

James
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 21, 2016, 02:28:09 PM
For me the best window style is... WS_POPUP, without anything else, then you can take the control of your window just as you want.

Remember this old thread
http://www.jose.it-berater.org/smfforum/index.php?topic=1164.0

8)
Title: Re: Possible Bug In VC19
Post by: Mike Lobanovsky on November 22, 2016, 01:33:09 AM
Quote from: Patrice Terrier on November 21, 2016, 12:11:36 PM
Scrollbars must be part of the client area (they are drawn directly by the OS itself) ...

Strictly speaking I'm afraid this isn't exactly so, Patrice.

Windows native scrollbars, disabled or enabled alike, that it adds in response to the WS_VSCROLL/WS_HSCROLL window styles, as opposed to their common or user control varieties, are not part of the window client area once they pop up automatically into view at app start or become visible through programmatic methods at some later point in time:Contrary to that, the Common Controls' Flat Scroll Bar or custom user control scrollbars would be hosted in the window client area just like any other ordinary static or button or whatever controls and would not affect the window (non-)client area sizes, accessors or hit tests, and their underlying area would still be reported as HTCLIENT area. Of course, if you wouldn't fool the OS with your custom zzTop() hit testing in the meantime. :)
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 22, 2016, 10:06:06 AM
Here is how i check in WinLIFT (in polling mode)  if the scrollbars are visible or not.
(Using a combination of GetWindowRect and GetClientRect)

long skCheckScrollBar (IN HWND hWnd) {
//  Check if the control's scrollbars are shown.
//  Returns zero if (none, 1 if vertical, 2 if horizontal and 3 if both.
    RECT rw = {0}, rc = {0};
    long nRet = SCROLLBAR_NONE;
    if (IsWindowVisible(hWnd)) { // 06-25-2015
        GetWindowRect(hWnd, &rw);
        GetClientRect(hWnd, &rc);
        if (rc.right <= rw.right - rw.left - GetSystemMetrics(SM_CXVSCROLL)) { nRet = SCROLLBAR_VERT; }
        if (rc.bottom <= rw.bottom - rw.top - GetSystemMetrics(SM_CXHSCROLL)) { nRet = nRet + SCROLLBAR_HORZ; }
    }
    return nRet;
}


and for more oddities play with: menu, toolbar, statusbar, rebar and the like.
Title: Re: Possible Bug In VC19
Post by: Frederick J. Harris on November 22, 2016, 03:31:15 PM
It looks like you've opened up a can of worms Jim! :)
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 22, 2016, 03:57:01 PM
QuoteIt looks like you've opened up a can of worms Jim

And i have a couple more, when dealing with Windows 8+ 10, and moving unexpectedly a window outside of the bound edges of the desktop.

You must absolutly handle properly these messages:

    case %WM_GETMINMAXINFO
         pMM = lParam
         @pMM.ptMinTrackSize.x = gP.MinTrackSizeW
         @pMM.ptMinTrackSize.y = gP.MinTrackSizeH
         function = 0: exit function

    case %WM_MOVING '// Keep the window into the working area
         hMonitor = MonitorFromWindow(hWnd, %MONITOR_DEFAULTTONEAREST)
         lpr = lParam
         if (@lpr.nTop < 0) then @lpr.nTop = 0
         @lpr.nRight = @lpr.nLeft + gP.MinTrackSizeW
         @lpr.nBottom = @lpr.nTop + gP.MinTrackSizeH
         tmi.cbSize = sizeof(tmi)
         if (GetMonitorInfo(hMonitor, tmi)) then
             if (@lpr.nBottom > tmi.rcWork.nBottom) then
                 @lpr.nBottom = tmi.rcWork.nBottom
                 @lpr.nTop = @lpr.nBottom - gP.MinTrackSizeH
             end if
         end if
         function = %TRUE: exit function


Or Windows will resize your window based on its own rules despite of the minimum client size you specify, terrible when using a non-client area that doesn't use the Windows default theme.
Title: Re: Possible Bug In VC19
Post by: Mike Lobanovsky on November 23, 2016, 06:12:55 AM
Quote from: Patrice Terrier on November 22, 2016, 10:06:06 AMmore oddities play with: menu, toolbar, statusbar, rebar and the like.

These, except for the menu that is a genuine non-client HTMENU area of the window, are all HTCLIENT area controls that don't affect the rectangle returned by a GetClientArea() call. In other words, they behave like ordinary labels, buttons, checkboxes, progressbars, etc. that you would put into the window client area to enable user interaction in accordance with your app's intended purposes. It's just another story that they are normally auto-resizable and would snap in their places all by themselves seamlessly unless given visible border styles of their own to discern them from the adjacent non-client spaces at a glance.

Quote from: Patrice Terrier on November 22, 2016, 03:57:01 PMAnd i have a couple more, when dealing with Windows 8+ 10 ...

You'd have a lot more than that had you tried to skin windows that belong to a process other than your own -- something such SW as e.g. Stardock Corp.'s WindowBlinds does. :)
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 23, 2016, 11:56:00 AM
Mike--

A skin engine is not intendend to skin the whole Windows UI, but only a specific window.
And you can use simultaneously different skins with specific applications.

On the other hand WindowBlinds is a Theme engine that substitutes its own graphic components in lieu of those being used by Windows, meaning ALL the windows have the same look (except those skinned).

Theming is {easier to program} than Skinning, because you just have to replace the default Windows theme components.
However there is much more graphic art work to do with theming to create all the bitmaps needed, including icons and a specific wallpapers background set. Doable only if you have a team of talented artist to concieve new themes.

Note: with Theming, all the GetSystemMetrics functions are matching those used by the theme.
Title: Re: Possible Bug In VC19
Post by: Mike Lobanovsky on November 23, 2016, 08:28:58 PM
Quote from: Patrice Terrier on November 23, 2016, 11:56:00 AMA skin engine is not intendend to skin the whole Windows UI, but only a specific window.

Contemporary Eclecta (FBSL's official IDE application) is a very heavily skinned "specific window". Skinning (in your sense of the word) helps me keep the user environment consistent across the platforms and is also a tribute to XP that was the greatest OS I ever used.

Eclecta also happens to utilize a lot of owned child processes as its tools and utilities, and it would've been unnatural should all of them keep on using their own skins and colors, even if beautifully themed by a mature OS which of course can hardly be expected of such a graphical and metrical nuisance as Windows 10.

I guess Eclecta's skinning lies on the borderline between what you call themeing and skinning "a specific window" proper.

In fact the 64-bit Unicode child window chaos in Win 10's Calculator and Task Monitor was the only real reason why I would install Win 10 Pro Anniversary Edition at all. :)
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 24, 2016, 09:56:47 AM
Interresting threads about the same problem

http://stackoverflow.com/questions/11783086/get-exact-window-region-size-createwindow-window-size-isnt-correct-size-of-wi

http://stackoverflow.com/questions/27928254/adjustwindowrectex-and-getwindowrect-give-wrong-size-with-ws-overlapped

When in aero mode, see also the DwmGetWindowAttribute (https://msdn.microsoft.com/en-us/library/windows/desktop/aa969515(v=vs.85).aspx) function

Windows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing.
The borders might look like this: 7,0,7,7 (left, top, right, bottom)

http://stackoverflow.com/questions/34139450/getwindowrect-returns-a-size-including-invisible-borders
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 24, 2016, 12:46:07 PM
Rather than GetWindowRect, use this API to retrieve the correct size in DWM AERO mode

RECT lpr = { 0 };
HRESULT hRes =  DwmGetWindowAttribute(hWin, DWMWA_EXTENDED_FRAME_BOUNDS, &lpr, sizeof(RECT));


And to detect if DWM is enabled, here is what i am doing in WinLIFT

long zDwmIsCompositionEnabled () {
    long nRet = 0;
    HMODULE hLib = LoadDWM();
    if (hLib) {
        long_proc (BOOL*);
        zProc hProc = (zProc) GetProcAddress(hLib, "DwmIsCompositionEnabled");
        if (hProc) {
            BOOL bAero = FALSE;
            if (hProc(&bAero) == 0) {
                if (bAero) { nRet = -1; }
            }
        }
    }
    return nRet;
}


Title: Re: Possible Bug In VC19
Post by: Mike Lobanovsky on November 25, 2016, 12:09:52 PM
Quote from: Patrice Terrier on November 24, 2016, 09:56:47 AMWindows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing.
The borders might look like this: 7,0,7,7 (left, top, right, bottom)

http://stackoverflow.com/questions/34139450/getwindowrect-returns-a-size-including-invisible-borders

Hehe, thanks for this link Patrice!

It actually points to an answer (at the very bottom of the page) that contains yet another link:

http://winaero.com/blog/enable-the-hidden-aero-lite-theme-in-windows-10/

which teaches us how to non-intrusively enable Windows 10 unofficial Aero Lite theme that would make those invisible border extras fully visible and that would also bring the GetWindowRect() returns back to their expected visually consistent values! :)

For all intents and purposes, Aero Lite is roughly equivalent to Basic-style non-Aero theming in Vista and 7.

Addendum to the above link:

Once you double-click the new AeroLite.theme file on your desktop to install the new Basic-like theme in your system, you may safely delete this file from your desktop altogether. The new theme will be installed permanently alongside the other themes available via standard Personalization->Theming functionality.
Title: Re: Possible Bug In VC19
Post by: Patrice Terrier on November 25, 2016, 01:43:11 PM
About the transparent border section, i am using exactly the same concept when running WinLIFT with a composited Skin.
it is based on the use of transparent png components, and this allows me to create shadow or Hallo effects.

This is clearly visible on this WinLIFT screenshot

(http://www.zapsolution.com/pictures/wlftwdm.jpg)

This is the reason why i have always considered the client size when skinning a window rather than its WindowRect, because i knew that it is changing from one OS to another.

Since VISTA i have always used DWM, and the Device Window Manager API allows me to create any Skin i could imagine with full variable opacity, as you can see on the caption of the screenshot.

WinLIFT has its own skGetSystemMetrics API to retrieve the correct size of its non-client parts.
And notice the use of SK_DWM_LEFT, SK_DWM_TOP, SK_DWM_RIGHT, SK_DWM_BOTTOM.

long skGetSystemMetrics (IN long nMeasure) { // dllexport

    if ((nMeasure > -1) || (nMeasure < SKMETRIC_UB)) {
        long xWidth, yHeight, CyCaption, CxFrameLeft, CxFrameRight, CyFrameBottom, CxFrame, CyMenu;
       
        switch (nMeasure) {
        case SK_CYCAPTION:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYCAPTION"));
                if (g_nMetrics[nMeasure] == 0) {
                   skGetBitmapSize(g_CaptionM, xWidth, CyCaption);
                   g_nMetrics[nMeasure] = CyCaption;
                }
             }
             break;
        case SK_CYMENU:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                skGetBitmapSize(g_MenuBar, xWidth, CyMenu);
                g_nMetrics[nMeasure] = CyMenu;
             }
             break;
        case SK_CYSTATUS:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = 0;
                if (CheckStyle(skWindowStyle(0), SK_STATUSBAR)) {
                   g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYSTATUS"));
                }
             }
             break;
        case SK_CXFRAMELEFT:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXFRAMELEFT"));
                if (g_nMetrics[nMeasure] == 0) {
                   skGetBitmapSize(g_SideL, CxFrameLeft, yHeight);
                   g_nMetrics[nMeasure] = CxFrameLeft;
                }
             }
             break;
        case SK_CXFRAMERIGHT:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXFRAMERIGHT"));
                if (g_nMetrics[nMeasure] == 0) {
                   skGetBitmapSize(g_SideR, CxFrameRight, yHeight);
                   g_nMetrics[nMeasure] = CxFrameRight;
                }
             }
             break;
        case SK_CYFRAMEBOTTOM:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYFRAMEBOTTOM"));
                if (g_nMetrics[nMeasure] == 0) {
                   skGetBitmapSize(g_BottomM, xWidth, CyFrameBottom);
                   g_nMetrics[nMeasure] = CyFrameBottom;
                }
             }
             break;
        case SK_CXSIZE:     // Dimension of caption button in pixels
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXSIZE"));
             }
        case SK_CYSIZE:     // Dimension of caption button in pixels
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYSIZE"));
             }
             break;
        case SK_CXSYSBUT:   // Right X seed for system buttons
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXSYSBUT"));
                if (g_nMetrics[nMeasure] == 0) {
                   skGetBitmapSize(g_SideL, CxFrame, yHeight);
                   g_nMetrics[nMeasure] = CxFrame;
                   if (g_nMetrics[nMeasure] == 0) { g_nMetrics[nMeasure] = 6; }
                }
             }
             break;
        case SK_CYSYSBUT:     // Right Y seed for system buttons
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYSYSBUT"));
             }
             break;
        case SK_CXCAPTEXT:    // X coordinate for Caption text
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXCAPTEXT"));
             }
             break;
        case SK_CYCAPTEXT:    // Y coordinate for Caption text
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYCAPTEXT"));
             }
             break;
        case SK_XBUT3DBORDER: // Horizontal non stretched button border
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"XBUT3DBORDER"));
             }
             break;
        case SK_YBUT3DBORDER: // Vertical non stretched button border
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"YBUT3DBORDER"));
             }
             break;
        case SK_CXSYSICON:    // X seed for system icon
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXSYSICON"));
             }
             break;
        case SK_CYSYSICON:    // Y seed for system icon
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYSYSICON"));
             }
             break;
        case SK_CXSYSLED:     // X coordinate for Caption led
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CXSYSLED"));
             }
             break;
        case SK_CYSYSLED:     // Y coordinate for Caption led
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"CYSYSLED"));
             }
             break;
        case SK_TRANSLUCENCY: // Translucency
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"TRANSLUCENCY"));
                if (g_nMetrics[nMeasure] == 0) { g_nMetrics[nMeasure] = 50; }
             }
             break;
        case SK_MENUTRANSLUCENCY: // Menu translucency percentage
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"MENUTRANSLUCENCY"));
                if (g_nMetrics[nMeasure] == 0) { g_nMetrics[nMeasure] = 100; }
             }
             break;
        case SK_PAINT_BORDER:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"PAINT_BORDER"));
             }
             break;
        case SK_PAINT_BACKGROUND:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"PAINT_BACKGROUND"));
             }
             break;
        case SK_ICONSIZE:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = max(LongVAL(skLoadString(L"ICONSIZE")), 16);
             }
             break;
        case SK_OUTER_GLOW:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"OUTER_GLOW"));
             }
             break;
        case SK_SKIN_ICON:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"SKIN_ICON"));
             }
             break;
        case SK_DWM_AERO:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"DWM_AERO"));
                if (zDwmIsCompositionEnabled() == 0) { g_nMetrics[nMeasure] = 0; }
             }
             break;
        case SK_DWM_LEFT:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"DWM_LEFT"));
             }
             break;
        case SK_DWM_TOP:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"DWM_TOP"));
             }
             break;
        case SK_DWM_RIGHT:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"DWM_RIGHT"));
             }
             break;
        case SK_DWM_BOTTOM:
             if (g_nMetrics[nMeasure] == MESURE_UNDEFINED) {
                g_nMetrics[nMeasure] = LongVAL(skLoadString(L"DWM_BOTTOM"));
             }
             break;
        }
        return g_nMetrics[nMeasure]; }
    else {
        return 0;
    }
}

Title: Re: Possible Bug In VC19
Post by: Mike Lobanovsky on November 25, 2016, 05:37:38 PM
Patrice,

I told you more than once that for over a decade now (which is effectively forever) I've been, and still am, a dedicated admirer of your beautiful GUIs. :)

It's just that I can't go the same route for fear lest you might think I'm reverse-engineering your GDImage.dll. ;D

This is exactly why my skinning engine in fact suppresses entirely any Windows system drawing in the non-client area (Classic, Basic and Aero alike), reassigns to it a new window region of known skin-dependent size, intersects it with the window's existing client area region, and draws in this new non-client region fixing the hit-test flags as necessary to match my custom sizes and placement of caption buttons and system icon, as well as the size of caption and menu and the size, placement and spaces between the menu buttons, SDI and MDI. Naturally both the system and main menu panes are entirely owner-drawn as well.

Frankly, it takes so much effort that I've never been physically able to go beyond rebars, toolbars and statusbars and get down to simpler targets like buttons, checkboxes, option buttons, progressbars, and especially scrollbars. :)