View Full Version : Rough Notes, and posts to be referenced from elsewhere, on VBA Windows API
DocAElstein
09-16-2015, 03:25 PM
Rough Notes on VBA Windows API Introduction Part 1
If, for now we restrict ourselves, to the subject area of Excel VBA Windows API, we can consider us to be talking most often about another, and/or similar to other ways, ( such as the so called External shared libraries (https://www.excelfox.com/forum/showthread.php/2240-VBA-referring-to-external-shared-Libraries-1)-Early-1-5)-Laterly-Early-and-2)-Late-Binding-Techniques)), to control or communicate with things outside of Excel, or even sometimes in Excel.
More broadly speaking we are controlling or communicating with windows. (An existing window is often seen as based on a Class, and we are messing with the window/ manipulating the window, so what we are doing may sometimes be regarded as Sub Classing)
Manipulating "Windows”.
It would appear initially that the word “Windows” is a name for a programming idea which might result in something we “see” as what we conceive as Windows. But, a window is a vague concept. It includes what we see as windows and other things.
Manipulating of the actual “Windows” seems the key to pseudo “making my own” Class or of a API Function or a Window thing from it
Doing this in any language is a task for a computer genius, and in Visual Basic, (In particular Visual Basic for Applications), the documentation is very sparse. But “ API User 32 dll Programs” would appear to make this possible.
It would appear that direct linked libraries (dll) are available to run as and when required, hence the wording of direct link: They are used as an efficient means to organise Microsoft’s software generally allowing different Applications to share smaller programs which are shipped as standard with the Microsoft Windows Operating system. They are however also available to programmers, programming the applications. Hence Application Programming Interface
There are some similarities between a .dll file and a .exe file. The main difference is that we usually need to organise how and when it is used in Windows, hence I say Manipulating "Windows"
API , “API Calls”
Such things get bundled up in an imprecise intimidating term API, for Application Programming Interface. They are usually contained in a Folder with a name similar to User 32.
Another seemingly intimidating phrase is “API call”. You may hear the term “I am using API calls”. It just means usually that you are using those things and related “Windows” concept
I have been told by some professionals that in actual fact these Library programs are organised in a similar way to the Libraries that one can pseudo Import by “checking a reference” in the list of available to VBA code libraries. However by some subtlety that they are not sure about they cannot be used in a code in the way of through declaring ( Dim ing ) them and then after assigning a variable using that variable to “get at” the various Methods / Functions inside them. Perhaps they are slightly more run time things, even though I have heard that the other Libraries are as well. Perhaps it can depend on the exact thing.
When we are involved with VBA, it is difficult sometimes perhaps to distinguish between an end user and a professional programmer. The so called External shared libraries (https://www.excelfox.com/forum/showthread.php/2240-VBA-referring-to-external-shared-Libraries-1)-Early-1-5)-Laterly-Early-and-2)-Late-Binding-Techniques) may be regarded as for the end user, whereas the API things could be regarded as intended for a programmer.
In place of the normal declaring ( Dim ing ) that would be within a routine, in the case of the Library programs being used here, you must do a sort of initial globial type Declaration.
Declareing Declare Type Functions
You don’t always need the AliAs bit in these things. ( It just means _ this Lib "user32" _ Ali As ¬_ “that” _ (that is the Microsoft name , this is any name that I choose to use) ). Occasionally something can only be done to the AliAs where numbers and variable used to refer to things are concerned. It is subtle general point in computing that you might get problems when a number is used to refer to something that might take or give a number at some point. But you might need to do that, so having an intermediate word is a workaround for that so that the number is set to a word which is then related to a word that might be being referred to or returning a number.
Function = Word
Word = 873248
So the Function can be referred to by a number indirectly, --- occasionally this may not be possible directly, --- Function =837547 might error for subtle computer reasons.
It seems to do no harm to use an AliAs when you don’t need it and it helps to make a code prettier.
Once Declared you can think of them to a first approximation as a function written in a code module in the Folder on your computer with the name something like “User32” or “User32dll” or similar. You then use them to a very crude approximation as you would any conventional function that you may have made and which is typically in a VBA code module, like pseudo
_ x = SetWindowsHookExample( 3 , y , _..__…… etc )
x would need to be a variable declared at the top of the module I think, as would possibly be some of the signature line arguments in the Function, but note those arguments could also be a pseudo function, - pseudo as the address/ location of the function is given. (That function may, for example, be set off by something going on in a window at some point). The possibilities and construction of the signature line in a API Declare Function line are not as simply defined as in a standard VBA Function
For use in a normal code you can use Private or Pubic. As in convectional VBA Functions Pubic will not confine the use of the function to the macro module in which it is in.
For a class code module, such as a worksheet code module ( To get there, right click the worksheet's tab and select View Code ), these Declare type functions must be Private
Owned “Windows”, and/ or z order.
It is well above my knowledge to explain all concepts here, and as noted some things will have to be read as “on the tin” or in other words its faecile value.
A Pop up is apparently always the one on top of to be seen ( “above on the screen “z axis” “ , - as a approximation the z axis is in the direction looking at it ) of the Window to which they belong and they always “belong”” to a parent window… well maybe something is not quite clear there…
It is not always clear what “z option” does what, and even professionals sometimes seem to choose it from trial and error .
But anyway these are two things that will need to be taken into the equation… or rather the “API calls” that we do..
Hooking a “Window” to Handle it ..Computer Bollox terminology.
I have needed to get some terms undefined correctly. Words like Handle and Hook are computer terms similar to the word Bollox in normal language and can be used alone or in conjunction with other words to have some meaning possibly in the context in which they are used but cannot have any precise meaning. Defining them as some computer bollox to do with handling and identifying Windows is a useful way to understand these terms.
Some handle bollox will need to be taken into the equation… or rather the “API calls” that I do..
Some published literature even supports my somewhat naive and critical resume, saying the words can mean a number of things. In our case the handle can be thought a number identifying a Window. A Hook can be thought of as hook or trip trap placed in some run or chain of events cause shuddering or jerking off of a procedure.
Handleing
When doing VBA Windows API coding, a "handle" seems to play a major role. It is an identification number / address/ pointer , or similar, which is required in much coding, as one might reasonably expect, in order that a coding knows which window or windows that we want to manipulate. One problem/s is that, although a window may have some known fixed name, this number is more often what is required in coding, and those numbers are not fixed, but rather are somehow generated and given each time to a software when it us running so that that software can access the windows, without us knowing any specific memory location/ address of things. Possibly that is done to make it more difficult to hack things . We are not privy to exactly how the numbers are generated, so we can consider them as random. ( Not all possible numbers are used, so it is possible that the same number is re used, but it is random chance if it is).
To make things worse,
_ getting the number seems to be not always reliable, and not all things that should do work.
_ to get at most windows would require some sort of navigating of an explorer tree like structure.
There are several API functions, that is to say Declareation Functions available to get the handle, and one or more may need to be used for a particular coding situation.
So getting the handle/ using handle related Declareation Functions can be a good start point when learning VBA Windows
DocAElstein
02-07-2018, 03:49 PM
Dumping Logs for support of this Thread Post:
http://www.excelfox.com/forum/showthread.php/2227-VBA-Input-Pop-up-Boxes-Application-InputBox-Method-versus-VBA-InputBox-Function?p=10476#post10476
Test Function used to produce the Log below
'Going a HoldYaBackCalledYaBackClapTrapRuc - Copy number_GlobinalCntChopsLog - a few copies of this are made and run. (Recursion)
'_-=Rem 4===================??? Got me hook lochprocedue in my code , 5 times simple run then another + 29 new copies of it are run = 5+30=35 times in total calling it it a few times http://www.excelfox.com/forum/showthread.php/1324-Loop-Through-Files-In-A-Folder-Using-VBA#post10421 .... wanking myself up and down a few times
Private Function HoldYaBackCalledYaBackClapTrapRuc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long ' ByVal CopyNumberFroNxtLvl As Long) As Long
Let GlobinalCntChopsLog = GlobinalCntChopsLog + 1: Debug.Print " Going a HoldYaBackCalledYaBackClapTrapRuc"; GlobinalCntChopsLog; "(1Msg"; lMsg; ", wParam"; wParam; ", lParam"; lParam; ") Function Copy Number_"; GlobinalCntChopsLog
'If GlobinalCntChopsLog = 2 Then Let GlobinalCntChopsLog = GlobinalCntChopsLog - 1: UnHookWindowsHookCodEx hHookTrapCrapNumber: Exit Function
If lMsg = 5 Then '_-.... ( Hook type: HCBT_ACTIVATE = 5 but not here?) ... this runs a further 29 copies of HoldYaBackCalledYaBackClapTrap all coming here, so 30 times in total
Debug.Print "Expose Interface"; Tab(30); GlobinalCntChopsLog
SetWindowPosition wParam, 0, poX, pussY, 400, 150, 40 ' SWP_NOZORDER is 4 .. but not here?? 'SWP_NOSIZE + SWP_NOZORDER ' Pull the Chainge position ...
UnHookWindowsHookCodEx hHookTrapCrapNumber ' Release the Hook 30 times this is done
Else
Debug.Print "No InterOfCourse"; Tab(30); GlobinalCntChopsLog; Tab(50); hHookTrapCrapNumber
End If ' 5 times here then '_-....
Debug.Print "Wipe chain WRap"; Tab(30); GlobinalCntChopsLog; Tab(50); hHookTrapCrapNumber
Let HoldYaBackCalledYaBackClapTrapRuc = 0 ' Done 5+30=35 times in total '0 (or False) makes it work, all other numbers and I get no Message box
Let GlobinalCntChopsLog = GlobinalCntChopsLog - 1
End Function ' HoldYaBackCalledYaBackClapTrapRuc
---------------------------
MutsNuts AkaApi working ApplicationPromptToRangeInputBox
---------------------------
Select Range
---------------------------
OK
---------------------------
WndNumber 66770 HandleWndOfMyParent 983700 hWndDskTop 66204 hHookTrapCrapNumber
State of Much Such Penialtration's Number HookCodeXcretion's
================== AliAs Pull of my chain AliAs my long Hook
0
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 3 , wParam 2623104 , lParam 2353392 ) Function Copy Number_ 1
No InterOfCourse 1 276039693
Wipe chain WRap 1 276039693
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 3 , wParam 1377832 , lParam 2353500 ) Function Copy Number_ 1
No InterOfCourse 1 276039693
Wipe chain WRap 1 276039693
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 3 , wParam 3934358 , lParam 2353500 ) Function Copy Number_ 1
No InterOfCourse 1 276039693
Wipe chain WRap 1 276039693
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 3 , wParam 984706 , lParam 2353480 ) Function Copy Number_ 1
No InterOfCourse 1 276039693
Wipe chain WRap 1 276039693
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 9 , wParam 3934358 , lParam 66766 ) Function Copy Number_ 1
No InterOfCourse 1 276039693
Wipe chain WRap 1 276039693
Going a HoldYaBackCalledYaBackClapTrapRuc 1 (1Msg 5 , wParam 2623104 , lParam 2353812 ) Function Copy Number_ 1
Expose Interface 1
Going a HoldYaBackCalledYaBackClapTrapRuc 2 (1Msg 5 , wParam 2623104 , lParam 2353500 ) Function Copy Number_ 2
Expose Interface 2
Going a HoldYaBackCalledYaBackClapTrapRuc 3 (1Msg 5 , wParam 2623104 , lParam 2353188 ) Function Copy Number_ 3
Expose Interface 3
Going a HoldYaBackCalledYaBackClapTrapRuc 4 (1Msg 5 , wParam 2623104 , lParam 2352876 ) Function Copy Number_ 4
Expose Interface 4
Going a HoldYaBackCalledYaBackClapTrapRuc 5 (1Msg 5 , wParam 2623104 , lParam 2352564 ) Function Copy Number_ 5
Expose Interface 5
Going a HoldYaBackCalledYaBackClapTrapRuc 6 (1Msg 5 , wParam 2623104 , lParam 2352252 ) Function Copy Number_ 6
Expose Interface 6
Going a HoldYaBackCalledYaBackClapTrapRuc 7 (1Msg 5 , wParam 2623104 , lParam 2351940 ) Function Copy Number_ 7
Expose Interface 7
Going a HoldYaBackCalledYaBackClapTrapRuc 8 (1Msg 5 , wParam 2623104 , lParam 2351628 ) Function Copy Number_ 8
Expose Interface 8
Going a HoldYaBackCalledYaBackClapTrapRuc 9 (1Msg 5 , wParam 2623104 , lParam 2351316 ) Function Copy Number_ 9
Expose Interface 9
Going a HoldYaBackCalledYaBackClapTrapRuc 10 (1Msg 5 , wParam 2623104 , lParam 2351004 ) Function Copy Number_ 10
Expose Interface 10
Going a HoldYaBackCalledYaBackClapTrapRuc 11 (1Msg 5 , wParam 2623104 , lParam 2350692 ) Function Copy Number_ 11
Expose Interface 11
Going a HoldYaBackCalledYaBackClapTrapRuc 12 (1Msg 5 , wParam 2623104 , lParam 2350380 ) Function Copy Number_ 12
Expose Interface 12
Going a HoldYaBackCalledYaBackClapTrapRuc 13 (1Msg 5 , wParam 2623104 , lParam 2350068 ) Function Copy Number_ 13
Expose Interface 13
Going a HoldYaBackCalledYaBackClapTrapRuc 14 (1Msg 5 , wParam 2623104 , lParam 2349756 ) Function Copy Number_ 14
Expose Interface 14
Going a HoldYaBackCalledYaBackClapTrapRuc 15 (1Msg 5 , wParam 2623104 , lParam 2349444 ) Function Copy Number_ 15
Expose Interface 15
Going a HoldYaBackCalledYaBackClapTrapRuc 16 (1Msg 5 , wParam 2623104 , lParam 2349132 ) Function Copy Number_ 16
Expose Interface 16
Going a HoldYaBackCalledYaBackClapTrapRuc 17 (1Msg 5 , wParam 2623104 , lParam 2348820 ) Function Copy Number_ 17
Expose Interface 17
Going a HoldYaBackCalledYaBackClapTrapRuc 18 (1Msg 5 , wParam 2623104 , lParam 2348508 ) Function Copy Number_ 18
Expose Interface 18
Going a HoldYaBackCalledYaBackClapTrapRuc 19 (1Msg 5 , wParam 2623104 , lParam 2348196 ) Function Copy Number_ 19
Expose Interface 19
Going a HoldYaBackCalledYaBackClapTrapRuc 20 (1Msg 5 , wParam 2623104 , lParam 2347884 ) Function Copy Number_ 20
Expose Interface 20
Going a HoldYaBackCalledYaBackClapTrapRuc 21 (1Msg 5 , wParam 2623104 , lParam 2347572 ) Function Copy Number_ 21
Expose Interface 21
Going a HoldYaBackCalledYaBackClapTrapRuc 22 (1Msg 5 , wParam 2623104 , lParam 2347260 ) Function Copy Number_ 22
Expose Interface 22
Going a HoldYaBackCalledYaBackClapTrapRuc 23 (1Msg 5 , wParam 2623104 , lParam 2346948 ) Function Copy Number_ 23
Expose Interface 23
Going a HoldYaBackCalledYaBackClapTrapRuc 24 (1Msg 5 , wParam 2623104 , lParam 2346636 ) Function Copy Number_ 24
Expose Interface 24
Going a HoldYaBackCalledYaBackClapTrapRuc 25 (1Msg 5 , wParam 2623104 , lParam 2346324 ) Function Copy Number_ 25
Expose Interface 25
Going a HoldYaBackCalledYaBackClapTrapRuc 26 (1Msg 5 , wParam 2623104 , lParam 2346012 ) Function Copy Number_ 26
Expose Interface 26
Going a HoldYaBackCalledYaBackClapTrapRuc 27 (1Msg 5 , wParam 2623104 , lParam 2345700 ) Function Copy Number_ 27
Expose Interface 27
Going a HoldYaBackCalledYaBackClapTrapRuc 28 (1Msg 5 , wParam 2623104 , lParam 2345388 ) Function Copy Number_ 28
Expose Interface 28
Going a HoldYaBackCalledYaBackClapTrapRuc 29 (1Msg 5 , wParam 2623104 , lParam 2345076 ) Function Copy Number_ 29
Expose Interface 29
Going a HoldYaBackCalledYaBackClapTrapRuc 30 (1Msg 5 , wParam 2623104 , lParam 2344764 ) Function Copy Number_ 30
Expose Interface 30
Wipe chain WRap 30 276039693
Wipe chain WRap 29 276039693
Wipe chain WRap 28 276039693
Wipe chain WRap 27 276039693
Wipe chain WRap 26 276039693
Wipe chain WRap 25 276039693
Wipe chain WRap 24 276039693
Wipe chain WRap 23 276039693
Wipe chain WRap 22 276039693
Wipe chain WRap 21 276039693
Wipe chain WRap 20 276039693
Wipe chain WRap 19 276039693
Wipe chain WRap 18 276039693
Wipe chain WRap 17 276039693
Wipe chain WRap 16 276039693
Wipe chain WRap 15 276039693
Wipe chain WRap 14 276039693
Wipe chain WRap 13 276039693
Wipe chain WRap 12 276039693
Wipe chain WRap 11 276039693
Wipe chain WRap 10 276039693
Wipe chain WRap 9 276039693
Wipe chain WRap 8 276039693
Wipe chain WRap 7 276039693
Wipe chain WRap 6 276039693
Wipe chain WRap 5 276039693
Wipe chain WRap 4 276039693
Wipe chain WRap 3 276039693
Wipe chain WRap 2 276039693
Wipe chain WRap 1 276039693
_-.__________________________________
Windows Handleing Info:
' 1b) To hang in the Excel Window malking it effectively a Excel Msgbox... Normally if I did not do this ... don't do this .. that is to say leave it at 0 , specifically no window is 0 , and it "hanging in mid air so isn't even if it is imaginatively speaking
Public Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Dim HandleWndOfMyParent As Long ' I wanted to comment this 1b)(i) and ( 1b(ii) later ) out to leave it hanging in mid air in a virtual inadvirtual not thereness ... but somehow this complicated hook stuff does hang it somwhere but not in my Excel Window but I don't know what my parent's fart has to do with anything
' 1d) For some Misc experiments
Private Declare Function FindWindowExtremeNutty Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Dim WndNumber As Long, hWndDskTop As Long
Sub AkaApiApplicationPromptToRangeInputBox() ' This one works.. but HTF
' 1b(ii) This section is some how over written in / by the section part or some strange Addressing of HoldYaBackCalledYaBackClapTrap
Let WndNumber = FindWndNumber(lpClassName:=vbNullString, lpWindowName:=vbNullString)
Let HandleWndOfMyParent = FindWndNumber(lpClassName:="XLMAIN", lpWindowName:=vbNullString) ' This is a case where vbNullstring is important - that signifies that I am not giving it, which i do not have to. The second option is a bit flaky and does not often work. it certainly won't work if you make it "" as that is a specific string of zero. Null is a special idea in computing of not set yet / not defined - that is required if I do not want to give it
' 1d) Just some experiments, I forgot why as my brain has goine comfortably numb
Dim HeavyWindBreak As Long: Let HeavyWindBreak = HandleWndOfMyParent
Let hWndDskTop = FindWindowExtremeNutty(HandleWndOfMyParent, 0&, "XLDESK", vbNullString)
Debug.Print "WndNumber"; WndNumber; " HandleWndOfMyParent"; HandleWndOfMyParent; " hWndDskTop"; hWndDskTop; " hHookTrapCrapNumber"
Rem 3 Mess with me hook? God knows what this all does and it seems to make no difference if the proXYs poX or pussY are before or after SetWindowsHooksExample
DocAElstein
02-08-2018, 12:53 AM
Per PM request: One full working example of above code:
Option Explicit
Rem 1 ' This I understand. it is a simple more basic version of the VBA Message Box Function http://www.eileenslounge.com/viewtopic.php?f=18&t=28885#p223629
' 1a) UnWRap it and..
Private Declare Function APIssinUserDLL_MsgBox Lib "user32" Alias "MessageBoxA" (Optional ByVal HowManyFartsCanYouHandle As Long, Optional ByVal Prompt As String, Optional ByVal Title As String, Optional ByVal buttons As Long) As Long '
' 1b) To hang in the Excel Window malking it effectively a Excel Msgbox... Normally if I did not do this ... don't do this .. that is to say leave it at 0 , specifically no window is 0 , and it "hanging in mid air so isn't even if it is imaginatively speaking
Public Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Dim HandleWndOfMyParent As Long ' I wanted to comment this 1b)(i) and ( 1b(ii) later ) out to leave it hanging in mid air in a virtual inadvirtual not thereness ... but somehow this complicated hook stuff does hang it somwhere but not in my Excel Window but I don't know what my parent's fart has to do with anything
' 1d) For some Misc experiments
Private Declare Function FindWindowExtremeNutty Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Dim WndNumber As Long, hWndDskTop As Long
Dim Booloks As Boolean
'_-_._______________________________________________-
'_-=================??? main Declarations that I don't really understand
Rem 2 Position my box --- From here on I do not really have a clue
' 2(a) This will tie something on the chain for when you pull it https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
Private Declare Function SetWindowsHooksExample Lib "user32" Alias "SetWindowsHookExA" (ByVal Hooktype As Long, ByVal lokprocedureAddress As Long, Optional ByVal hmod As Long, Optional ByVal dwThreadId As Long) As Long
' 2(b) Wipe the chain clean
Private Declare Function UnHookWindowsHookCodEx Lib "user32" Alias "UnhookWindowsHookEx" (ByVal hHookTrapCrapNumber As Long) As Long
' 2(c) Don't loose the Thread? - This seems to have no effect , - maybe it would if something else was going on at the time. You don't want to loose the Thread I guess
'Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long ' Effectively long Null acttuall not ?? -
Public Declare Function GetCurrentFredId Lib "kernel32" Alias "GetCurrentThreadId" () As Long ' Effectively long Null acttuall not ?? -
' 2(d) This looks understandable almost, z(0 for top), posLeft, posTop, x pixels, y pixels,
Private Declare Function SetWindowPosition Lib "user32" Alias "SetWindowPos" (ByVal hWnd As Long, ByVal zNumber As Long, ByVal CoedX As Long, ByVal CoedY As Long, ByVal xPiXel As Long, ByVal yPiYel As Long, ByVal wFlags As Long) As Long
' 2e)
Private hHookTrapCrapNumber As Long ' Handle to the Hook procedure
' 2f)
Private poX As Long: Private pussY As Long ' Positional By proXYs
Dim GlobinalCntChopsLog As Long ' Only used in this test code to keep track of the copies of a Function(HoldYaBackCalledYaBackClapTrap) used in a recursion process
' 2g) bits to do with 1 that i am resonably happy with
Sub AkaApiApplicationPromptToRangeInputBox() ' This one works.. but HTF
' 1b(ii) This section is some how over written in / by the section part or some strange Addressing of HoldYaBackCalledYaBackClapTrap
Let WndNumber = FindWndNumber(lpClassName:=vbNullString, lpWindowName:=vbNullString)
Let HandleWndOfMyParent = FindWndNumber(lpClassName:="XLMAIN", lpWindowName:=vbNullString) ' This is a case where vbNullstring is important - that signifies that I am not giving it, which i do not have to. The second option is a bit flaky and does not often work. it certainly won't work if you make it "" as that is a specific string of zero. Null is a special idea in computing of not set yet / not defined - that is required if I do not want to give it
' 1d) Just some experiments, I forgot why as my brain has goine comfortably numb
Dim HeavyWindBreak As Long: Let HeavyWindBreak = HandleWndOfMyParent
Let hWndDskTop = FindWindowExtremeNutty(HandleWndOfMyParent, 0&, "XLDESK", vbNullString)
Debug.Print "WndNumber"; WndNumber; " HandleWndOfMyParent"; HandleWndOfMyParent; " hWndDskTop"; hWndDskTop; " hHookTrapCrapNumber"
Rem 3 Mess with me hook? God knows what this all does and it seems to make no difference if the proXYs poX or pussY are before or after SetWindowsHooksExample
Debug.Print "State of Much Such"; Tab(20); "Penialtration's Number"; Tab(45); "HookCodeXcretion's"
Debug.Print "=================="; Tab(20); "AliAs Pull of my chain"; Tab(45); "AliAs my long Hook"
Let GlobinalCntChopsLog = 0:
'_-======================== Weird thing with an AddressOf ???
Let poX = 10: pussY = 50 ' These can go before or after the next line, makes no diffference.. - I bet no Pro noticed that...
'Let hHookTrapCrapNumber = SetWindowsHooksExample(5, AddressOf HoldYaBackCalledYaBackClapTrap, 0, GetCurrentThreadId) ' (5-pull before flush, somehow arranges that the function gets called ,
Debug.Print ; Tab(75); hHookTrapCrapNumber ' 'APIssinUserDLL_MsgBox HeavyWindBreak, "Excel MsgBox", "This is Center Position", vbOKOnly ' This breaks Wnd in Excel Window
Call HookAPIssinUserDLL_MsgBoxThenDropIt
'APIssinUserDLL_MsgBox &H0, "Select Range", "MutsNuts AkaApi working ApplicationPromptToRangeInputBox", vbOKOnly ' Pseudo Non Modal
'APIssinUserDLL_MsgBox &H0, "Select Range", "MutsNuts AkaApi working ApplicationPromptToRangeInputBox", vbOKOnly ' Pseudo Non Modal
'HookAPIssinUserDLL_MsgBoxThenDropIt
Dim Rng As Range: Set Rng = Selection
' (Optional ByVal hwnd As Long, Optional ByVal Prompt As String, Optional ByVal Title As String, Optional ByVal buttons As Long) As Long '
End Sub ' AkaApiApplicationPromptToRangeInputBox
Sub HookAPIssinUserDLL_MsgBoxThenDropIt()
Sub HookAPIssinUserDLL_MsgBoxThenDropIt()
' a) HOOK Hook the pseudo Windows Sub Class Function WinSubWinCls_JerkBackOffHooKerd
Dim BookMarkClassTeachMeWind As Long: Let BookMarkClassTeachMeWind = 5
'Let hHookTrapCrapNumber = SetWindowsHooksExample(BookMarkClassTeachMeWind, AddressOf HoldYaBackCalledYaBackClapTraped, 0, GetCurrentThreadId) ' (5-pull before flush, somehow arranges that the function gets called ,
'Let hHookTrapCrapNumber = SetWindowsHooksExample(BookMarkClassTeachMeWind, AddressOf HoldYaBackCalledYaBackClapTrapRuc, 0, GetCurrentThreadId) ' (5-pull before flush, somehow arranges that the function gets called ,
Let hHookTrapCrapNumber = SetWindowsHooksExample(BookMarkClassTeachMeWind, AddressOf HoldYaBackCalledYaBackClapTrapRuc, 0, GetCurrentFredId) ' (5-pull before flush, somehow arranges that the function gets called ,
' b) Call the MessageBoxA
APIssinUserDLL_MsgBox &H0, "Select Range", "MutsNuts AkaApi working ApplicationPromptToRangeInputBox", vbOKOnly ' Pseudo Non Modal
End Sub
'_-=Rem 4===================??? Got me hook lochprocedue in my code , 5 times simple run then another + 29 new copies of it are run = 6+29=35 times in total calling it it a few times http://www.excelfox.com/forum/showthread.php/1324-Loop-Through-Files-In-A-Folder-Using-VBA#post10421 .... wanking myself up and down a few times
'_-=Rem 4===================??? Got me hook lochprocedue in my code , 5 times simple run then another + 29 new copies of it are run = 5+30=35 times in total calling it it a few times http://www.excelfox.com/forum/showthread.php/1324-Loop-Through-Files-In-A-Folder-Using-VBA#post10421 .... wanking myself up and down a few times
Private Function HoldYaBackCalledYaBackClapTrapRuc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long ' ByVal CopyNumberFroNxtLvl As Long) As Long
Let GlobinalCntChopsLog = GlobinalCntChopsLog + 1: Debug.Print " Going a HoldYaBackCalledYaBackClapTrapRuc"; GlobinalCntChopsLog; "(1Msg"; lMsg; ", wParam"; wParam; ", lParam"; lParam; ") Function Copy Number_"; GlobinalCntChopsLog
'If GlobinalCntChopsLog = 2 Then Let GlobinalCntChopsLog = GlobinalCntChopsLog - 1: UnHookWindowsHookCodEx hHookTrapCrapNumber: Exit Function
If lMsg = 5 Then '_-.... ( Hook type: HCBT_ACTIVATE = 5 but not here?) ... this runs a further 29 copies of HoldYaBackCalledYaBackClapTrap all coming here, so 30 times in total
Debug.Print "Expose Interface"; Tab(30); GlobinalCntChopsLog
Call SetWindowPosition(wParam, 0, poX, pussY, 400, 150, 40) ' SWP_NOZORDER is 4 .. but not here?? 'SWP_NOSIZE + SWP_NOZORDER ' Pull the Chainge position ...
UnHookWindowsHookCodEx hHookTrapCrapNumber ' Release the Hook 30 times this is done
Else
Debug.Print "No InterOfCourse"; Tab(30); GlobinalCntChopsLog; Tab(50); hHookTrapCrapNumber
End If ' 5 times here then '_-....
Debug.Print "Wipe chain WRap"; Tab(30); GlobinalCntChopsLog; Tab(50); hHookTrapCrapNumber
Let HoldYaBackCalledYaBackClapTrapRuc = 0 ' Done 5+30=35 times in total '0 (or False) makes it work, all other numbers and I get no Message box
Let GlobinalCntChopsLog = GlobinalCntChopsLog - 1
End Function ' HoldYaBackCalledYaBackClapTrapRuc
DocAElstein
02-17-2018, 05:06 PM
lcnascn
DocAElstein
02-17-2018, 05:06 PM
Rough Notes on VBA Windows API Introduction Part 2 Handles, hwnd number
Arguably one of the most important things in VBA Windows API to get familiar with is this number, the number that gets given to a window when it opens**, or probably better said, most windows associated with a software get given their own one of these unique identifying numbers, - note: - they get a new one every time the software starts
The subject we are considering here is controlling windows, and in order to do this, the API functions we are using will almost certainly need this number, and sometimes a few of them. Typically, the Long type variable used is given the name hwnd - It is very common to see this variable name, but only because it is often used, - it is not some reserved word, or it might be somewhere other than VBA. (So in writings, even mine, it may be referring specifically to a variable, or just a handle(s) in general ,so it might get carelessly written like hwnd or hwnd, although generally I try to keep the hwnd format for coding
Perhaps 3 important points should be made clear right from the start
1_ Whilst this number can, for any window, be used in our coding, ( or anything else communicating with windows ), to refer to / get / communicate etc. with that window directly, the particular number used is not fixed forever for that window. **It is given when the window comes into existence, and if the software creating it is then closed and re-opened, a new number will be given. It can be thought of as a semi random number given when the window is created, ( semi because the process giving the number follows certain rules ), and that particular number will only be valid for the duration of the software running. So generally, we cannot get that number somehow and then have a fixed number in our coding to always use. Instead we must either
__ use a third party software to get the number, and then each time we run our VBA coding we must enter that in
, or
__ the coding itself will need to get/find that number by some means, ( for example using a API function that uses some other property of the window to return the hwnd, or using some combination of API functions to loop through some windows and use some criteria to select the one we want)
2_ Similarly again, whilst this number can, for any window, be used in our coding, ( or anything else communicating with windows ), to refer to / get / communicate etc. with that window directly, point 2_ is that windows are generally organised in a explorer/ hierarchical way, and for some low level windows software innards reasons, if we want to get the handle with our VBA coding, we may need to "walk the tree" or go in steps to get it. This means that we often see a hwnd argument in a API function that we might use to get the handle, and the handle in that variable will likely be that of a window somewhere "near" the one which is being found by that API function. So if we were wanting the handle of a window that is a few "levels down" in the hierarchy, we would likely have a few API function lines, and the handle got from one line would be fed to the next, pseudo like
hwnd2 = Function(hwnd1, arga, argb)
hwnd3 = Function(hwnd2, argx, argy)
hwnd4 = Function(hwnd3, argz, argy)
( Since a VBA coding works from right to left, and because we are usually only interested in the final hwnd, you will often see such code lines simplified to use the same variable, hwnd, pseudo like
hwnd = Function(hwnd, arga, argb)
hwnd = Function(hwnd, argx, argy)
hwnd = Function(hwnd, argz, argy) )
It is important not to get those last two points mixed up: We don’t have to delve into the hierarchy to reference a window if we have the hwnd; but we may need to do so if we want to get that hwnd with our coding. This latter point is often missed when learning or initially using simple API codings, since we may be just working at the same "level" on our desktop, ( although this "level" word needs to be used lightly/ carefully , - we may conceive it to be things we "see", whereas we may have "invisible" windows and also there may be other "level -type" organisations of the windows not strictly part of the hierarchical windows structure, for example the "z – order" which is the order in which windows are "seen on top of eachother" ). In some blogs and documentation we would sometimes say we usually begin at the top-level window if writing coding, although smart people with good deep down knowledge of computers might not like the sound of that.
I think in most all day use we can generally regard, at least in Layman terms, that the desktop is "where we mostly are" and that this desktop is the top level, so the hierarchical nature and this strange need to "walk the tree" is often over looked. Its perhaps worth noting that one of the few simple APi functions taking no arguments, that the average user may come across is the GetDesktopWindow which returns the handle of the desktop. Most other handle getting API functions require arguments that often need some thinking about
3_ I forgot the third point, I will add it later
The hierarchical structure, Spy software and other third party software/ lists/ explanations
Before getting into some demonstrative coding, we can look at some useful third party tools
_ API function lists and explanations:
https://eileenslounge.com/viewtopic.php?p=322050#p322050
ApiViewer 2004 https://app.box.com/s/qbz657wp505n4vdgp3rg67dltksma5wx
https://eileenslounge.com/viewtopic.php?p=322151#p322151
http://allapi.mentalis.org/apilist/apilist.php http://allapi.mentalis.org/apilist/apilist.php
API-Gude 3.7
https://app.box.com/s/3orl65g0rzwktbi39ser8qdu46rshp0y
https://app.box.com/s/bufdyf643jujd86iuloztwhscvicwb34
https://app.box.com/s/ckt6a0p57245j879wvuit7s4vi9n0oxt
https://app.box.com/s/jr5aoc3nsdzziqb2spgmtxnyinuxseui
_Spys
These crawl the operating system: It gives a view of your systems processes, Threads, Windows and other messages
The main thing the commonly called spy programs are used for is a graphical view of the window things and window like things, - remember the term is not restricted to the obvious rectangular things we experience:
There are a few. You have a graphical view of your systems processes, Threads, Windows and other messages
( https://youtu.be/C43btudYyzA?list=PL6OYc4rwKjcNirRW9cX4N1_2VfDnMdnO s&t=178 )
The standard one is Microsoft Spy++. I have not figured out yet how to get it working without Visual Studio bloat. (I will try later). It does give nice view of the Hierarchical structure.
At the other extreme there is a small portable, winspy, ( https://app.box.com/s/kmkjg0djef8je9lpcrp2ufm80sjv5l4y ) , with a slightly different view.
https://i.postimg.cc/nhPrHqYr/winspy-and-Microsoft-Spy.jpg 6129
https://i.postimg.cc/k5R4DDfc/winspy-and-Microsoft-Spy.jpg https://i.postimg.cc/k5R4DDfc/winspy-and-Microsoft-Spy.jpg (https://postimages.org/)
I am not sure yet of advantages / disadvantages, of either, but I have a feeling that Microsoft Spy++ and some of the installable larger alternatives my sometimes cause some problems / crashes.
It can be useful to use the Spys ++ initially early on so as to see the hierarchical structure, as a self made coding for that might come at a later intermediate level or advanced level. However for an intermediate / beginner level, we can look at the top-level window, as long as we bear in mind the points made about the hierarchical structure and the likely need to "walk the tree", we can get some useful beginner information and understanding if we write a coding for that. The danger can be doing this simple codings before the points about the hierarchical structure and the likely need to "walk the tree", as I did originally, (https://eileenslounge.com/viewtopic.php?p=223629#p223629)but 6 years later, 2024, I am making better progress, amongst other reasons due to some better more enlightened help. ( https://eileenslounge.com/viewtopic.php?p=322075#p322075 )
A "Top level" window handle getting program
This one (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24916&viewfull=1#post24916) has had a few discussions and versions
https://eileenslounge.com/viewtopic.php?f=30&t=41610
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24921&viewfull=1#post24921
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24925&viewfull=1#post24925
Here is another version
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24926&viewfull=1#post24926
The main new or changed features of this version are a few more explaining comments, and in the first column, the hwnd number is additionally given in Hexagonorrhoea and (2' compliment) binary. For the normal column width these extra numbers are not visible, but they are there for reference because:
_ Spy's typically have Hexagonorrhoea so it is convenient for comparisons
_ I want to jeep my eye on the binary to see if there are any typical values / patterns
If I run that coding at a time and conditions on my computer, similar to those as I made those Screenshots above, and compare for example the numbers for an open Notepad text file, then we can see some good correlation with the top level results
https://i.postimg.cc/BbtGWnqr/Good-correlation-with-Spys-and-my-coding.jpg ( Full handle numbers: 224003622 D5A0626 00001101010110100000011000100110 )
https://i.postimg.cc/GT0fGrTK/Good-correlation-with-Spys-and-my-coding.jpg (https://postimg.cc/GT0fGrTK) 6130
The window Title also seems in agreement
_____ Workbook: GetHwndClassNameCaptionHwnd.xls ( Using Excel 2013 32 bit )
224003622 D5A0626 00001101010110100000011000100110NotepadNeues Textdokument.txt - Editor
224003622
Worksheet: GetDesktopClassNames
We can see however that the coding only gets us the top level information. We can often get at that information with coding, we must just remember the important point that in coding we must do it in steps, "walking the tree"
In the coding and associated forum Thread posts there is some general top level coding with explanations.
In the next post we will do some shorter simple coding, getting and using handles for that text file
DocAElstein
02-23-2018, 03:16 PM
"FindWindowA"
When discussing handles, the API function "FindWindowA" is perhaps one of the most common, and since obtaining a handle is a very common action in API coding, then it is perhaps one of the most common API functions.
Let us remind ourselves what this handle, hwnd is about, in particular with API VBA coding: Knowing this unique identifying number, we can interact in many ways with a window via API functions: we can do many things to, or get properties from, a window, but we will usually need to give the API function the identifying number so it knows which window.
We could get this number via Third party software and use that in any coding to get directly at any window, but that is of limited use since a different handle number will be given for any window every time it is open.
If we want to use a coding to consistently interact with a window, the coding will need to get the handle, or handles that we need, (and an important side issue to remember is that we generally can only get a handle with an immediate relation to another handle, so if we want a handle some way down the hierarchy, then we will have to do it in a multi-line stepping process, sometimes referred to as "walking the tree" )
All three of the code lines below will get the handle of a window in the current level , typically in such an example, the current level is the desktop. – So I am not "walking the tree" here, - I am simply showing three argument choice alternatives for the same single code line. For this to work you will need to have open Notepad with a file named Neues Textdokument.txt . It doesn’t matter where that file is stored but it does need to be open, showing on the desktop (https://i.postimg.cc/BZKj10Mm/Neues-Textdokument-txt-Editor.jpg), and note importantly, if using the argument lpWindowName, then you must use the window name you see, and that may be a bit different to the file name. In this example it is Neues Textdokument.txt - Editor
If you do not have the text file open, then the code lines will not error, but you will just get 0 for the handle number.
With that ext file open, If the coding works as it should, you will see in the Immediate window, similar numbers to those I have indicated in the 'comments, but they are unlikely to be exactly the same
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Sub TextAPI() '
Dim HdlTextFile As Long, MsgRef As Long
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:=vbNullString): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 224003622 D5A0626
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 224003622 D5A0626
Let HdlTextFile = FindWndNumber(lpClassName:=vbNullString, lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 224003622 D5A0626
End Sub
In that coding the lpWindowName is what typically is seen as the window title, lpClassName is technically a Class of sorts , it can sometimes be easily related to the thing running, in this case Notepad, but the name is not always so obvious, for example Excel is XLMAIN and Word is really weird, OpusApp
https://www.eileenslounge.com/viewtopic.php?p=322424#p322424
There are two ( three ** ) main things to be learnt from the next coding below, one is new, the other is something important already touched on a few times, the "walking the tree" idea.
(** An extra thing to clarify another point made few times, has come I by chance: In between the next coding and the last coding, the Laptop was restarted. I opened windows/ software similarly to how they had previously been. Never the less, none of the handles obtained in the last coding are any use to us: Even though the first main code line actually is identical to one in the previous coding, the handle obtained is different : A different handle number is given for any window every time it is open.)
FindWindowEx
Hopefully this new coding will get one ( two** ) important point finally clear at this early stage: Although we can directly reference any window anywhere if we know its handle, we will usually need to determine it in the same coding that uses it, and functions are only available to find the handle in close relation to another, so we must ("walk the tree”).
FindWindowEx is one of the commonest functions to do that. As often with such a function , the first argument required is the handle of the nearby window to that which we want.
( A phenomena ( Null , Empty , Long zero 0& , vbNullString etc ) , will also briefly be mentioned that we see for the first time in one of its guises here )
As example, we consider the same open text file that we considered. Here is a view ( using portable winspy ), opening up all + to revel the full "tree"
https://imgur.com/6Cq1Dj7 https://i.imgur.com/s7qbFaJ.jpeg
The first thing we see, seems to be something like the main window we might be familiar with. So that might be a useful one to have the handle of, https://i.postimg.cc/LX5Q1c5W/Notepad-Edit-window.jpg
In the coding below, the first main line is the code line of the last coding, and note the handle I obtained is shown in the ' comments, is different to that previously obtained.
https://i.postimg.cc/CL3LBDpc/Sub-Text-API.jpg 6137 https://i.postimg.cc/ZCLhXWRN/Sub-Text-API.jpg (https://postimg.cc/ZCLhXWRN)
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Sub TextAPI() '
Dim HdlTextFile As Long, MsgRef As Long
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
Dim HdlEdit As Long
Let HdlEdit = FindWindowEx(hWnd1:=HdlTextFile, hWnd2:=0, lpsz1:="Edit", lpsz2:=""): Debug.Print HdlEdit & " " & Hex(HdlEdit) ' 6030920 5C0648
Let HdlEdit = FindWindowEx(hWnd1:=0, hWnd2:=0, lpsz1:="Notepad", lpsz2:="Neues Textdokument.txt - Editor"): Debug.Print "0, 0, " & HdlEdit & " " & Hex(HdlEdit) ' 0, 0, 984776 F06C8
End SubThis will be required for the first argument of FindWindowEx, since I am "walking the tree", in this case one step
I will only talk around some of the important argument issues I will only talk around some of the important argument issues
Its best to get a good look at the Function and argument descriptions, for example here currently,
http://allapi.mentalis.org/apilist/FindWindowEx.shtml
, and remember that the original allapi.net site is very well archived at Archive org wayback machine, so most things can be found by trying something corresponding like this http://allapi.net/apilist/FindWindowEx.shtml
In the Wayback machine you would search for that http://allapi.net/apilist/FindWindowEx.shtml, like this https://imgur.com/35EeKLP https://i.postimg.cc/0N8B8MsP/Archive-org-wayback-allapi-net-apilist-Find-Window-Ex.jpg
https://i.postimg.cc/fVrKCbyr/Archive-org-wayback-allapi-net-apilist-Find-Window-Ex.jpg (https://postimg.cc/fVrKCbyr) https://i.imgur.com/35EeKLP.jpeg
In fact, Archive org wayback machine seems to have the whole site very well archived so you can start at an archived main page, then use the links which seem to work to take you further. I will only talk around some of the important argument issues
The second main line, HdlEdit = FindWindowEx(hWnd1:=HdlTextFile, hWnd2:=0, lpsz1:="Edit", lpsz2:="") is demonstrating the common use of FindWindowEx
Phenomenon Null , Empty , Long zero 0& , vbNullString etc.
The third line is intended to give an indication of a phenomena that later will be noticed more significantly later: A Null . Empty , Long zero 0& , normal simple zero in some cases, can often have a specific meaning, and cannot always be treated so carelessly. This is yet another example of the more "dangerous" aspect of API which things like normal VBA and VB were designed to help protect us from.
This first example seems relatively harmless: I note that a simple 0 is satisfactory, whereas in other cases a 0& would be required
As noted I will not always give detailed explanation of all arguments, as having the list with explanations (http://allapi.mentalis.org/apilist/apilist.php)to hand is perhaps more useful/more efficient. The second hwnd argument is clearly an order in similar level things , type qualifier, and so its reasonable that a form of nothing given , 0, will likely still give us something useful, in this case perhaps the first or most important. It is difficult to be sure about these things. (For one reason people claiming to know seem a bit reluctant to give simple clear but detailed explanations.) The main argument, the first, being left at a form of nothing, 0, could be thought perhaps of dong a step of not step, in other words staying where you are. So it perhaps makes sense that we then get the handle returned of the main text file window, the same value as in the first main code line. Possibly what ever process moves a bit to find something and then give the answer, was called into play, but then not moved, so found the thing again that it last did, the thing in the current position.
DocAElstein
02-23-2018, 03:16 PM
Messaging window.
Microsoft windows is controlled by messaging, and this messaging is a major part of the VBA Windows API subject.
Example: ShowWindow ( Example, maximise and Minimise) http://allapi.mentalis.org/apilist/ShowWindow.shtml
A look at the function description makes this fairly simple to understand. Two arguments, the first, necessarily requiring the hwnd of the window to be controlled in some way/ shown I some way, as specified by the second argument. In effect the second argument is just a number, from a set of numbers which determine what will be done
We are using for the first time in this example the API constants. Using these is more of a conventional practice: Although there are some parallels with Early Binding of the available Library functions (https://www.excelfox.com/forum/showthread.php/2240-VBA-referring-to-external-shared-Libraries-1)-Early-1-5)-Laterly-Early-and-2)-Late-Binding-Techniques), we do not have available any named constants in VBA API work, in the same way that we do sometimes after Early Binding.
But rather than using a number, we define a constant, and use that instead. The constant can have any name we like, ( and in fact, we can also be a simple variable rather than a Constant, but conventionally we use the recognised naming and assigning way. So we will use these sort of conventions also
Const SW_MINIMIZE As Long = 6
Const SW_MAXIMIZE As Long = 3
https://i.postimg.cc/4y94MXh1/API-Constants.jpg https://i.postimg.cc/RqxCx27x/API-Constants.jpg
The following demonstration coding works on a same text file as the previous coding and is self explanatory if run in debug mode
https://i.postimg.cc/DZdPG4g9/Show-Window-Max-Min-Norm.jpg
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Const SW_MINIMIZE As Long = 6
Private Const SW_MAXIMIZE As Long = 3
Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Const SW_NORMAL As Long = 1
Sub TextAPI()
Dim HdlTextFile As Long, MsgRef As Long
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
Dim FuncReturn As Variant
Let FuncReturn = ShowWindow(HdlTextFile, SW_MINIMIZE): Debug.Print FuncReturn ' 24
Let FuncReturn = ShowWindow(HdlTextFile, SW_MAXIMIZE): Debug.Print FuncReturn ' 24
Let FuncReturn = ShowWindow(HdlTextFile, SW_NORMAL): Debug.Print FuncReturn ' 24
End Sub
Example: ShowWindow ( Example Hide Unhide)
This example follows on directly from the last, and perhaps requires little explanation. This perhaps borders on the area of "dangerous".
Using the same text file as example I hide and unhide the window. I deliberately do this in the pair so as to hopefully leave all back in the previous normal
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Const SW_HIDE As Long = 0
Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Const SW_SHOW As Long = 5
Sub TextAPI()
Dim HdlTextFile As Long, MsgRef As Long
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
Dim FuncReturn As Variant
Let FuncReturn = ShowWindow(HdlTextFile, SW_HIDE): Debug.Print FuncReturn ' 24
Let FuncReturn = ShowWindow(HdlTextFile, SW_SHOW): Debug.Print FuncReturn ' 0 - ' If the window was previously hidden, the return value is zero.
End Sub
Example, close window ( SendMessageA )
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Const WM_CLOSE As Long = &H10
Sub TextAPI()
Dim HdlTextFile As Long
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
Dim FuncReturn As Variant
Let FuncReturn = SendMessage(HdlTextFile, WM_CLOSE, 0, 0): Debug.Print FuncReturn '
End Sub
Example, Capture window text ( SendMessageA )
These API things can be a bit obscure in their functioning and somewhat difficult to define, group or order in terms of what they are about. This example demonstrates that.
In this example we remain with our text file examples, and look again at a text file and the corresponding winspy view centred around the "second level" Edit window, whose handle we found in an initial second handle getting coding above (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24908&viewfull=1#post24908). We noted that it looked like it might be the window that we typically concern ourselves with when working on such a text file.
In fact, as a confirmation, if we restart the winspy from new , we will initially have a small winspy window (https://i.postimg.cc/ZKKtchPq/Drag-winspy-into-text-editor.jpg), and if we leave it initially small, but drag the small target/sight thing into the main part of the text file, then it expands and gives what it thinks is the window we dragged it into, in this case, indeed the Edit window with the actual text form the text file somehow showing in winspy.
https://i.postimg.cc/sx3Fqktw/Draged-winspy-into-text-editor.jpg
https://i.postimg.cc/8JXnr0k6/Draged-winspy-into-text-editor.jpg (https://postimg.cc/8JXnr0k6)
Now it all gets a bit hit and miss and god knows if anyone really knows of any logic to the seemingly hap hazard way of doing things here…
The last two arguments for the SendMessageA are not so well defined: - Specifies additional message-specific information. , and the documentation to the returned values is just as much use: - The return value specifies the result of the message processing and depends on the message sent.
About as useful as a chocolate Teapot and as welcome as a fart in a space suit.
Before completing this I took a look in a bit more detail in the next post (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24909&viewfull=1#post24909)and here
DocAElstein
02-28-2018, 12:22 AM
Coding and some extra notes to go with the last post (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24914&viewfull=1#post24914)and these main forum Threads
https://eileenslounge.com/viewtopic.php?f=30&t=41659
Don’t run this – it crashes Cures below
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long ' To "walk a step down in the tree" from the code line above
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Const WM_GETTEXTLENGTH As Long = &HE ' 14 Hex(14) is E
Const WM_GETTEXT As Long = &HD ' 13 Hex(13) is E
Sub TextAPI() '
1 Dim HdlTextFile As Long: Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="TextFile.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
2 Dim HdlEdit As Long: Let HdlEdit = FindWindowEx(hWnd1:=HdlTextFile, hWnd2:=0, lpsz1:="Edit", lpsz2:=""): Debug.Print HdlEdit & " " & Hex(HdlEdit) ' 6030920 5C0648 ' ' To "walk a step down in the tree" from the code line above
3 Dim Lenf As Long: Let Lenf = SendMessage(HdlEdit, WM_GETTEXTLENGTH, 0&, 0&): Debug.Print Lenf
4 Dim Biffa As String: Let Biffa$ = Space$(Lenf): Debug.Print Biffa$
5 Dim FuncReturn As Long: Let FuncReturn = SendMessage(HdlEdit, WM_GETTEXT, 5, Biffa$): Debug.Print FuncReturn
6 Debug.Print Biffa & " Length Biffa is " & Len(Biffa$)
End Sub
Cure 1
Here is cure 1(i) and 1(ii): add ByVal in the SendMessagA Declare line, but then also: _1(ii) Somehow related is something, a similar phenomena that I have seen before: I must now change in line 3, the last 0 to 0&
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long ' To "walk a step down in the tree" from the code line above
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Any) As Long
Const WM_GETTEXTLENGTH As Long = &HE ' 14 Hex(14) is E
Const WM_GETTEXT As Long = &HD ' 13 Hex(13) is E
Sub TextAPI() '
1 Dim HdlTextFile As Long: Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="TextFile.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
2 Dim HdlEdit As Long: Let HdlEdit = FindWindowEx(hWnd1:=HdlTextFile, hWnd2:=0, lpsz1:="Edit", lpsz2:=""): Debug.Print HdlEdit & " " & Hex(HdlEdit) ' 6030920 5C0648 ' ' To "walk a step down in the tree" from the code line above
3 Dim Lenf As Long: Let Lenf = SendMessage(HdlEdit, WM_GETTEXTLENGTH, 0, 0&): Debug.Print Lenf
4 Dim Biffa As String: Let Biffa$ = Space$(Lenf): Debug.Print Biffa$
5 Dim FuncReturn As Long: Let FuncReturn = SendMessage(HdlEdit, WM_GETTEXT, 5, Biffa$): Debug.Print FuncReturn
6 Debug.Print Biffa & " (Length Biffa is " & Len(Biffa$) & ")"
End Sub
Cure 2
_2 I can forget _1(i) and _1(ii), making just one change, by adding a ByVal at line 5
Option Explicit
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long ' To "walk a step down in the tree" from the code line above
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Const WM_GETTEXTLENGTH As Long = &HE ' 14 Hex(14) is E
Const WM_GETTEXT As Long = &HD ' 13 Hex(13) is E
Sub TextAPI() '
1 Dim HdlTextFile As Long: Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="TextFile.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 984776 F06C8
2 Dim HdlEdit As Long: Let HdlEdit = FindWindowEx(hWnd1:=HdlTextFile, hWnd2:=0, lpsz1:="Edit", lpsz2:=""): Debug.Print HdlEdit & " " & Hex(HdlEdit) ' 6030920 5C0648 ' ' To "walk a step down in the tree" from the code line above
3 Dim Lenf As Long: Let Lenf = SendMessage(HdlEdit, WM_GETTEXTLENGTH, 0, 0): Debug.Print Lenf
4 Dim Biffa As String: Let Biffa$ = Space$(Lenf): Debug.Print Biffa$
5 Dim FuncReturn As Long: Let FuncReturn = SendMessage(HdlEdit, WM_GETTEXT, 5, ByVal Biffa$): Debug.Print FuncReturn
6 Debug.Print Biffa & " (Length Biffa is " & Len(Biffa$) & ")"
End Sub
DocAElstein
02-28-2018, 12:22 AM
The ShellExecute function
The ShellExecute function opens or prints a specified file in different ways, manipulating window(s) as it goes. The file can be an executable file or a document file. It offers some error indications too. So perhaps it is one of those things where it is the more fundamental and more useful version of something available in VB / VBA, perhaps something similar to like a worksheet function used from Application rather than Application.WorksheetFunction (https://www.eileenslounge.com/viewtopic.php?p=297474#p297474)
In this case the difference between the VBA shell function (execute) (https://support.microsoft.com/de-de/topic/shell-funktion-ausf%C3%BChren-ff2e4b1b-712d-4e34-aea6-6832eadd3c63) and the api shell execute are a bit more significant although the difference in error handling follows the similar trend, in that the VBA shell function would error when the api shell execute might give us some useful information. This perhaps ties up with the idea of us being more protected in the VB VBA normal environment, as some wiring is perhaps in place to take action on an error, rafter than telling us about it. The final terminal error that we then might get is then done when all other important things were done. So as ever, we should be more careful how we tread when using api things. I will keep, things simple for now and just open a text file
' https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24915&viewfull=1#post24915
Private Declare Function FindWndNumber Lib "user32.dll" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Const SW_NORMAL As Long = 1
Sub TextAPI() '
Dim HdlTextFile As Long
' Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="Neues Textdokument.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) '
Let HdlTextFile = FindWndNumber(lpClassName:="Notepad", lpWindowName:="TextFile.txt - Editor"): Debug.Print HdlTextFile & " " & Hex(HdlTextFile) ' 0 0
Dim FuncReturn As Variant
' Let FuncReturn = ShellExecute(HdlTextFile, "open", "C:\Users\Elston\Desktop\Neues Textdokument.txt", 0, 0, SW_NORMAL): Debug.Print FuncReturn '
' Let FuncReturn = ShellExecute(HdlTextFile, "open", "C:\Users\Elston\Desktop\TextFile.txt", 0, 0, SW_NORMAL): Debug.Print FuncReturn '
Let FuncReturn = ShellExecute(HdlTextFile, "open", ThisWorkbook.Path & "\TextFile.txt", 0, 0, SW_NORMAL): Debug.Print FuncReturn ' 42
End Sub
Here we have perhaps another example of the strange varying way that arguments are handled with these api things, as HdlTextFile = FindWndNumber(………. line which we have a lot, is now used in a strange different way. It can’t be getting a handle this time, but never the less, the documentation suggests it somehow in conjunction with the first argument of ShellExecute( organises which parent window is used for displaying a user interface or error messages?? … maybe another case of … I can't think of any logical way to organise all this back end working at the upper user interface level, so just make an argument work however it can, don' tell anyone too much about it with any decent documentation, let a few hacks think they know, even some here who think they are creating or did create windows, and let them tell people about it and then good riddance to it all, I am off with my wife to enjoy the sun in a distant land, at least until she goes mental, as they all do eventually …. Bill Gates, early 80’s, …. I told him , or maybe it was one of his mates trying to sell windows to me, … I was not interested in those pretty coloured square boxes things, they all look like some sort of small child’s video game xmas present
DocAElstein
10-23-2024, 01:50 PM
This is post #7
https://www.excelfox.com/forum/showthread.php/2986-Version-Info-using-VBA-and-registry-quirks?p=24876&viewfull=1#post24876
https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues?p=24876&viewfull=1#pst24876
This is post #552
https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues/page56#post24323
https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues/page56#post24323
https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues?p=24317&viewfull=1#post24323
https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues?p=24317&viewfull=1#post24323
Edit: I gave up with this post after getting so many quirky results in Windows 10 and windows 11, so I started this Thread (https://www.excelfox.com/forum/showthread.php/2986-Version-Info-using-VBA-and-registry-quirks)
Some functions and rough notes on Versions on some computers used in the testings from this page 56 (https://bit.ly/40fepOB) and page 55 (https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues/Page55#post24120) and a few other related forum postings
Its useful to keep track of some of your computer specs, and Office versions when playing around with the codings on this page.
The macro below, Sub WhatAmI() ( along with the functions under it which go with it) may help to get some of that info. Run it and some info should appear in the Immediate Window. (From the VB Editor, hold the Ctrl key down and then hit key g to get that Immediate Window up)
Note there are a few bugs and quirks :
_ Application.OperatingSystem can give quirky answers in windows 11 (https://eileenslounge.com/viewtopic.php?p=313844#p313844) , so the operating system result may be wrong for if you have Windows 11. In fact currently it seems a bit wonky everywhere
_I don’t know if that macro gets it correct in Office versions 2016, 2019,2021, 2024 or 365, since I don’t have them versions to check. My guess is that it might be a bit iffy for 2016 2019,2024 or 365
Sub WhatAmI() ' https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues?p=24323&viewfull=1#post24323 https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-pasting-Cliipboard-issues/page56#post24323
Debug.Print ExcelVersion & " " & Application.OperatingSystem & " (ApplicationVersion " & CLng(Val(Application.Version)) & ") Computer named " & CreateObject("WScript.Network").ComputerName ' Environ$("computername") Nigel Heffernan https://stackoverflow.com/questions/3551055/how-to-get-name-of-the-computer-in-vba/10108951#10108951
' Windows 11 (2021) ...
' Windows 10 S (2017) ...
' Windows 10 (2015) - MS Version 6.4. ...
' Windows 8/8.1 (2012-2013) - MS Version 6.2/6.3. ...
' Windows 7 (2009) - MS Version 6.1. ...
' Windows Vista (2006) - MS Version 6.0. ...
' Windows XP (2001) - MS Version 5.1. ...
' Windows 2000 (2000) - MS Version 5.0.
End Sub
Private Function ExcelVersion() As String ' From Rory somewhere, then a blind mod for above 2016 from https://excelguru.ca/check-the-application-version-in-modern-office/ , which probably does not work too well - https://excelguru.ca/check-the-application-version-in-modern-office/#comment-358558
Dim Temp As String
'On Error Resume Next
#If Mac Then
Select Case CLng(Val(Application.Version))
Case 11: Temp = "Excel 2004"
Case 12: Temp = "Excel 2008" ' this should NEVER happen!
Case 14: Temp = "Excel 2011"
Case 15: Temp = "Excel 2016 (Mac)"
Case Else: Temp = "Unknown"
End Select
#Else
Select Case CLng(Val(Application.Version))
Case 9: Temp = "Excel 2000"
Case 10: Temp = "Excel 2002"
Case 11: Temp = "Excel 2003"
Case 12: Temp = "Excel 2007"
Case 14: Temp = "Excel 2010"
Case 15: Temp = "Excel 2013"
Case 16: ' https://excelguru.ca/check-the-application-version-in-modern-office/
Let Temp = ForVersion16() '
Case Else: Temp = "Unknown"
End Select
#End If
#If Win64 Then
Let Temp = Temp & " 64 bit"
#Else
Let Temp = Temp & " 32 bit"
#End If
Let ExcelVersion = Temp
End Function
Function ForVersion16() As String ' https://excelguru.ca/check-the-application-version-in-modern-office/ This may be crap - https://excelguru.ca/check-the-application-version-in-modern-office/#comment-358558
'Test the Office application version, 'Written by Ken Puls (www.excelguru.ca) ' ...."From Office 2016 onwards, Microsoft has not revved the Application.Version number - they all show as 16.0 - giving you no way to differentiate between versions."....
Dim registryObject As Object
Dim rootDirectory As String, keyPath As String
Dim arrEntryNames As Variant, arrValueTypes As Variant
Dim x As Long
'Check for existence of Licensing key
Let keyPath = "Software\Microsoft\Office\" & CStr(Application.Version) & "\Common\Licensing\LicensingNext"
Let rootDirectory = "."
Set registryObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & rootDirectory & "\root\default:StdRegProv")
registryObject.EnumValues &H80000001, keyPath, arrEntryNames, arrValueTypes
On Error GoTo ErrorExit
For x = 0 To UBound(arrEntryNames)
If InStr(arrEntryNames(x), "365") > 0 Then
Let ForVersion16 = 365
Exit Function
End If
If InStr(arrEntryNames(x), "2019") > 0 Then
Let ForVersion16 = 2019
Exit Function
End If
If InStr(arrEntryNames(x), "2021") > 0 Then
Let ForVersion16 = 2021
Exit Function
If InStr(arrEntryNames(x), "2024") > 0 Then
Let ForVersion16 = 2024
Exit Function
End If
Next x
Exit Function
ErrorExit:
'Version 16, but no licensing key. Must be Office 2016
Let ForVersion16 = 2016
End Function
'Some typical results of my computers for future reference for me because I keep forgetting which versions I have where
' ExcelVersion Application.OperatingSystem (CLng(Val(Application.Version) CreateObject("WScript.Network").ComputerName ' Environ$("computername") Nigel Heffernan https://stackoverflow.com/questions/3551055/how-to-get-name-of-the-computer-in-vba/10108951#10108951
'(based on App.version)
' Excel 2007 32 bit Windows (32-bit) NT 6.00 (ApplicationVersion 12) Alan's Computer named ELSTON-LAPTOP KB Vista Office 2007
' Excel 2010 32 bit Windows (32-bit) NT 6.00 (ApplicationVersion 14) Computer named ELSTON-PC Alan's Computer GB Vista Office 10
' Excel 2003 32 bit Windows (32-bit) NT 6.01 (ApplicationVersion 11) Computer named ALAN-PC Martin Windows 7 Pro Office 2003
' Excel 2010 32 bit Windows (32-bit) NT 6.01 (ApplicationVersion 14) Computer named ALAN-PC Martin Windows 7 pro Office 2010
' Excel 2010 32 bit Windows (32-bit) NT 6.02 (ApplicationVersion 14) Computer named TM5730G Alan's Computer Verranda Windows 10 Office 10
' Excel 2013 32 bit Windows (32-bit) NT :.00 (ApplicationVersion 15) Computer named DESKTOP-G7BIH1B Alan's Computer SerSzuD2 Windows 10 Office 13
' Excel 2016 (Windows) 32 bit Windows (32-bit) NT 10.00 (ApplicationVersion 16) Alan's Computer named DESKTOP-14C4HCR Torrox Windows 10 Office 2016
' Excel 2010 32 bit Windows (32-bit) NT 6.02 (ApplicationVersion 14) Computer named ASPIRE7730G Elfy Windows 11 Office 10
'
DocAElstein
11-12-2024, 08:16 PM
This is page 2
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page2
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page2
This is post #11 forum post24916
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page2
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page2
This is post #11 forum post24916
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24916&viewfull=1#post24916
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page2
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24916&viewfull=1#post24916
Some notes, codings etc. in support of some other posts
https://eileenslounge.com/viewtopic.php?p=321979#p321979
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24904&viewfull=1#post24904
Getting some windows identification info.
Main coding courtesy of Dev Ashish, http://access.mvps.org/access/api/api0013.htm
( and https://eileenslounge.com/viewtopic.php?p=321978#p321978 )
I did some minor adjustments, mostly in output to suit my own experiments
' Original main Code Courtesy of Dev Ashish http://access.mvps.org/access/api/api0013.htm and https://eileenslounge.com/viewtopic.php?p=321978#p321978
'
Private Declare Function apiGetClassName Lib "user32" Alias "GetClassNameA" (ByVal Hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long
Private Declare Function apiGetWindow Lib "user32" Alias "GetWindow" (ByVal Hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function apiGetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal Hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function apiGetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal Hwnd As Long, ByVal lpString As String, ByVal aint As Long) As Long
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long
Private Const mcGWCHILD = 5
Private Const mcGWHWNDNEXT = 2
Private Const mcGWLSTYLE = (-16)
Private Const mcWSVISIBLE = &H10000000 ' Watch window gives 268435456 (even when no code is running)
Private Const mconMAXLEN = 255
Public Sub fEnumWindows()
' For worksheet output, not important for understanding the main coding
Dim Ws As Worksheet: Set Ws = ThisWorkbook.Worksheets.Item(1)
Dim Lc As Long, Lr As Long: Let Lc = Ws.Cells.Item(2, Ws.Columns.Count).End(xlToLeft).Column
Let Ws.Cells.Item(1, Lc + 1) = CreateObject("WScript.Network").ComputerName & " " & Format(Now(), "ddd,dd,mmm,yyyy") ' Environ$("computername") Nigel Heffernan https://stackoverflow.com/questions/3551055/how-to-get-name-of-the-computer-in-vba/10108951#10108951
Let Ws.Cells.Item(2, Lc + 1) = "Hwnd": Let Ws.Cells.Item(2, Lc + 2) = "Class Name": Let Ws.Cells.Item(2, Lc + 3) = "Caption": Let Ws.Cells.Item(2, Lc + 4) = "Hwnd( Caption)": Let Ws.Cells.Item(2, Lc + 5) = "enum visible?"
Dim lngx As Long, lngLen As Long, lngStyle As Long, strCaption As String
Let lngx = apiGetDesktopWindow(): Debug.Print "Geted Desktop Window " & lngx & " " & " CLass name " & fGetClassName(lngx)
Let lngx = apiGetWindow(lngx, mcGWCHILD): Debug.Print " First child to Desktop " & lngx & " CLass name " & fGetClassName(lngx) ' GW_CHILD = 5 The topmost of the given window's child windows. This has the same effect as using the GetTopWindow function, ... usually at the top of all the other children in the Z-order
Do While Not lngx = 0 ' We are looping "equal level children", seperated not realy, just look seperate to us because of the seen to us z order
Let strCaption = fGetCaption(lngx)
' If Len(strCaption) > 0 Then ' Those without a caption seem not important
Let lngStyle = apiGetWindowLong(lngx, mcGWLSTYLE) ' apiGetWindowLong gets info, GWL_STYLE -16 retrieves the window styles
' For enum visible windows only
' If lngStyle And mcWSVISIBLE Then '
Let Lr = Ws.Cells.Item(Ws.Rows.Count, Lc + 1).End(xlUp).Row ' Handle Class name Caption
If lngStyle And mcWSVISIBLE Then
Let Ws.Cells.Item(Lr + 1, Lc + 5) = "enum visible " & lngStyle & " And " & mcWSVISIBLE
Else
'Let Ws.Cells.Item(Lr + 1, Lc + 5) = lngStyle & " And " & mcWSVISIBLE
End If
Let Ws.Cells.Item(Lr + 1, Lc + 6) = lngStyle: Ws.Cells.Item(Lr + 1, Lc + 7) = mcWSVISIBLE
Debug.Print FindWndNumber(lpClassName:=fGetClassName(lngx), lpWindowName:=vbNullString), fGetClassName(lngx); Tab(50); fGetCaption(lngx); Tab(100); FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
Let Ws.Cells.Item(Lr + 1, Lc + 1) = lngStyle & " " & FindWndNumber(lpClassName:=fGetClassName(lngx)): Let Ws.Cells.Item(Lr + 1, Lc + 2) = fGetClassName(lngx): Let Ws.Cells.Item(Lr + 1, Lc + 3) = fGetCaption(lngx): Let Ws.Cells.Item(Lr + 1, Lc + 4) = FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
' End If
' End If
Let lngx = apiGetWindow(lngx, mcGWHWNDNEXT) ' GW_HWNDNEXT = 2 The window below the given window in the Z-order.
Loop ' While Not lngx = 0 ' I am going through all the child windows of the desktop windows
End Sub
Private Function fGetCaption(Hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(Number:=255 - 1, Character:="0") ' "00000000000000000000000000000000..........000"
Let intCount = apiGetWindowText(Hwnd:=Hwnd, lpString:=strBuffer, aint:=255) ' This makes strBuffer something like *MSCTFIME UI 0000000000000000............000"
If intCount > 0 Then Let fGetCaption = Left$(strBuffer, intCount)
End Function
Private Function fGetClassName(Hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(255 - 1, 0)
Let intCount = apiGetClassName(Hwnd, strBuffer, mconMAXLEN)
If intCount > 0 Then
Let fGetClassName = Left$(strBuffer, intCount)
End If
End Function
I got up to date more recently on my API references, https://eileenslounge.com/viewtopic.php?p=322050#p322050 , so I was able to understand a lot of that coding above.
But the logic of If lngStyle And mcWSVISIBLE Then confused me a bit, even though I understand what it is doing.
Investigating what typically finds its way into the coding at that line revealed that it is fed some big numbers on either side of the And , ( a fixed number on the right, varied numbers on the left).
I could not see how it becomes True in some numbers and not on others. It is obviously not a simple thing since at first glance there is no obvious pattern to what numbers give true: We typically seem to have some spread of big numbers, positive and negative. Example numbers in the next screen shot in column B and C. The results in column D are typical of what I got in a few ways with VBA codings, and they seem to be doing something similar to that code line with the same numbers as the code line typically gets, and they get the same results.
So its something to do with how in VBA , this sort of thing works
If ___ And ___ Then
Sub TestStrangeIfAndLogic()
Range("D2:D20").ClearContents
Dim Rw As Long
For Rw = 2 To 20
If Range("B" & Rw).Value And Range("C" & Rw).Value Then Let Range("D" & Rw) = "True?"
Next Rw
End Sub
Sub TestStrangeIfAndLogicArr()
Range("D2:D20").ClearContents
Dim Rw As Long, arrRws() As Variant: Let arrRws() = Range("A1:C20").Value
For Rw = 2 To 20
If arrRws(Rw, 2) And arrRws(Rw, 3) Then Let Range("D" & Rw) = "True?"
Next Rw
End Sub
https://i.postimg.cc/NMg25kxm/Strange-If-And-Then-logic-with-two-numbers.jpg 6122
https://i.postimg.cc/NMg25kxm/Strange-If-And-Then-logic-with-two-numbers.jpg (https://postimages.org/)
I went off to get some help, https://eileenslounge.com/viewtopic.php?f=30&t=41610
I got some good help, and the next few posts discus the issues, and get the final solutions and final understanding, which in initially looked like it would be fairly simple, after the help I got, but turned out to be a bit more complicated, mainly as I had never heard of …." 2’s Compliment Computer Codswollop" ( https://www.aimathcoach.com/en/mathgenerator/mathop/binary_2s_complement1/solution_guide/
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24921&viewfull=1#post24921 )
I start looking at this issue in more detail in the next few post
DocAElstein
11-15-2024, 02:39 AM
If lngStyle And mcWSVISIBLE Then
If lngStyle And mcWSVISIBLE Then
Some notes, codings etc. in support of some other posts
https://eileenslounge.com/viewtopic.php?p=321979#p321979 https://eileenslounge.com/viewtopic.php?f=30&t=41610
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24904&viewfull=1#post249016
Introduction
A code line from the last post
, If lngStyle And mcWSVISIBLE Then
What’s going on? – Hans told me (https://eileenslounge.com/viewtopic.php?p=322157#p322157) …. The number is looked at by VBA in its binary representation form, and each corresponding Bit at the same horizontal position for the two numbers is compared. This is referred to as bitwise AND of the binary representation of the numbers. (https://eileenslounge.com/viewtopic.php?p=322157#p322157)
In simple terms, If at any position both are 1 , then the result will be true…..
It all started here:
I had some strange results that I did not understand. It boiled down to some code lines such as this returning True
If -1811939328 And 268435456 Then
, whilst similar such as this returning False
If -2046820352 And 268435456 Then
At first glance there is no thing obvious to see to explain the difference in behaviour in the two examples
So, because ExcelFox is the adult thinking man’s forum, we are going to have a good look at it.
Knowing the answer, or appearing to be close to knowing it, suggests we want initially to get those two decimals into some String like " 0 1 " representation of a number( Binary computer stuff " 0 0 0 1 0 1 1 0 1 " )
A couple of points to consider
_(i) A string type representation of a lot of 0s and 1s is a good idea so that we don’t have problems with things like leading 0s vanishing when Excel or VBA messes with the format of a number we may write: In binary computer things the number will have typically some fixed character length, so we should not mess with that, or let Excel or VBA mess with it
_(ii) The first Bit/first position is always reserved for the sign character, (which is 1 for a negative number, and that sort of leads to the phenomena that Anding two negative numbers always results in a True. But it is not quite so straight forward always.
It's an artefact, perhaps, of both how computers store negative numbers and the bit wise way that the VBA And works.
The following function to convert a decimal to binary is useful to know about and understand, but bare in mind that solving the main issue ended up being a bit more involved.
A simple function to get the string like binary 0s and 1s representation of a number.
The basic idea: (To keep it simple initially in this first summary, we will not concern ourselves directly with the actual unbar of digits in the binary string of 1s and 0s )
It’s basically all based on the school maths way of converting a decimal to binary…. Take the decimal number and divide it by a number got from a high power of 2;
__ If that division comes out >= 1 , then you have your first binary digit, starting from the left of 1; then you subtract that number which was the high power of 2 from the decimal number , so the decimal number under consideration is now smaller
__ Else when that division comes out < 1 , then you have your first binary digit of 0 starting from the left. You leave the decimal number at the size it is.
Now you do the same again using the next power of 2 down as the denominator to get the next binary digit to the right. Eventually you are down to (2 ^0) to get the last binary digit at the right
The actual implementation in the coding.
We decide on some length limit for the string. For now, based on an initial quick empirical look and guess, I will go for up to 30 powers of 2, ( (2 ^ N) = (2 ^ 30) ). I might change that later based on experience. A big one initially will hopefully catch numbers as big as we have. This means the string length will be 32 characters, as in the string like binary 0s and 1s representation we have (2 ^ 0) at the right, (2 ^ 30) at the left, and also an extra sign bit included to be the **first left character. ( ** As it turns out it is not quite as simple as that )
A simple function can be one that builds the string….
, first with a 0 or 1 is added to the string depending on if the decimal number being converted is negative or positive
, then we successively divide the number by (2 ^ N) where N goes from 30 to 0.
__ If the result of the division results in 1 or 1 and a fraction more, we add** ( ** add as in including another character, via a & "1" not maths add + ) a "1" to the string, and reduce the decimal number by that used (2 ^ N) , before moving to the next N.
__ Else the division results in less than 1, then we add a 0, (and do not reduce the decimal value)
, then move on to the next N
Sub TestNumberInBinary()
Debug.Print NumberInBinary(9) ' 00000000000000000000000000001001
Debug.Print NumberInBinary(268435456) ' 00010000000000000000000000000000
End Sub
Public Function NumberInBinary(ByVal DecNumber As Long) As String
Rem 1 A negative number in a computer binary representation has a 1 at the first character position
Let NumberInBinary = IIf(DecNumber < 0, "1", "0")
Rem 2 we successively divide the number by (2 ^ N) where N goes from 30 to 0. If the result of the division results in 1 or 1 and a fraction more, we add** ( ** add as in including another character, not maths add ) a 1 to the string, and reduce the decimal number by that (2 ^ N) before moving to the next N. If the division resilts in less than 1, we add a 0, then move on to the next N Divide the decimal number by 2 to the power of N, with N geting smaller. Every tine the resulting number is equal or bigger than 1 the binary bit would be 1 and the decimal number we reduce by that 2 to the N, and keep going
Dim N As Long
For N = 30 To 0 Step -1 ' 30 seems to be the limit before something is too big
If DecNumber / (2 ^ N) >= 1 Then
Let NumberInBinary = NumberInBinary & "1"
Let DecNumber = DecNumber - (2 ^ N)
Else
Let NumberInBinary = NumberInBinary & "0"
End If
Next N
End Function
A function to mimic the behaviour of the VBA And with numbers is very easy.
Simply
_ convert the two decimal numbers to a string in the form of the computer binary 0s and 1s representation, (using for example the function I did above)
_ then starting from the left compare the characters in the corresponding position in the two strings. As soon as you get a 1 in both , you make the functions returned output as True and exit the function, otherwise the function returns false if you never get a pair of 1s at the same horizontal position
Public Function NumbersInVBAIf_And_Then(ByVal Dec1 As Long, Dec2 As Long) As Boolean
Rem 1 the two decimal numbers to a string in the form of the computer binary 0s and 1s representation
Dim Bin1 As String, Bin2 As String ' String representation helps prevent loosing leading 0's
Let Bin1 = NumberInBinary(Dec1): Bin2 = NumberInBinary(Dec2)
Rem 2 starting from the left compare the characters in the corresponding position in the two strings. As soon as you get a 1 in both , you make the functions returned output as True and exit the function, otherwise the function returns false if you never get a pair of 1s
Dim TPwr As Long
For TPwr = 1 To 32 Step 1
If Mid(Bin1, TPwr, 1) = 1 And Mid(Bin2, TPwr, 1) = 1 Then Let NumbersInVBAIf_And_Then = True: Exit Function
Next TPwr
End Function
Conclusions, … Oh dear :(
I thought it was too good to be true. It did tons of tests, my coding is sound, and definitely does what I think it should with all data extremes
It doesn’t’ get the right bloody results though: ….Compare… as before, column D ( which effectively does what the main full codng does ) which gets the correct results.
Based on everything so far, this is the test coding to get results in column E
Sub TryMyFuncsNumberInBinaryNumbersInVBAIf_And_Then()
Range("E2:E20").Clear
Dim Rw As Long, arrRws() As Variant: Let arrRws() = Range("A1:C20").Value
For Rw = 2 To 20
Let Range("E" & Rw) = NumbersInVBAIf_And_Then(arrRws(Rw, 2), arrRws(Rw, 3))
Next Rw
End Sub
The results, however, speak for themselves..
https://i.postimg.cc/2jxYmcbH/Bollox.jpg
6120 https://i.postimg.cc/2jxYmcbH/Bollox.jpg (https://postimages.org/)
Bollox
.... continued in next post
DocAElstein
11-15-2024, 11:55 PM
…. Continued from last post….
( …. as the saying goes, Two's complement, (three’s probably some other crazy idiotic computer mathematicians abortion) )
Bollox, what went wrong
It did not take long to find the problem. .. VBA ( and most computer stuff) apparently does not always use the simple binary logic
Just to review what I was dong, the simple binary logic: So I was following the simple logic like..
A number 7 is somehow in computer binary a variation of
8 4 2 1
0 0 0 0 0 0 0 1 1 1
, and correspondingly -7 I was thinking , (and in a few places I was even seeing stated….)
8 4 2 1
1 0 0 0 0 0 0 1 1 1
It aint quite like that, :( , ( at last in most modern day computer things)
It seems mostly we have something called Two's complement (https://en.wikipedia.org/wiki/Two%27s_complement)
This is the basic jist of it; ….. For the negative number, you do a few weird things…..
_ you first turn the positive number upside down / flip / invert or call it what you want to get this ( 0s become 1’s and visa versa )
8 4 2 1
1 1 1 1 1 1 1 0 0 0
_ Now you do a math add of 1,
( but important is that you do it in base 2 -
1+0 = 1
1+1 =0 and carry over a 1 to add to the next to the left
etc. )
8 4 2 1
1 1 1 1 1 1 1 0 0 1
That’s it, Crazy, but that's how it goes: in most computer systems, -7 would have the form something of the form
1 1 1 1 1 1 1 0 0 1
Just to get that clear, especially the add in base 2 bit, the same again for binary 6, and binary (2’s compliment) -6.
First the positive number, 6
8 4 2 1
0 0 0 0 0 0 0 1 1 0
Now, for -6 …..
First a flip of the "normal" binary for 6
8 4 2 1
1 1 1 1 1 1 1 0 0 1
, next, the final step, is to add the 1, in binary maths, which is base 2. So as it is base 2, you wont get a 2 furthest right. You get a 0 and then have to carry the 1 over to the next left****, so you get finally for -6
8 4 2 1
1 1 1 1 1 1 1 0 1 0
( **** A nice Laymen way of thinking about adding a 1 in binary, is to start from the right and try to find an " empty" place ( i.e., a 0 ), to dump the 1 in . )
If the positive number was 4, then to get -4, after the flip, you would have had to carry over the added 1 twice and so finally for -4 you would have
8 4 2 1
1 1 1 1 1 1 1 1 0 0
Compare that with positive 4 and you can see its easy to get confused
8 4 2 1
0 0 0 0 0 0 0 1 0 0
So, what went wrong?
So we know now what the 2’s codswallop is all about, … how does that explain the failings of the last post
The second function is sound. – Just to review that: The basic idea, as Hans said (https://eileenslounge.com/viewtopic.php?p=322157#p322157), is that in a VBA If … And … Then with two numbers either side of the And , the first thing to do is convert the two numbers to binary, and then, do a bitwise And
, - just for convenience show them in the same vertical plane…..
Example:
6 And 5
8 4 2 1
0 0 0 0 0 0 0 1 1 0 ---- 6
0 0 0 0 0 0 0 1 0 1 ---- 5
The "result" of that, according to the bitwise comparison, is
8 4 2 1
0 0 0 0 0 0 0 1 0 0
Any amount of 1s and you get a True, so 5 And 6 is True. ( The actual result of 5 And 6 is what that last binary number is in decimal which is 4, but anything other than 0 is True (https://eileenslounge.com/viewtopic.php?p=322175#p322175))
Do the same for 4And 2 and the result is got from this
8 4 2 1
0 0 0 0 0 0 0 0 1 0 ---- 2
0 0 0 0 0 0 0 1 0 0 ---- 4
, which finally is
8 4 2 1
0 0 0 0 0 0 0 0 0 0
That is 0 in binary or decimal
https://i.postimg.cc/hvzXKctd/5-And-6-4-And-2.jpg 6121
https://i.postimg.cc/hvzXKctd/5-And-6-4-And-2.jpg (https://postimages.org/)
So far so good.
can take the second small function, Function NumbersInVBAIf_And_Then(ByVal Dec1 As Long, Dec2 As Long) As Boolean , as OK
Perhaps better said, the final function, Function NumbersInVBAIf_And_Then(ByVal Dec1 As Long, ByVal Dec2 As Long) As Boolean , is also OK. With the right numbers
There is not much there for it to do wrong: It does a simple job of detecting any position where both decimal numbers have a 1. Simple and correct.
So what is the damm problem?? I think we know. The original simple Decimal to Binary function got the correct binary number for positive numbers, but usually wrong numbers for the negative as it was not based on the Two's complement codswollop for negative numbers
So we just need a new function to convert decimals correctly, in the case of negative numbers, in the Two's complement styleo
Two’s Compliment Function
There is nothing clever or difficult required. We just need to apply the logic carefully.
I done a coding quite quick, it won’t be the best, but it will do. 2 main sections, Rem 1, for positive given decimal numbers, Rem 2 for any negative given decimal numbers
Rem 1 - in the coding
Positive decimal numbers can be handled as in the main part of the previous simple decimal to binary coding, Function NumberInBinary(ByVal DecNumber As Long) As String
Public Function NumberInBinary2sCompliment(ByVal DecNumber As Long) As String
If Not DecNumber < 0 Then
Rem 1 Positive decimal number
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "0" ' The first digit ( or last 32th if you prefer ) is included, 0 is for a positive number
' Here we go again with the classic school maths way of converting a decimal number to binary
Dim N As Long ' N is effectively the power of two at any time
For N = 30 To 0 Step -1 ' We can think of this as looping from left to right, down the power of 2 values. 30 seems to be the limit before something is too big
If DecNumber / (2 ^ N) >= 1 Then ' We need a 1 in the position, for this power of 2
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "1" ' putting effectively a 1 in the position, for this power of 2
Let DecNumber = DecNumber - (2 ^ N) ' We have effectively accounted for an amount equal to this power of 2, so the decimal number we will further investigate must effectively be reduced
Else ' We cant effectively eat up am amount from the decimal of this value of power 2 as the decimal total is smaller, so the binary string needs a 0 at this position
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "0"
End If
Next N ' We effectively go to the next power of 2 down
Exit Function ' We are finished here for a positive decimal number
Else ' The case of a negative decimal number
For the positive number we just divide the decimal number by decreasing powers of 2.
__ If that gives >= 1 then we add a 1 to the binary number string, effectively then that is at a position for that power of 2. The decimal number is then reduced accordingly by that power of 2 amount.
__ If that division gave a number less than 1 then a 0 is added to the binary number string
Then we repeat this for the next power of two down, and so on.
For this, our new coding, for this case of a positive number, the function would finally end , Exit Function when all powers of two had been considered. This section is mostly a copy of the simple decimal to binary function, as in my Function NumberInBinary(ByVal DecNumber As Long) As String (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24918&viewfull=1#post24918)
For the Case of a negative decimal number, its just a case of carefully following the exactly the process of 2's compliment in some way
The following coding description is the first way I came up with, so I doubt it’s the most efficient It will do for now
I will do that in the next post as its specifically for getting the 2’s compliment and it may be good to have a separate post to reference later
…. Continued in the next post
DocAElstein
11-16-2024, 03:17 PM
2’s Compliment Function Decimal To Binary conversion, section for negative Decimal numbers
'== Rem 2 == 2's complement Negative Binary number from decimal ==========================
The coding is not written particularly efficient. It’s written in a way to help understand more clearly what is going on for learning purposes and better later revision
'2a) I see no fundamental reason not to work on the negative decimal number, but for clarity I make the decimal number to its absolute (positive) value here. (A sign change would do just as well here)
'2b) This section is once again possibly an inefficient thing to do, but for clarity, I find the power of 2 number ( value of N ) at which (2 ^ N) is equal or bigger than the (now considered as positive) decimal number. In effect we know the position where in simple normal binary the first 1 would go looking left to right, in other words we effectively have this value, ( at the (2 ^ 6) ) , when considering normal binary values
9 8 7 6 5 4 3 2 1 0 ---- N from (2 ^ N)
0 0 0 1 1 0 1 1 0 0 ---- Normal binary number
For the above example, I am saying we are at the left first digit of a final binary number that , as example, would look in normal binary, if written as one might manually in maths class at school, as this
1 1 0 1 1 0 0
'2c) This section is just the classic school maths, as we did before a few times, of converting a decimal to a binary, just back to front with a 0 put where you would have put a 1 and visa versa. This is because, considering the last example again, we want to have the "flip" of that, so we actually want
0 0 1 0 0 1 1
'2c)(i) Using the above example again, I am at the start of constructing the string variable to be returned by the function, NumberInBinary2sCompliment, or rather , at the first significant part, effectively what would be the first 1 in normal binary. But, in actual fact, I want the "flip" of it. Rather than construct it and then flip it, which would be talking inefficiency a bit far, I construct it on the flip side as it where. So I add my first character to the string. It will be the flip of 1, so it will be 0
'2c)(ii)The first binary digit was known so added above, as was the reduction of the decimal value by the (2 ^ N) value. So now we continue the looping for the rest
I am using a Do While Loop for no particular reason, rather than a For Next Loop, - its just slightly simpler than having to have a variable, such as NN for the next N to use in a line like For N = NN To 0 Step -1 . But basically I do now the classic progression in school maths that we did a few times already, just back to front(flipped), i.e., with a 0 put where you would put a 1 and visa versa
So at the end of this section I have my final flipped binary number for the decimal value. In other words I have the exact flip of the normal binary for the decimal number.
'2d) I have the flip, so I now want to add a 1 in binary
I loop, effectively going from right to left along the binary number. Because of the way I add a 1 in binary, I effectively am looking for the next " empty" , that is to say 0 , in which to "dump" this 1. If however, I find a 1, I must change that 1 to a 0, and try again at the next left position. I am finished in this For Next loop as soon as I have "got rid" of the 1
At this point I sort of, have my final 2s Compliment binary number. But generally, a binary in computer workings has a fixed length , so that a normal number would then have a lot of 0s added to the left, or as many as needed to get the length, probably 32 I would guess. In this negative value 2s compliment, the basic idea is the same, except that 1s are added to the left.
'2e) This effectively adds 1s to the left to get the full digit size of a typical computer number ( remember the way I chose to do this , means that sections '2b) and '2c) may get me a small number of digits for a small decimal number, something like 1 1 0 1 1 0 0 , rather than a more typical in computing thing where unused digits are at 0, (for positive binary numbers ), like 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0
So, three simple lines:
_ I make a variable of the length finally wanted. (The characters I use is irrelevant!!°)
_ The RSet statement puts my current 2s compliment binary number at the right of the made string, ( and the rest of the characters become spaces, - !!° hence the characters I used to make the string was irrelevant )
_ The spaces are changed to 1s
That’s it!, or rather this is it below – the full working function Function NumberInBinary2sCompliment(ByVal DecNumber As Long) As String
The over next post (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24923&viewfull=1#post24923) details a quick test of the function
' https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24922&viewfull=1#post24922
Public Function NumberInBinary2sCompliment(ByVal DecNumber As Long) As String
If Not DecNumber < 0 Then
Rem 1 Positive decimal number
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "0" ' The first digit ( or last 32th if you prefer ) is included, 0 is for a positive number
' Here we go again with the classic school maths way of converting a decimal number to binary
Dim N As Long ' N is effectively the power of two at any time
For N = 30 To 0 Step -1 ' We can think of this as looping from left to right, down the power of 2 values. 30 seems to be the limit before something is too big
If DecNumber / (2 ^ N) >= 1 Then ' We need a 1 in the position, for this power of 2
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "1" ' putting effectively a 1 in the position, for this power of 2
Let DecNumber = DecNumber - (2 ^ N) ' We have effectively accounted for an amount equal to this power of 2, so the decimal number we will further investigate must effectively be reduced
Else ' We cant effectively eat up am amount from the decimal of this value of power 2 as the decimal total is smaller, so the binary string needs a 0 at this position
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "0"
End If
Next N ' We effectively go to the next power of 2 down
Exit Function ' We are finished here for a positive decimal number
Else ' The case of a negative decimal number
'== Rem 2 == 2's 2's complement Negative Binary number from decimal ===============================
'2a)
Let DecNumber = Abs(DecNumber) ' We know we are negative, that will be taken care of automatically later as a result of making all unused digits 1. I could probably fiddle the maths below to work on negative numbers, but just for lazy comvenmience I will make the decimal number positive here
'2b) This bit brings me
Let N = 30 ' Back to the start left of our powers of 2
Dim Frac As Double: Let Frac = DecNumber / (2 ^ N)
Do While Frac < 1 ' We want to get to the number of digits needed for the number when in normal binary representation. Mostly lazy convenience I think so as to see a nice smaller amount of 0s and 1s when testing/ debugging
Let N = N - 1
Let Frac = DecNumber / (2 ^ N)
Loop ' While Frac < 1 ' I am effectibely working from left to right along the power to 2 range,
'2c) The classic school maths of converting a decimal to a binary, just back to front (fliped) with a 0 put where you would put a 1 and visa versa
'2c)(i) In normal binary I know I want my first 1,
Let NumberInBinary2sCompliment = "0" ' so we have as many digits as we need and we know the first digit would be 1 in binary , but in 2sCompliment it will be "0"
Let DecNumber = DecNumber - (2 ^ N) ' this and the last line are effectively the first use of the If section in the school maths way of converting a decimal to a binary
'2c)(ii)
Do While N <> 0
Let N = N - 1
If DecNumber / (2 ^ N) >= 1 Then ' The next 3 code lines are the classic progression in school maths, just back to front(flipped) with a 0 put where you would put a 1 and visa versa
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "0"
Let DecNumber = DecNumber - (2 ^ N)
Else
Let NumberInBinary2sCompliment = NumberInBinary2sCompliment & "1"
End If
Loop ' While N <> 0
'2d) add 1 in binary maths
Dim ToAdd As Long: Let ToAdd = 1 ' I have 1 and I need to get rid of it. (##I don't need the variable, I could use just a 1 in place of it) I work from the right of the binary number and effectively dump it on the first position with a 0 If the positon is 1 already, I must changer that to 0 , - a bit like reaching 10 in normal maths, where you leave aa 0 then carry the 1 over to the next column/digit on the left, then try again to get rid of the 1
For N = Len(NumberInBinary2sCompliment) To 1 Step -1 ' Effectively going from right to left along the binary number
If Mid(NumberInBinary2sCompliment, N, 1) = 0 Then ' I can dump my 1 here then i am finished with this section
Mid(NumberInBinary2sCompliment, N, 1) = ToAdd ' ##I don't need the variable, I could use just a 1 in place of it
Let ToAdd = 0 ' I don't need this as I am finished here.
Exit For ' As soon as we got rid of the 1 to add, we are finished
Else ' I must have come acros a 1
Mid(NumberInBinary2sCompliment, N, 1) = 0 ' I hit a 1, so 1+1 in binary is like reaching 10 in normal maths, where you leave aa 0 then carry the 1 over to the next column/digit on the left, then try again to get rid of the 1
End If
Next N ' Go to next character to the left to see if it is 0 so that I can get rid of the 1 ToAdd
'2e) ' my final binary number could be short or long at this point depending on the size of the original decimal number. This ssection
Dim BiffaBin As String: Let BiffaBin = String$(32, " ") ' Make a string of the length I want, (The characters I use is irrelevant!!)
RSet BiffaBin = NumberInBinary2sCompliment ' The RSet statement puts my current 2s compliment binary number at the right of the made string, ( and the rest of the characters become spaces, hence the characters I used to make the string was irrelevant!! )
Let NumberInBinary2sCompliment = Replace(BiffaBin, " ", "1", 1, -1, vbBinaryCompare) '
End If
End Function
DocAElstein
11-17-2024, 06:57 PM
Original post #15, Forum post24923 It slipped down to post #16 after I made a copy, which is the post above
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24923&viewfull=1#post24923
Here is a full set of codings to conclude the last few posts up to post #14 (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24922&viewfull=1#post24922) and to test the final function from then, Function NumberInBinary2sCompliment(ByVal DecNumber As Long) As String
You need that function and these codings below.
Then run Sub TryMyFuncsNumberInBinary2sComplimentNumbersInVBAIf _And_Then() ( All codings are also in the uploaded file, GetHwndClassNameCaptionHwnd.xls in the second worksheet code module
Sub TryMyFuncsNumberInBinary2sComplimentNumbersInVBAIf _And_Then()
Range("F2:F20").Clear
Dim Rw As Long, arrRws() As Variant: Let arrRws() = Range("A1:C20").Value
For Rw = 2 To 20
Let Range("F" & Rw) = NumbersInVBAIf_And_Then(arrRws(Rw, 2), arrRws(Rw, 3))
Next Rw
End Sub
Public Function NumbersInVBAIf_And_Then(ByVal Dec1 As Long, ByVal Dec2 As Long) As Boolean
Rem 1 the two decimal numbers to a string in the form of the computer binary 0s and 1s representation
Dim Bin1 As String, Bin2 As String ' String representation helps prevent loosing leading 0's
Let Bin1 = NumberInBinary2sCompliment(Dec1): Bin2 = NumberInBinary2sCompliment(Dec2)
Rem 2 starting from the left compare the characters in the corresponding position in the two strings. As soon as you get a 1 in both , you make the functions returned output as True and exit the function, otherwise the function returns false if you never get a pair of 1s
Dim TPwr As Long
For TPwr = 1 To 32 Step 1
If Mid(Bin1, TPwr, 1) = 1 And Mid(Bin2, TPwr, 1) = 1 Then Let NumbersInVBAIf_And_Then = True: Exit Function
Next TPwr
End Function
The results in column F are in agreement with those in column D, (Column D results that mirror the behaviour seen of the VBA If __ And __ Then for those number examples.
https://i.postimg.cc/mZNxBPpJ/Correct-results-using-Function-Number-In-Binary2s-Compliment.jpg 6123
https://i.postimg.cc/mZNxBPpJ/Correct-results-using-Function-Number-In-Binary2s-Compliment.jpg (https://postimages.org/)
DocAElstein
11-17-2024, 06:57 PM
This was copied from the original post #15, and it became a new post #15, and in doing so shifted the original post #15 down, which is now Post #16
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24925&viewfull=1#post24925
A Monday morning refresh of my explanations in the light of some learning in this thread (https://eileenslounge.com/viewtopic.php?f=30&t=41610)
Back to the main coding from the top of this page (https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24916&viewfull=1#post24916)
The coding seems to do what a Layman might regard as getting some identity information about things you got running on your desktop, narrowed down to what you experience/ see, and not necessarily everything going on.
Start at Rem2 , the meaty stuff,
'2a) This somehow gets me "on the desktop", ( - where I prefer to be, (it’s the lesser of the Evils, compared to a zombie with a Smartphone) ). I am at some sort upper level, I am not sure what I am allowed to call it. I think I am going on to look at things that are some how on , attached, belong to this level, or could be thought as the level below it. Children of the desktop perhaps, for want of a more politically correct wording
'2b) I am looping things, things which I as a Layman, I think are the things I see going on, on my desktop. I use the typical VBA Do While __ Loop, looping way, where the loop keeps going while some condition is met. Often that condition is that another one is found of something. In this case its windows of the sort I am looking for
'2b)(i) As is typical with this use of a VBA Do While __ Loop, just before we go into the loop, an attempt is made to find the first one. So a code line is done which typically will be similar to the last one in the loop, as the loop at the start is told to keep going While. Specifically I find the window at the top of the z order, which can be thought of as the one active, or the one I am most looking at. The z order should perhaps be though of as a sort of lateral / horizontal set of things, rather than the main vertical levels in an explorer type view. It’s a bit of a personal conception sometimes perhaps
'2b)(ii) I am looping as long as I find a handle
Often things without a caption seem to be repeats, not all, but in any case it seems that things without a caption are not useful to know about. Or in any case the code author seems to think so. It narrows down quite a bit how many things we find, so
If Len(strCaption) > 0 Then
gets rid of those, or rather arranges that we hop over them without giving information out about them.
We go then into a couple of lines that further narrows down substantially which of the found things we give output about. It considers its "Style”. Why the word style is used as a way of saying "type of” or similar perhaps has some meaning to someone privy to deeper knowledge? For us as Laymen it seems to allow us to pick out a style which narrows things down to what we experience as being there or running
In particular how the code line If lngStyle And mcWS_VISIBLE Then actually works is the main point of the discussion around here: https://eileenslounge.com/viewtopic.php?p=322270#p322270 ,so I won’t repeat all that, - it is close to getting well understood and explained, I think, thanks to someone smart setting me straight
The next few lines output the Window identification info, exactly what that is , is still getting a bit more clarity from about here
The last line of the loop, in the loop, is the one similar to the one just before the loop. It gets us the next child thing, so just slightly different to the one just before the loop: we get the handle of the window next in the z order, if there is one.
Here is today’s fresh version of the coding to get window info, as explained above. (The top API function Declaration section has not changed, so I miss that out for clarity):
Public Sub fEnumWindowsPost15Post() ' https://eileenslounge.com/viewtopic.php?p=322275#p322275
Rem 1 ' Some headings for worksheet output, and for me to remeber when/ what computer I was on, not important for understanding the main coding
Dim Ws As Worksheet: Set Ws = ThisWorkbook.Worksheets.Item(1)
Dim Lc As Long, Lr As Long: Let Lc = Ws.Cells.Item(2, Ws.Columns.Count).End(xlToLeft).Column
Let Ws.Cells.Item(1, Lc + 1) = CreateObject("WScript.Network").ComputerName & " " & Format(Now(), "ddd,dd,mmm,yyyy") ' Environ$("computername") Nigel Heffernan https://stackoverflow.com/questions/3551055/how-to-get-name-of-the-computer-in-vba/10108951#10108951
Let Ws.Cells.Item(2, Lc + 1) = "Hwnd": Let Ws.Cells.Item(2, Lc + 2) = "Class Name": Let Ws.Cells.Item(2, Lc + 3) = "Caption": Let Ws.Cells.Item(2, Lc + 4) = "Hwnd( Caption)" ' : Let Ws.Cells.Item(2, Lc + 5) = "enum visible?"
Rem 2 ' The next is all mostly from Dev Ashish http://access.mvps.org/access/api/api0013.htm
Dim lngx As Long, lngLen As Long, lngStyle As Long, strCaption As String
'2a) This somehow gets me to my start point, whatever I am allowed to call it
Let lngx = apiGetDesktopWindow(): Debug.Print "Geted Desktop Window " & lngx & " " & " CLass name " & fGetClassName(lngx)
'2b) Loop to get info from windows at some sort of "top, main, visible or some such"
'2b)(i)
Let lngx = apiGetWindow(lngx, mcGWCHILD): Debug.Print " First child to Desktop " & lngx & " CLass name " & fGetClassName(lngx) ' GW_CHILD = 5 The topmost of the given window's child windows. This has the same effect as using the GetTopWindow function, ... usually at the top of all the other children in the Z-order
'2b)(ii)
Do While Not lngx = 0 ' We are looping "equal level children", seperated not realy, just look seperate to us because of the seen to us z order
Let strCaption = fGetCaption(lngx)
If Len(strCaption) > 0 Then ' Those without a caption seem not important
Let lngStyle = apiGetWindowLong(lngx, mcGWLSTYLE) ' apiGetWindowLong gets info, GWL_STYLE -16 retrieves the window styles
If lngStyle And mcWSVISIBLE Then ' ' For enum visible windows only - see here for full discusions of what this is about https://eileenslounge.com/viewtopic.php?p=322270#p322270
Let Lr = Ws.Cells.Item(Ws.Rows.Count, Lc + 1).End(xlUp).Row ' Handle Class name Caption
' If lngStyle And mcWSVISIBLE Then
' Let Ws.Cells.Item(Lr + 1, Lc + 5) = "enum visible got from " & lngStyle & " And " & mcWSVISIBLE
' Else
' '
' End If
Debug.Print FindWndNumber(lpClassName:=fGetClassName(lngx), lpWindowName:=vbNullString), fGetClassName(lngx); Tab(50); fGetCaption(lngx); Tab(100); FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
Let Ws.Cells.Item(Lr + 1, Lc + 1) = FindWndNumber(lpClassName:=fGetClassName(lngx), lpWindowName:=vbNullString)
Let Ws.Cells.Item(Lr + 1, Lc + 2) = fGetClassName(lngx)
Let Ws.Cells.Item(Lr + 1, Lc + 3) = fGetCaption(lngx)
Let Ws.Cells.Item(Lr + 1, Lc + 4) = FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
End If
End If
Let lngx = apiGetWindow(lngx, mcGWHWNDNEXT) ' GW_HWNDNEXT = 2 The window below the given window in the Z-order.
Loop ' While Not lngx = 0 ' I am going through all the child windows of the desktop windows
End Sub
Private Function fGetCaption(Hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(Number:=255 - 1, Character:="0") ' "00000000000000000000000000000000..........000"
Let intCount = apiGetWindowText(Hwnd:=Hwnd, lpString:=strBuffer, aint:=255) ' This makes strBuffer something like *MSCTFIME UI 0000000000000000............000"
If intCount > 0 Then Let fGetCaption = Left$(strBuffer, intCount)
End Function
Private Function fGetClassName(Hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(255 - 1, 0)
Let intCount = apiGetClassName(Hwnd, strBuffer, mconMAXLEN)
If intCount > 0 Then
Let fGetClassName = Left$(strBuffer, intCount)
End If
End Function
DocAElstein
11-17-2024, 10:09 PM
' Some further experiments
later
DocAElstein
11-20-2024, 08:17 PM
The main new or changed features of this version are a few more explaining comments, and in the first column, the hwnd number is additionally given in Hexagonorrhoea and (2' compliment) binary. For the normal column width these extra numbers are not visible, but they are there for reference because:
_ Spy's typically have Hexagonorrhoea so it is convenient for comparisons
_ I want to jeep my eye on the binary to see if there are any typical values / patterns
' Original main Code Courtesy of Dev Ashish http://access.mvps.org/access/api/api0013.htm
' (and Hans, https://eileenslounge.com/viewtopic.php?p=321978#p321978)
Private Declare Function apiGetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long ' lpClassName - Points to the buffer that is to receive the class name string.
Private Declare Function apiGetDesktopWindow Lib "user32" Alias "GetDesktopWindow" () As Long ' The desktop window is the area on top of which all icons and other windows are painted.
Private Declare Function apiGetWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wCmd As Long) As Long ' retrieves the handle of a window that has the specified relationship (Z order or owner) to the specified window. ' uCmd Specifies the relationship GW_CHILD The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
Private Declare Function apiGetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long ' information about the specified window. - retrieves the 32-bit (long) value at the specified offset into the extra window memory of a window. nIndex - Valid values are in the range zero through the number of bytes of extra window memory, minus four
Private Declare Function apiGetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal aint As Long) As Long ' copies the text of the specified window’s title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied.
Private Declare Function FindWndNumber Lib "user32" Alias "FindWindowA" (Optional ByVal lpClassName As String, Optional ByVal lpWindowName As String) As Long ' retrieves the handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows. lpWindowName- the window name (the window’s title), if parameter is NULL, all window names match. http://allapi.mentalis.org/apilist/FindWindow.shtml
Private Declare Function IsWindowVisible Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Const mcGWCHILD = 5
Private Const mcGWHWNDNEXT = 2 ' GW_HWNDNEXT - The retrieved handle identifies the window below the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window below the specified window. If the specified window is a top-level window, the handle identifies the top-level window below the specified window. If the specified window is a child window, the handle identifies the sibling window below the specified window.
Private Const mcGWLSTYLE = (-16)
Private Const mcWSVISIBLE = &H10000000 ' Watch window gives 268435456 (even when no code is running)
Private Const mconMAXLEN = 255
Public Sub fEnumWindowsPost15Post() ' https://eileenslounge.com/viewtopic.php?p=322275#p322275
Rem 1 ' Some headings for worksheet output, and for me to remeber when/ what computer I was on, not important for understanding the main coding
Dim Ws As Worksheet: Set Ws = ThisWorkbook.Worksheets.Item(1)
Dim Lc As Long, Lr As Long: Let Lc = Ws.Cells.Item(2, Ws.Columns.Count).End(xlToLeft).Column
Let Ws.Cells.Item(1, Lc + 1) = CreateObject("WScript.Network").ComputerName & " " & Format(Now(), "ddd,dd,mmm,yyyy") ' Environ$("computername") Nigel Heffernan https://stackoverflow.com/questions/3551055/how-to-get-name-of-the-computer-in-vba/10108951#10108951
Let Ws.Cells.Item(2, Lc + 1) = "Hwnd": Let Ws.Cells.Item(2, Lc + 2) = "Class Name": Let Ws.Cells.Item(2, Lc + 3) = "Caption": Let Ws.Cells.Item(2, Lc + 4) = "Hwnd(from Caption)" ' : Let Ws.Cells.Item(2, Lc + 5) = "enum visible?"
Rem 2 ' The next was originally from Dev Ashish http://access.mvps.org/access/api/api0013.htm
Dim lngx As Long, lngLen As Long, lngStyle As Long, strCaption As String
'2a) This somehow gets me to my start point, whatever I am allowed to call it
Let lngx = apiGetDesktopWindow(): Debug.Print "Geted Desktop Window " & lngx & " " & " CLass name " & fGetClassName(lngx)
'2b) Loop to get info from windows at some sort of "top, main, visible or some such"
'2b)(i)
Let lngx = apiGetWindow(lngx, mcGWCHILD): Debug.Print " First child to Desktop " & lngx & " CLass name " & fGetClassName(lngx) ' GW_CHILD = 5 The topmost of the given window's child windows. This has the same effect as using the GetTopWindow function, ... usually at the top of all the other children in the Z-order
'2b)(ii)
Do While Not lngx = 0 ' We are looping "equal level children", seperated not realy, just look seperate to us because of the seen to us z order
Let strCaption = fGetCaption(lngx)
If Len(strCaption) > 0 Then ' Those without a caption seem not important
Let lngStyle = apiGetWindowLong(lngx, mcGWLSTYLE) ' apiGetWindowLong gets info, GWL_STYLE -16 retrieves the window styles
If lngStyle And mcWSVISIBLE Then ' ' For enum visible windows only - see here for full discusions of what this is about https://eileenslounge.com/viewtopic.php?p=322270#p322270
' If IsWindowVisible(lngx) Then ' alternative https://www.eileenslounge.com/viewtopic.php?p=322379#p322379
Let Lr = Ws.Cells.Item(Ws.Rows.Count, Lc + 1).End(xlUp).Row
Debug.Print FindWndNumber(lpClassName:=fGetClassName(lngx), lpWindowName:=vbNullString), fGetClassName(lngx); Tab(50); fGetCaption(lngx); Tab(100); FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
Dim strHandle As String: Let strHandle = FindWndNumber(lpClassName:=fGetClassName(lngx), lpWindowName:=vbNullString) ' This is not really necerssary, other thsn perhaps useful for later debuggung
'Let Ws.Cells.Item(Lr + 1, Lc + 1) = strHandle & " " & Application.Evaluate("=DEC2HEX(" & strHandle & ")") & " " & NumberInBinary2sCompliment(strHandle)
Let Ws.Cells.Item(Lr + 1, Lc + 1) = strHandle & " " & Hex(strHandle) & " " & NumberInBinary2sCompliment(strHandle)
Let Ws.Cells.Item(Lr + 1, Lc + 2) = fGetClassName(lngx)
Let Ws.Cells.Item(Lr + 1, Lc + 3) = fGetCaption(lngx)
Let Ws.Cells.Item(Lr + 1, Lc + 4) = FindWndNumber(lpClassName:=vbNullString, lpWindowName:=fGetCaption(lngx))
End If
End If
Let lngx = apiGetWindow(lngx, mcGWHWNDNEXT) ' GW_HWNDNEXT = 2 The window below the given window in the Z-order...... in oother words, the handle returned identifies the sibling window below the specified window.
Loop ' While Not lngx = 0 ' I am going through all the child windows of the desktop windows
End Sub
Private Function fGetCaption(hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(Number:=255 - 1, Character:="0") ' "00000000000000000000000000000000..........000"
Let intCount = apiGetWindowText(hwnd:=hwnd, lpString:=strBuffer, aint:=255) ' This makes strBuffer something like *MSCTFIME UI 0000000000000000............000"
If intCount > 0 Then Let fGetCaption = Left$(strBuffer, intCount)
End Function
Private Function fGetClassName(hwnd As Long) As String
Dim strBuffer As String, intCount As Integer
Let strBuffer = String$(255 - 1, 0)
Let intCount = apiGetClassName(hwnd, strBuffer, mconMAXLEN)
If intCount > 0 Then
Let fGetClassName = Left$(strBuffer, intCount)
End If
End Function
DocAElstein
12-03-2024, 04:50 PM
later
www.sagotogo.co
www.sagotogo.co
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA (https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdPM65i9 PG (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdPM65i9 PG)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdPQHFk_ zm (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdPQHFk_ zm)
http://www.eileenslounge.com/viewtopic.php?p=324457#p324457 (http://www.eileenslounge.com/viewtopic.php?p=324457#p324457)
http://www.eileenslounge.com/viewtopic.php?p=324064#p324064 (http://www.eileenslounge.com/viewtopic.php?p=324064#p324064)
http://www.eileenslounge.com/viewtopic.php?p=323960#p323960 (http://www.eileenslounge.com/viewtopic.php?p=323960#p323960)
https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg (https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg)
https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg.ADd4m2zp_xDADd6Nnotj 1C (https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg.ADd4m2zp_xDADd6Nnotj 1C)
s://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgySdtXqcaA27wQLd1t4AaABAg (s://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgySdtXqcaA27wQLd1t4AaABAg)
http://www.eileenslounge.com/viewtopic.php?p=323959#p323959 (http://www.eileenslounge.com/viewtopic.php?p=323959#p323959)
http://www.eileenslounge.com/viewtopic.php?f=30&t=41784 (http://www.eileenslounge.com/viewtopic.php?f=30&t=41784)
http://www.eileenslounge.com/viewtopic.php?p=323966#p323966 (http://www.eileenslounge.com/viewtopic.php?p=323966#p323966)
http://www.eileenslounge.com/viewtopic.php?p=323959#p323959 (http://www.eileenslounge.com/viewtopic.php?p=323959#p323959)
http://www.eileenslounge.com/viewtopic.php?p=323960#p323960 (http://www.eileenslounge.com/viewtopic.php?p=323960#p323960)
http://www.eileenslounge.com/viewtopic.php?p=323894#p323894 (http://www.eileenslounge.com/viewtopic.php?p=323894#p323894)
http://www.eileenslounge.com/viewtopic.php?p=323843#p323843 (http://www.eileenslounge.com/viewtopic.php?p=323843#p323843)
https://www.youtube.com/watch?v=fEHKPhJxgBA&lc=Ugxx8_MjhC9FDaQgcHN4AaABAg (https://www.youtube.com/watch?v=fEHKPhJxgBA&lc=Ugxx8_MjhC9FDaQgcHN4AaABAg)
https://www.youtube.com/watch?v=jpjYm4UvyWk&lc=Ugx_Qd4rfAN_ZYcJbo94AaABAg.ACGbG9c76OWACGbjKa7H 8k (https://www.youtube.com/watch?v=jpjYm4UvyWk&lc=Ugx_Qd4rfAN_ZYcJbo94AaABAg.ACGbG9c76OWACGbjKa7H 8k)
https://www.youtube.com/watch?v=jpjYm4UvyWk&lc=Ugx_Qd4rfAN_ZYcJbo94AaABAg (https://www.youtube.com/watch?v=jpjYm4UvyWk&lc=Ugx_Qd4rfAN_ZYcJbo94AaABAg)
https://www.youtube.com/watch?v=GyPHaydeng0&lc=UgzE4a4f_e_y9Rk5OR94AaABAg (https://www.youtube.com/watch?v=GyPHaydeng0&lc=UgzE4a4f_e_y9Rk5OR94AaABAg)
https://www.youtube.com/watch?v=I5FkNG94BcQ&lc=UgxXnkEHqulXSR5tXwh4AaABAg (https://www.youtube.com/watch?v=I5FkNG94BcQ&lc=UgxXnkEHqulXSR5tXwh4AaABAg)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa6BSa17 3Z (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa6BSa17 3Z)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa6-64Xpgl (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa6-64Xpgl)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa5ms39y jd (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa5ms39y jd)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa5ZXJwR CM (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa5ZXJwR CM)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa4Pr15N Ut (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa4Pr15N Ut)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa4I83Je lY (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGABa4I83Je lY)
https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdMo2n-hyF (https://www.youtube.com/watch?v=3t8Mk4URi6g&lc=UgzoakhRXOsCaoRm_Nd4AaABAg.8xzeMdC8IOGADdMo2n-hyF)
https://www.youtube.com/watch?v=C43btudYyzA&lc=Ugyf349Ue6_4umFfNUB4AaABAg.8mjgPNoTt_HABa3tnAjh ZU (https://www.youtube.com/watch?v=C43btudYyzA&lc=Ugyf349Ue6_4umFfNUB4AaABAg.8mjgPNoTt_HABa3tnAjh ZU)
http://www.eileenslounge.com/viewtopic.php?p=323547#p323547 (http://www.eileenslounge.com/viewtopic.php?p=323547#p323547)
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA (https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA)
DocAElstein
12-13-2024, 02:49 PM
Later
DocAElstein
12-13-2024, 02:50 PM
Page 3
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page3
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API?p=24934&viewfull=1#post24934
https://www.excelfox.com/forum/showthread.php/2989-Rough-Notes-and-posts-to-be-referenced-from-elsewhere-on-VBA-Windows-API/page3#post24934
post24934, Thread2989
Some notes related loosely to these forum posts
https://eileenslounge.com/viewtopic.php?p=322955#p322955 https://eileenslounge.com/viewtopic.php?p=323065#p323065
https://eileenslounge.com/viewtopic.php?f=30&t=41659
TestAccount
12-15-2024, 07:13 PM
Testing
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA (https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA)
http://www.eileenslounge.com/viewtopic.php?p=324457#p324457 (http://www.eileenslounge.com/viewtopic.php?p=324457#p324457)
http://www.eileenslounge.com/viewtopic.php?p=324064#p324064 (http://www.eileenslounge.com/viewtopic.php?p=324064#p324064)
http://www.eileenslounge.com/viewtopic.php?p=323960#p323960 (http://www.eileenslounge.com/viewtopic.php?p=323960#p323960)
https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg (https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg)
https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg.ADd4m2zp_xDADd6Nnotj 1C (https://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgyZCnNfnZRfgwzDlQF4AaABAg.ADd4m2zp_xDADd6Nnotj 1C)
s://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgySdtXqcaA27wQLd1t4AaABAg (s://www.youtube.com/watch?v=7VwD9KuyMk4&lc=UgySdtXqcaA27wQLd1t4AaABAg)
http://www.eileenslounge.com/viewtopic.php?p=323959#p323959 (http://www.eileenslounge.com/viewtopic.php?p=323959#p323959)
http://www.eileenslounge.com/viewtopic.php?f=30&t=41784 (http://www.eileenslounge.com/viewtopic.php?f=30&t=41784)
http://www.eileenslounge.com/viewtopic.php?p=323966#p323966 (http://www.eileenslounge.com/viewtopic.php?p=323966#p323966)
http://www.eileenslounge.com/viewtopic.php?p=323959#p323959 (http://www.eileenslounge.com/viewtopic.php?p=323959#p323959)
http://www.eileenslounge.com/viewtopic.php?p=323960#p323960 (http://www.eileenslounge.com/viewtopic.php?p=323960#p323960)
http://www.eileenslounge.com/viewtopic.php?p=323894#p323894 (http://www.eileenslounge.com/viewtopic.php?p=323894#p323894)
http://www.eileenslounge.com/viewtopic.php?p=323843#p323843 (http://www.eileenslounge.com/viewtopic.php?p=323843#p323843)
http://www.eileenslounge.com/viewtopic.php?p=323547#p323547 (http://www.eileenslounge.com/viewtopic.php?p=323547#p323547)
http://www.eileenslounge.com/viewtopic.php?p=323516#p323516 (http://www.eileenslounge.com/viewtopic.php?p=323516#p323516)
http://www.eileenslounge.com/viewtopic.php?p=323517#p323517 (http://www.eileenslounge.com/viewtopic.php?p=323517#p323517)
http://www.eileenslounge.com/viewtopic.php?p=323449#p323449 (http://www.eileenslounge.com/viewtopic.php?p=323449#p323449)
http://www.eileenslounge.com/viewtopic.php?p=323226#p323226 (http://www.eileenslounge.com/viewtopic.php?p=323226#p323226)
http://www.eileenslounge.com/viewtopic.php?f=25&t=41702&p=323150#p323150 (http://www.eileenslounge.com/viewtopic.php?f=25&t=41702&p=323150#p323150)
http://www.eileenslounge.com/viewtopic.php?p=323085#p323085 (http://www.eileenslounge.com/viewtopic.php?p=323085#p323085)
http://www.eileenslounge.com/viewtopic.php?p=322955#p322955 (http://www.eileenslounge.com/viewtopic.php?p=322955#p322955)
http://www.eileenslounge.com/viewtopic.php?f=30&t=41659 (http://www.eileenslounge.com/viewtopic.php?f=30&t=41659)
http://www.eileenslounge.com/viewtopic.php?p=322462#p322462 (http://www.eileenslounge.com/viewtopic.php?p=322462#p322462)
http://www.eileenslounge.com/viewtopic.php?p=322356#p322356 (http://www.eileenslounge.com/viewtopic.php?p=322356#p322356)
http://www.eileenslounge.com/viewtopic.php?p=321984#p321984 (http://www.eileenslounge.com/viewtopic.php?p=321984#p321984)
https://eileenslounge.com/viewtopic.php?f=30&t=41610 (https://eileenslounge.com/viewtopic.php?f=30&t=41610)
https://eileenslounge.com/viewtopic.php?p=322176#p322176 (https://eileenslounge.com/viewtopic.php?p=322176#p322176)
https://eileenslounge.com/viewtopic.php?p=322238#p322238 (https://eileenslounge.com/viewtopic.php?p=322238#p322238)
https://eileenslounge.com/viewtopic.php?p=322270#p322270 (https://eileenslounge.com/viewtopic.php?p=322270#p322270)
https://eileenslounge.com/viewtopic.php?p=322300#p322300 (https://eileenslounge.com/viewtopic.php?p=322300#p322300)
http://www.eileenslounge.com/viewtopic.php?p=322150#p322150 (http://www.eileenslounge.com/viewtopic.php?p=322150#p322150)
http://www.eileenslounge.com/viewtopic.php?p=322111#p322111 (http://www.eileenslounge.com/viewtopic.php?p=322111#p322111)
http://www.eileenslounge.com/viewtopic.php?p=322086#p322086 (http://www.eileenslounge.com/viewtopic.php?p=322086#p322086)
https://stackoverflow.com/questions/33868233/shell-namespace-not-accepting-string-variable-but-accepting-string-itself/77888851#77888851 (https://stackoverflow.com/questions/33868233/shell-namespace-not-accepting-string-variable-but-accepting-string-itself/77888851#77888851)
http://www.eileenslounge.com/viewtopic.php?p=322084#p322084 (http://www.eileenslounge.com/viewtopic.php?p=322084#p322084)
http://www.eileenslounge.com/viewtopic.php?p=321822#p321822 (http://www.eileenslounge.com/viewtopic.php?p=321822#p321822)
http://www.eileenslounge.com/viewtopic.php?p=322424#p322424 (http://www.eileenslounge.com/viewtopic.php?p=322424#p322424)
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA (https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA)
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.