Hi, Ronnie -
Benjamin's excellent suggestion does indeed work, and you don't need to create a custom DLL in order to accomplish this from PB.
Here's the external function declaration I used:
FUNCTION Longptr SendMessageTabItemRect ( &
Longptr hWnd, &
UnsignedLong Msg, &
LongPtr wParam, &
REF s_winapi_rect lParam &
) LIBRARY "user32.dll" ALIAS FOR "SendMessageW"
The "trick" is to pass the WinAPI rectangle structure by reference as the LPARAM argument to the SendMessageW API function, so that the address of the structure gets passed and Windows can fill in the structure member values.
Here's code I used to call this external function:
ULong lul_tabctrl_getitemrect = 4864 + 10 // = TCM_FIRST + 10
Longptr llptr_rc, llptr_htab
s_winapi_rect lstr_recttab1, lstr_recttab2
llptr_htab = Handle(tab_1)
llptr_rc = SendMessageTabItemRect(llptr_htab,lul_tabctrl_getitemrect,0,lstr_recttab1)
MessageBox('Tab Control GetItemRect for Tabpage 1', &
'Left = ~t'+String(lstr_recttab1.l_left) + &
'~r~nTop = ~t'+String(lstr_recttab1.l_top) + &
'~r~nRight = ~t'+String(lstr_recttab1.l_right) + &
'~r~nBottom = ~t'+String(lstr_recttab1.l_bottom) + &
'~r~n~r~nRC = ' + String(llptr_rc))
llptr_rc = SendMessageTabItemRect(llptr_htab,lul_tabctrl_getitemrect,1,lstr_recttab2)
MessageBox('Tab Control GetItemRect for Tabpage 2', &
'Left = ~t'+String(lstr_recttab2.l_left) + &
'~r~nTop = ~t'+String(lstr_recttab2.l_top) + &
'~r~nRight = ~t'+String(lstr_recttab2.l_right) + &
'~r~nBottom = ~t'+String(lstr_recttab2.l_bottom) + &
'~r~n~r~nRC = ' + String(llptr_rc))
Note the tab # argument is zero-based (the first tab is tab #0). The SendMessageW message # for the TabCtrl_GetItemRect is defined as TCM_FIRST (TCM = Tab Control Message)+ 10, or 4864 + 10 = 4874.
The rectangle structure member values are in pixels, of course. relative to the upper-left corner of the tab control.
The APi appears to work with non-standard tab positioning, not just when tabs are on the top. Be aware that if the tab area is "scrollable", you may need to recognize how this affects the values returned in the rectangle.
By obtaining the position of every tab and checking the tab position and multi-line properties, you can now dynamically determine the number of tab rows at execution time... an added benefit.
HTH, John
Thanks for posting your solution, which works perfectly!
I rarely (i.e. never) do much Win API coding, so I was looking at functions such as SystemParametersInfo() and would never have thought to look at SendMessage(). Very nice!
To get the number of tab rows directly, you could probably utilize the TCM_GETROWCOUNT message the same way.
(BOOL)SNDMSG((hwnd), TCM_GETITEMRECT, (WPARAM)(int)(i), (LPARAM)(RECT *)(prc))
- where "SNDMSG" translates to "SendMessage", then recognizing that the LPARAM argument to SendMessage was a pointer to a RECT structure. This was an interesting challenge, made possible only by your terrific tip to look at the TabCtrl_GetitemRect macro, Benjamin, so thank you for that!