PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  
Pages: [1] 2

Author Topic: FBWinSpy - Preliminary work  (Read 942 times)

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
FBWinSpy - Preliminary work
« on: June 06, 2017, 11:40:48 PM »

Inspired by the tools PBWinSpy by Börje Hagsten and WinSpy, I have done some preliminary work for FBWinSpy.

It extracts information about a GUI and its child controls. This information could be used to attempt to reconstruct the GUI generating code for FreeBasic. As an example, if the GUI has a menu, it generates code to reconstruct it.
« Last Edit: June 12, 2017, 10:30:37 AM by José Roca »
Logged

Johan Klassen

  • FireFly3 Registered User
  • Little Newbie FireFly
  • *
  • Posts: 19
  • FF3 User
Re: FBWinSpy - Preliminary work
« Reply #1 on: June 07, 2017, 04:29:02 AM »

thank you  :)
Logged

Pierre Bellisle

  • FireFly3 User
  • Junior FireFly Member
  • *
  • Posts: 57
Re: FBWinSpy - Preliminary work
« Reply #2 on: June 07, 2017, 01:42:30 PM »

:-)
Logged

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #3 on: June 08, 2017, 01:42:06 AM »

There is an undocumented function to retrieve the DPI awareness of an application, but requires windows 8.1+

Code: [Select]
' ========================================================================================
' Get process DPI awareness (undocumented)
' Untested. Requires Windows 8.1+
' ========================================================================================
FUNCTION GetProcessDpiAwarenessInternal (BYVAL hProcess AS HANDLE, BYVAL pValue AS ULONG PTR) AS BOOLEAN
   DIM pLib AS ANY PTR = DyLibLoad("user32.dll")
   IF pLib = NULL THEN EXIT FUNCTION
   DIM pGetProcessDpiAwarenessInternal AS FUNCTION (BYVAL hProcess AS HANDLE, BYVAL pValue AS ULONG PTR) AS LONG
   pGetProcessDpiAwarenessInternal = DyLibSymbol(pLib, "GetProcessDpiAwarenessInternal")
   IF pGetProcessDpiAwarenessInternal THEN FUNCTION = pGetProcessDpiAwarenessInternal(hProcess, pValue)
   DyLibFree(pLib)
END FUNCTION
' ========================================================================================

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #4 on: June 08, 2017, 01:48:22 AM »

I have added more information. Unfortunately, although I can retrieve the number of parts of a status bar of another application, I can't retrieve the size of the parts. Also limitations with other controls such Toolbars and Rebars.

Code: [Select]
' ========================================================================================
' Retrieve child windows
' ========================================================================================
FUNCTION EnumChildProc (BYVAL hwnd AS HWND, BYVAL lParam AS LPARAM) AS LONG

   DIM wszClassName AS WSTRING * 260 = AfxGetWindowClassName(hwnd)
   DIM cwsText AS CWSTR = wszClassName
   cwsText += "; cID = " & WSTR(GetDlgCtrlID(hwnd))
   cwsText += "; Width = " & WSTR(AfxGetWindowWidth(hwnd))
   cwsText += "; Height = " & WSTR(AfxGetWindowHeight(hwnd))
   cwsText += "; Style = &h" & HEX(AfxGetWindowStyle(hwnd))
   cwsText += "; StyleEx = &h" & HEX(AfxGetWindowExStyle(hwnd))
   cwsText += CHR(13, 10)

   SELECT CASE UCASE(wszClassName)
      CASE "STATIC"
         cwsText += "   - Styles: " & GetStaticStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "BUTTON"
         cwsText += "   - Styles: " & GetButtonStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "TOOLBARWINDOW32"
         cwsText += "   - Styles: " & GetToolbarStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - ExStyles: " & GetToolbarExStyles(Toolbar_GetExtendedStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Buttons: " & WSTR(Toolbar_ButtonCount(hwnd))
         cwsText += "; Width: " & WSTR(Toolbar_GetButtonWidth(hwnd))
         cwsText += "; Height: " & WSTR(Toolbar_GetButtonHeight(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "COMBOBOX"
         cwsText += "   - Styles: " & GetComboBoxStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "LISTBOX"
         cwsText += "   - Styles: " & GetListBoxStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "REBARWINDOW32"
         cwsText += "   - Styles: " & GetRebarStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "EDIT"
         cwsText += "   - Styles: " & GetEditStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "MSCTLS_PROGRESS32"
         cwsText += "   - Styles: " & GetProgressBarStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "MSCTLS_STATUSBAR32"
         cwsText += "   - Styles: " & GetStatusBarStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         DIM nParts AS LONG = StatusBar_GetPartsCount(hwnd)
         cwsText += "   - Parts: " & WSTR(nParts) & "; Text part 1: " & **AfxGetWindowText(hwnd) & CHR(13, 10)
      CASE "SYSTABCONTROL32"
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - ExStyles: " & GetSysTabExStyles(TabCtrl_GetExtendedStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "SYSHEADER32"
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "SYSTREEVIEW32"
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "SYSLISTVIEW32"
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Styles: " & GetListViewStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - ExStyles: " & GetSysTabExStyles(ListView_GetExtendedListViewStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE "RICHED20", "RICHEDIT20A", "RICHEDIT20W", "RICHEDIT", "RICHEDIT50A", "RICHEDIT50W"
         cwsText += "   - Styles: " & GetRichEditStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
      CASE ELSE
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
   END SELECT

   DIM pcws AS CWSTR PTR = cast(CWSTR PTR, lParam)
   IF pcws THEN pcws->Add(cwsText)

   FUNCTION = CTRUE

END FUNCTION
' ========================================================================================

Pierre Bellisle

  • FireFly3 User
  • Junior FireFly Member
  • *
  • Posts: 57
Re: FBWinSpy - Preliminary work
« Reply #5 on: June 08, 2017, 12:54:40 PM »

Hola José,

About the StatusBar, what if you try with VirtualAllocEx(), ReadProcessMemory(), and friends...

Pierre

Code: [Select]

 Dim ByteCount          AS SIZE_T_ Ptr
 Dim pStatusBarRect     AS LPCVOID
 Dim StatusBarRect      AS RECT
 Dim hStatusBar         AS HANDLE
 Dim hProcess           AS HANDLE
 Dim hThread            AS DWORD
 Dim pid                AS DWORD
 Dim StatusBarPartId    AS LONG
 Dim StatusBarPartCount AS LONG

 hStatusBar         = The status bar handle
 StatusBarPartCount = SendMessage(hStatusBar, SB_GETPARTS, 0, 0)
 StatusBarPartId    = StatusBarPartCount - 1 'Zero based
 hThread            = GetWindowThreadProcessId(hStatusBar, @pid)
 hProcess           = OpenProcess(PROCESS_VM_OPERATION OR PROCESS_VM_READ OR PROCESS_VM_WRITE OR _
                                  PROCESS_QUERY_INFORMATION, FALSE, pid)
 pStatusBarRect     = VirtualAllocEx(BYVAL hProcess, BYVAL 0, SIZEOF(StatusBarRect), _
                                     BYVAL MEM_COMMIT, BYVAL PAGE_READWRITE)
 SendMessage(hStatusBar, SB_GETRECT, StatusBarPartId, Cast(lParam, pStatusBarRect))
 ReadProcessMemory(hProcess, pStatusBarRect, BYVAL VARPTR(StatusBarRect), BYVAL SIZEOF(StatusBarRect), ByteCount)
 VirtualFreeEx(hProcess, @pStatusBarRect, 0, MEM_RELEASE)
 CloseHandle(hProcess)
 MessageBox(HWND_DESKTOP, _
            !"StatusBarPartCount \t"    & STR(StatusBarPartCount) & _
            !"\nStatusBarPartId  \t"    & STR(StatusBarPartId)    & _
            !"\nStatusBarRect.Left \t"  & STR(StatusBarRect.Left) & _
            !"\nStatusBarRect.Right \t" & STR(StatusBarRect.Right), _
            !"StatusBarRect", MB_OK OR MB_TOPMOST)

Logged

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #6 on: June 08, 2017, 05:05:47 PM »

Thanks very much, Pierre. I was looking at OpenProcess, but I was missing the VirtualAllocEx, ReadProcessMemory friends. I remember now to have read code that used them many years ago, but could not remember it. To fix knowledge about rarely used techniques is one of the reasons of what I write so many wrappers. Like this one, that I never have needed to use until now:

Code: [Select]
' ========================================================================================
' Retrieves the path of the executable file that created the specified window.
' ========================================================================================
PRIVATE FUNCTION AfxGetPathFromWindowHandle (BYVAL hwnd AS HWND) AS CWSTR
   DIM idProc AS DWORD, hProcess AS HANDLE, wszPath AS WSTRING * MAX_PATH
   GetWindowThreadProcessId(hwnd, @idProc)
   IF idProc THEN
      hProcess = OpenProcess(PROCESS_QUERY_INFORMATION OR PROCESS_VM_READ, FALSE, idProc)
      IF hProcess THEN
         GetModuleFileNameExW(hProcess, NULL, wszPath, SIZEOF(wszPath))
         CloseHandle(hProcess)
         RETURN wszPath
      END IF
   END IF
END FUNCTION
' ========================================================================================

I'm using it in FBWinSpy to detect if the application is 32 or 64 bit:

Code: [Select]
         ' // ------ Get the binary type ------------
         wszExePath = AfxGetPathFromWindowHandle(_hwnd)
         cwsText += wszExePath & CHR(13, 10)
         DIM nType AS DWORD
         GetBinaryTypeW(@wszExePath, @nType)
         DIM wszType AS WSTRING * 260
         IF nType = 0 THEN
            wszType = " (32 bit)"
         ELSEIF nType = 6 THEN
            wszType = " (64 bit)"
         END IF
         cwsText += "Binary type: " & WSTR(nType) & wszType & CHR(13, 10)

Coming back to the status bar, this function does the job:

Code: [Select]
' ========================================================================================
' Retrieves the bounding rectangle of a part in a status window.
' Parameters:
' - hStatusBar = Handle of the status bar control. It can belong to another application.
' - nPart = Zero-based index of the part whose bounding rectangle is to be retrieved.
' Return value: A RECT structure with the bounding rectangle.
' ========================================================================================
PRIVATE FUNCTION AfxGetStatusBarRect (BYVAL hStatusBar AS HWND, BYVAL nPart AS LONG) AS RECT
   DIM idProc AS DWORD, hProcess AS HANDLE, pSbRect AS ANY PTR, rc AS RECT, cbBytesRead AS SIZE_T
   GetWindowThreadProcessId(hStatusBar, @idProc)
   IF idProc = 0 THEN EXIT FUNCTION
   hProcess = OpenProcess(PROCESS_VM_OPERATION OR PROCESS_VM_READ OR PROCESS_VM_WRITE OR _
              PROCESS_QUERY_INFORMATION, FALSE, idProc)
   IF hProcess = NULL THEN EXIT FUNCTION
   pSbRect = VirtualAllocEx(hProcess, NULL, SIZEOF(RECT), MEM_COMMIT, PAGE_READWRITE)
   IF pSbRect THEN
      SendMessageW(hStatusBar, SB_GETRECT, nPart, cast(LPARAM, pSbRect))
      ReadProcessMemory(hProcess, pSbRect, @rc, SIZEOF(rc), @cbBytesRead)
      VirtualFreeEx(hProcess, pSbRect, 0, MEM_RELEASE)
   END IF
   CloseHandle(hProcess)
   FUNCTION = rc
END FUNCTION
' ========================================================================================

Being used as:

Code: [Select]
      CASE "MSCTLS_STATUSBAR32"
         cwsText += "   - Styles: " & GetStatusBarStyles(AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         cwsText += "   - Window styles: " & GetWindowStyles(hwnd, AfxGetWindowStyle(hwnd)) & CHR(13, 10)
         DIM rc AS RECT = AfxGetWindowRect(hwnd)
         cwsText += "   - Window Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         rc = AfxGetWindowClientRect(hwnd)
         cwsText += "   - Client Rect: Left = " & WSTR(rc.Left) & "; Right = " & WSTR(rc.Right) & "; Top = " & WSTR(rc.Top) & "; Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         DIM nParts AS LONG = StatusBar_GetPartsCount(hwnd)
         cwsText += "   - Parts: " & WSTR(nParts) & "; Text part 1: " & **AfxGetWindowText(hwnd) & CHR(13, 10)
         FOR i AS LONG = 0 to nParts - 1
            rc = AfxGetStatusBarRect(hwnd, i)
            cwsText += "   - Part " & WSTR(i) &": Left = " & WSTR(rc.Left) & ", Right = " & WSTR(rc.Right) & ", Top = " & WSTR(rc.Top) & ", Bottom = " & WSTR(rc.Bottom) & CHR(13, 10)
         NEXT
« Last Edit: June 08, 2017, 07:57:50 PM by José Roca »
Logged

Pierre Bellisle

  • FireFly3 User
  • Junior FireFly Member
  • *
  • Posts: 57
Re: FBWinSpy - Preliminary work
« Reply #7 on: June 08, 2017, 08:38:37 PM »

Looks like fbWinSpy is coming great.  :-)

I don't think it is usefull in the current scope, but if somebody ever need an extended GetBinaryType() that do more than exe,
then "Checking for 32/64 bit exe, dll, cpl, scr... files" might help,
or easier yet for non critial code,
the unDocumented Ole32.dll's CoGetModuleType(wFileName, dwModuleType) who also does check the FileHeader.

Pierre
Logged

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #8 on: June 08, 2017, 09:47:38 PM »

In fact, using the C aliases for data types, we don't even need to know if the application is 32 or 64 bit, because the goal is to generate code that compiles to 32 or 64 bit without changes.

For example, in the CWindows class, instead of assigning 4 or 8 bytes to the cbWndExtra member, I'm using SIZEOF(HANDLE). If it is 32 bit, SIZEOF(HANDLE) will return 4, and if it is 64 bit, it will return 8.

Code: [Select]
   ' // Fill the WNDCLASSEXW structure
   WITH wcexw
      .cbSize        = SIZEOF(wcexw)
      .style         = CS_DBLCLKS OR CS_HREDRAW OR CS_VREDRAW
      .lpfnWndProc   = lpfnWndProc
      .cbClsExtra    = 0
      .cbWndExtra    = SIZEOF(HANDLE)
      .hInstance     = hInstance
      .hCursor       = ..LoadCursorW(NULL, CAST(LPCWSTR, IDC_ARROW))
      .hbrBackground = CAST(HBRUSH, COLOR_3DFACE + 1)
      .lpszMenuName  = NULL
      .lpszClassName = @m_wszClassName
      .hIcon         = 0
      .hIconSm       = 0
   END WITH

I have noticed your use of BYVAL when passing some parameters in calls to Windows API functions. The FB headers always use BYVAL (there is not a single BYREF in any of the declares), so you won't ever need to use the BYVAL override when calling them (a different matter are my wrappers, in which I often use BYREF). What you will need a lot is to use VARPTR or @, and also CAST.

BTW here is the WINE code for GetBinary Type:
https://github.com/wine-mirror/wine/blob/master/dlls/kernel32/module.c

I often check the WINE source code to see what the Windows API functions do under the hood.

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #9 on: June 09, 2017, 01:43:32 AM »

Files reuploaded in the first post.

Added code to retrieve information about the toolbar buttons.

Added a check to ascertain if the form handle is the same that the main window before getting the menu information. The form handle could be a popup dialog or a tab page.

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #10 on: June 09, 2017, 01:44:55 PM »

I'm thinking that the best approach could be to use a TreeView to classify all the information retrieved, as I do in my TypeLib Browser. Then, this information can be parsed to generate code.

Pierre Bellisle

  • FireFly3 User
  • Junior FireFly Member
  • *
  • Posts: 57
Re: FBWinSpy - Preliminary work
« Reply #11 on: June 09, 2017, 02:01:50 PM »

Yep, about the ByVal you are right, code was a ported from PB
and I'm often lazy and sloppy so I posted without good cleaning.

I never did pay much attention to Wine, a second look made it more interesting, thank.

Now time to look at the new fbWinSpy, ...it will be much easier to port code.

Pierre
« Last Edit: June 15, 2017, 07:10:51 PM by Pierre Bellisle »
Logged

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #12 on: June 09, 2017, 03:14:27 PM »

> I never did pay much attention to Wine, a second look made it more interesting, thank.

I don't use Wine, but sometimes I look at the source code to know what and how the Windows API functions do.

Pierre Bellisle

  • FireFly3 User
  • Junior FireFly Member
  • *
  • Posts: 57
Re: FBWinSpy - Preliminary work
« Reply #13 on: June 09, 2017, 07:04:32 PM »

If you don't have already a function to retrieve controls handle that are inside a frame then, J. Brown wrote WindowFromPointEx.c.
Even if it's not really needed in the present case,  I find it useful in many occasions. It is working pretty well.
Here is a fb adaptation, and some pb code with a couple of frames and controls to show what I mean...
For the fun of it, I did replace WindowFromPoint(pt) with WindowFromPointEx(pt) in fbWinSpy.

Pierre

Code: [Select]
' ========================================================================================
' WindowFromPointEx procedure
' ========================================================================================
Function WindowFromPointEx(CursorPosDesktop AS POINT) AS HANDLE
 'Thank to J. Brown @ http://read.pudn.com/downloads14/sourcecode/windows/system/55084/winspy+SCR/scr/WindowFromPointEx.c__.htm

 'J. Brown says...
 'The problem:
 ' WindowFromPoint API is not very good. It cannot cope
 ' with odd window arrangements, i.e. a group-box in a dialog
 ' may contain a few check-boxes. These check-boxes are not
 ' children of the groupbox, but are at the same "level" in the
 ' window-hierachy. WindowFromPoint will just return the
 ' first available window it finds which encompasses the mouse
 ' (i.e. the group-box), but will NOT be able to detect the contents.

 'The solution:
 ' We use WindowFromPoint to start us off, and Then step back one
 ' level (i.e. from the parent of what WindowFromPoint returned).
 ' Once we have this window, we enumerate ALL children of this window
 ' ourselves, and find the one that best fits under the mouse -
 ' the smallest window that fits, in fact.
 ' I've tested this on alot of dIfferent apps, and it seems
 ' to work flawlessly - in fact, I havn't found a situation yet
 ' that this method doesn't work on.....we'll see!

 'J. Brown -

 Dim hFromPoint  AS HANDLE
 Dim hParent     AS HANDLE
 Dim hControlTry AS HANDLE
 Dim CtrlRect    AS RECT
 Dim Area        AS LONG
 Dim AreaPrev    AS LONG

 hFromPoint = WindowFromPoint(CursorPosDesktop)
 Function   = hFromPoint
 hParent    = GetParent(hFromPoint)
 If hParent Then
   hControlTry = GetWindow(hParent, GW_Child)      'Get first child
   Do While hControlTry                            'Enumerate all child including ourselve
     GetWindowRect(hControlTry, @CtrlRect)         'Get child's rect
     If PtInRect(@CtrlRect, CursorPosDesktop) Then 'Is mouse on control
       Area = (CtrlRect.Right - CtrlRect.Left) * (CtrlRect.Bottom - CtrlRect.Top) 'Calculate area
       If AreaPrev Then 'This is another control under same mouse position, like FRAME or BUTTON
         If Area < AreaPrev Then 'If it's smaller Then we want it
           If isWindowVisible(hControlTry) Then
             Function = hControlTry
           End If
         End If
       End If
       AreaPrev = Area 'Memorise for next loop, If any
     End If
     hControlTry = GetWindow(hControlTry, GW_HWNDNEXT)
   Loop
 End If

END Function
' ========================================================================================

Dialog with frames and other controls
Code: [Select]
#COMPILE EXE '#Win 9.07#
#DIM ALL
#INCLUDE "Win32Api.inc"
'#INCLUDE "Commctrl.inc"

%FrameA = 101
%FrameB = 102
%Static = 201
%Edit   = 202
%Button = 203
'_____________________________________________________________________________

CALLBACK FUNCTION MainProc()

 SELECT CASE CBMSG
   CASE %WM_COMMAND
     SELECT CASE CBCTL
       CASE %Button
         IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
           WinBeep(1500, 100)
         END IF
     END SELECT
 END SELECT

END FUNCTION
'_____________________________________________________________________________

FUNCTION PBMAIN()
 LOCAL RetVal AS LONG
 LOCAL hDlg   AS DWORD

 DIALOG NEW %HWND_DESKTOP, "FrameInFrame", , , 200, 200, _
 %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hDlg

 CONTROL ADD FRAME, hDlg, %FrameA, "Frame 101", 5, 5, 190, 190
 CONTROL ADD LABEL, hDlg, %Static, "Label 201", 25, 25, 150, 15, %SS_CENTER
 CONTROL ADD TEXTBOX, hDlg, %Edit, "TextBox 202", 35, 60, 130, 15
 CONTROL ADD FRAME, hDlg, %FrameB, "Frame 102", 25, 100, 150, 80
 CONTROL ADD BUTTON, hDlg, %Button, "Button 203", 70, 135, 60, 15

 DIALOG SHOW MODAL hDlg, CALL MainProc TO RetVal

END FUNCTION
'_____________________________________________________________________________
'

Logged

José Roca

  • Moderator
  • Master FireFly Member
  • *****
  • Posts: 2732
    • José Roca Software
Re: FBWinSpy - Preliminary work
« Reply #14 on: June 10, 2017, 05:19:42 AM »

Thanks very much, Pierre, it has been providential. I was pulling my hair because in my CSED editor I have popup windows with group boxes in which the controls are not children of the group box, but of the popup window, and it was not returning the selected control.

I have made a GUI. You can select the main window, a popup window with controls or an individual contros (with or without child controls) and it displays the retrieved information in a Treeview. Next step will be to retrieve and display information about the child controls.

New files reuploaded in the first post.
« Last Edit: June 10, 2017, 08:47:14 AM by José Roca »
Logged
Pages: [1] 2