ExcelBanter

ExcelBanter (https://www.excelbanter.com/)
-   Excel Programming (https://www.excelbanter.com/excel-programming/)
-   -   API Class Question (https://www.excelbanter.com/excel-programming/400260-api-class-question.html)

[email protected]

API Class Question
 
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)

I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:

"Invalid use of AddressOf operator"

Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:

==================================
Option Explicit

Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long

Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long

Private Type AppWindow
sTitle As String
lHandle As Long
End Type

Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle

Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))

FindWindowByTitle = tParms.lHandle
End Function

Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String

'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)

'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If

'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function

Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================

Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.

Thanks for any light that can be shed on this.

Cory


RB Smissaert

API Class Question
 
Try this:

Instead of calling AddressOf directly call it via a function like this:

Function FARPROC(ByVal pfn As Long) As Long

FARPROC = pfn

End Function


RBS

wrote in message
ups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)

I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:

"Invalid use of AddressOf operator"

Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:

==================================
Option Explicit

Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long

Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long

Private Type AppWindow
sTitle As String
lHandle As Long
End Type

Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle

Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))

FindWindowByTitle = tParms.lHandle
End Function

Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String

'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)

'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If

'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function

Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================

Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.

Thanks for any light that can be shed on this.

Cory



RB Smissaert

API Class Question
 
I forgot to give an example:

With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With


RBS


"RB Smissaert" wrote in message
...
Try this:

Instead of calling AddressOf directly call it via a function like this:

Function FARPROC(ByVal pfn As Long) As Long

FARPROC = pfn

End Function


RBS

wrote in message
ups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)

I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:

"Invalid use of AddressOf operator"

Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:

==================================
Option Explicit

Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long

Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long

Private Type AppWindow
sTitle As String
lHandle As Long
End Type

Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle

Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))

FindWindowByTitle = tParms.lHandle
End Function

Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String

'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)

'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If

'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function

Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================

Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.

Thanks for any light that can be shed on this.

Cory




Jim Cone

API Class Question
 
Cory,
A different approach...
Word has a "Tasks" collection that represents all the tasks currently
running on the system. You can run code from Excel like this...
'--
Sub WhichOnes()
Dim objWord As Object
Dim objTasks As Object
Dim N As Long
Set objWord = CreateObject("Word.Application")
Set objTasks = objWord.Tasks
For N = 1 To objTasks.Count
Cells(N, 2).Value = objTasks(N).Name
Next 'N
Set objTasks = Nothing
objWord.Quit
Set objWord = Nothing
End Sub
--
Jim Cone
San Francisco, USA
http://www.realezsites.com/bus/primitivesoftware
(Excel Add-ins / Excel Programming)





wrote in message
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)
I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:
"Invalid use of AddressOf operator"
Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:
-snip-
Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.
Thanks for any light that can be shed on this.
Cory


[email protected]

API Class Question
 
Thank you very much for your reply. I think I understand where you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:

Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))




On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:

With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With

RBS

"RB Smissaert" wrote in message

...



Try this:


Instead of calling AddressOf directly call it via a function like this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -




RB Smissaert

API Class Question
 
I think my solution was for a different problem.
Will have to Google it up.

RBS


wrote in message
ups.com...
Thank you very much for your reply. I think I understand where you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:

Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))




On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:

With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With

RBS

"RB Smissaert" wrote in message

...



Try this:


Instead of calling AddressOf directly call it via a function like this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -





[email protected]

API Class Question
 
Thank you too for posting that code! That's actually the approach I
was using before, but I found it's not as accurate as I need it to be,
which is why I'm trying to tackle it from the API end. With the Word
mothod, I had modified it to be able to pass in a string of text and
check it against the task collection. If a match was found, then that
program is running on the computer.

However, the task names don't seem to always be same as the text found
in the title of the program's window. I've been running into a
situation where users can have three instances of a mainframe program
running, all of which have the same process name in Task Manager, but
all of which have unique numbered titles (i.e: Session1, Session2,
etc...) in the title bar. I've been trying to get that text from the
title bar so I can see very specifically which instances they have
running. It would be easy to just count how many times the process
exists and assume they're numbered 1, 2, 3 etc, but the user can have
odd numbered instances such as Session1 and Session4 running, but not
Session2 or 3. Does that make sense?

I know the Word method should work, but it simply doesn't. I can pass
it "*Session1*" and it will return True even if all I have opened is
Session3. Weird, but true.

Thanks again!

Cory

On Oct 30, 9:50 am, "Jim Cone" wrote:
Cory,
A different approach...
Word has a "Tasks" collection that represents all the tasks currently
running on the system. You can run code from Excel like this...
'--
Sub WhichOnes()
Dim objWord As Object
Dim objTasks As Object
Dim N As Long
Set objWord = CreateObject("Word.Application")
Set objTasks = objWord.Tasks
For N = 1 To objTasks.Count
Cells(N, 2).Value = objTasks(N).Name
Next 'N
Set objTasks = Nothing
objWord.Quit
Set objWord = Nothing
End Sub
--
Jim Cone
San Francisco, USAhttp://www.realezsites.com/bus/primitivesoftware
(Excel Add-ins / Excel Programming)


wrote in message
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)
I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:
"Invalid use of AddressOf operator"
Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:
-snip-
Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.
Thanks for any light that can be shed on this.
Cory




[email protected]

API Class Question
 
Thanks! I'm doing the same thing. I haven't found anything useful
yet. This would be so much easier if I wasn't limited to VBA. But,
it is how it is....

On Oct 30, 11:36 am, "RB Smissaert"
wrote:
I think my solution was for a different problem.
Will have to Google it up.

RBS

wrote in message

ups.com...



Thank you very much for your reply. I think I understand where you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:


Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))


On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:


With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With


RBS


"RB Smissaert" wrote in message


.. .


Try this:


Instead of calling AddressOf directly call it via a function like this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -




RB Smissaert

API Class Question
 
Not sure it can work in VBA, but this link addresses the problem:
http://shorterlink.com/?DM71M6

RBS

wrote in message
ups.com...
Thanks! I'm doing the same thing. I haven't found anything useful
yet. This would be so much easier if I wasn't limited to VBA. But,
it is how it is....

On Oct 30, 11:36 am, "RB Smissaert"
wrote:
I think my solution was for a different problem.
Will have to Google it up.

RBS

wrote in message

ups.com...



Thank you very much for your reply. I think I understand where you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:


Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))


On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:


With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With


RBS


"RB Smissaert" wrote in message


.. .


Try this:


Instead of calling AddressOf directly call it via a function like
this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text.
One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying
to
migrate this to a reusable class, the code crashes on that line
with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this
code
really efficient by keeping it in a class amongst some other
utility
functions I've written. Seems I can only use it in a module
instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater
than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc
As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long)
As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String)
As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms
As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -





Peter T

API Class Question
 
Hi Cory,

Before seeing the link referred to by RBS I would have said no way to call a
procedure in a class module with AddressOf. However perhaps the Implements
approach might work, I haven't tried.

If all you want is to return a list of window handles and captions try the
'mySpy' routine here -
http://tinyurl.com/28ufpp

Ignore the preamble and discard Test2(), paste all into a normal module and
run the Test() example on a clean sheet.

The routine produces a tree like array of hWin's & titles 'ArrWins' and, as
written, dumps this into cells (guess you won't need that bit). It should be
easy to adapt to entirely to class based and use ArrWin as required.

In theory the recursive Find-next approach is not as reliable as
EnumWindows, eg if during the process a window is closed it would halt.
However for most purposes should be pretty fast and 'almost' always
complete.

Regards,
Peter T

wrote in message
ups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)

I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:

"Invalid use of AddressOf operator"

Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."

Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.

My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:

==================================
Option Explicit

Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long

Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long

Private Type AppWindow
sTitle As String
lHandle As Long
End Type

Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle

Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))

FindWindowByTitle = tParms.lHandle
End Function

Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String

'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)

'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If

'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function

Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================

Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.

Thanks for any light that can be shed on this.

Cory




[email protected]

API Class Question
 
That is valuable info, and it's one of the things I came across while
looking for a solution. It's also the article that has convinced me
this can't be done in one, easy to reuse, VBA class. It's amazing the
things that Microsoft has exposed via WMI and API, and it's even more
amazing to find that something as common as the title text in a window
can't be accessed the way I'm wanting: in a single VBA class.

Thank you all very much for your input and effort! I learned a ton
about what's available through API with this little exercise.

Cory

On Oct 30, 1:39 pm, "RB Smissaert"
wrote:
Not sure it can work in VBA, but this link addresses the problem:http://shorterlink.com/?DM71M6

RBS

wrote in message

ups.com...



Thanks! I'm doing the same thing. I haven't found anything useful
yet. This would be so much easier if I wasn't limited to VBA. But,
it is how it is....


On Oct 30, 11:36 am, "RB Smissaert"
wrote:
I think my solution was for a different problem.
Will have to Google it up.


RBS


wrote in message


roups.com...


Thank you very much for your reply. I think I understand where you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:


Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))


On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:


With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With


RBS


"RB Smissaert" wrote in message


.. .


Try this:


Instead of calling AddressOf directly call it via a function like
this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text.
One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying
to
migrate this to a reusable class, the code crashes on that line
with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this
code
really efficient by keeping it in a class amongst some other
utility
functions I've written. Seems I can only use it in a module
instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater
than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc
As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long)
As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String)
As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms
As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -




[email protected]

API Class Question
 
That's some pretty neat coding. Thanks for sharing that!

I ended up doing the one thing I was trying to avoid to solve this
problem. Rather than using the AddressOf to pass the Long, I just
modified the GetWindowTitles to use a For...Next to pass 1 to 9999 as
window handles to the GetTitleText call. Only if text was returned
did I store the value and then if the string I was searching for
turned out to be a match to that value, I considered it True.

I know it's not even close to being solid coding, but it works for
now.

Again, thanks for everyone's help on this!

Cory

On Oct 30, 3:41 pm, "Peter T" <peter_t@discussions wrote:
Hi Cory,

Before seeing the link referred to by RBS I would have said no way to call a
procedure in a class module with AddressOf. However perhaps the Implements
approach might work, I haven't tried.

If all you want is to return a list of window handles and captions try the
'mySpy' routine here -http://tinyurl.com/28ufpp

Ignore the preamble and discard Test2(), paste all into a normal module and
run the Test() example on a clean sheet.

The routine produces a tree like array of hWin's & titles 'ArrWins' and, as
written, dumps this into cells (guess you won't need that bit). It should be
easy to adapt to entirely to class based and use ArrWin as required.

In theory the recursive Find-next approach is not as reliable as
EnumWindows, eg if during the process a window is closed it would halt.
However for most purposes should be pretty fast and 'almost' always
complete.

Regards,
Peter T

wrote in message

ups.com...



OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text. One
of the functions uses "AddressOf AnotherFunctionName" to accomplish
this. The code works fantastic in a module. However, when trying to
migrate this to a reusable class, the code crashes on that line with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this code
really efficient by keeping it in a class amongst some other utility
functions I've written. Seems I can only use it in a module instead.


My question is this: Is there a way to work around this in a class?
Here's my working module code that simply returns a Long greater than
zero if an app with all or part of the passed title is found to be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal lEnumFunc As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As String) As
Long
'We'll pass a custom structure in as the parameter to store our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long, TheParms As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -




RB Smissaert

API Class Question
 
Just wondering why you are so keen to get it all in a class. As you got it
working with the added module
what is wrong with that?

RBS

wrote in message
ups.com...
That is valuable info, and it's one of the things I came across while
looking for a solution. It's also the article that has convinced me
this can't be done in one, easy to reuse, VBA class. It's amazing the
things that Microsoft has exposed via WMI and API, and it's even more
amazing to find that something as common as the title text in a window
can't be accessed the way I'm wanting: in a single VBA class.

Thank you all very much for your input and effort! I learned a ton
about what's available through API with this little exercise.

Cory

On Oct 30, 1:39 pm, "RB Smissaert"
wrote:
Not sure it can work in VBA, but this link addresses the
problem:http://shorterlink.com/?DM71M6

RBS

wrote in message

ups.com...



Thanks! I'm doing the same thing. I haven't found anything useful
yet. This would be so much easier if I wasn't limited to VBA. But,
it is how it is....


On Oct 30, 11:36 am, "RB Smissaert"
wrote:
I think my solution was for a different problem.
Will have to Google it up.


RBS


wrote in message


roups.com...


Thank you very much for your reply. I think I understand where
you're
going with this, but I can't seem to get it working. When I add in
the FARPROC function and use it per your example, I'm still getting
the same error that I originally described:


Call EnumWindows(FARPROC(AddressOf GetOpenWindows), VarPtr(tParms))


On Oct 30, 9:45 am, "RB Smissaert"
wrote:
I forgot to give an example:


With CC
'base flag
.flags = CC_ANYCOLOR
.flags = .flags Or CC_FULLOPEN
.flags = .flags Or CC_RGBINIT
.rgbResult = lStartColour
.flags = .flags Or CC_ENABLEHOOK
.lpfnHook = FARPROC(AddressOf ChooseColorProc)
'size of structure
.lStructSize = Len(CC)
'assign the custom colour selections
.lpCustColors = VarPtr(dwCustClrs(0))
End With


RBS


"RB Smissaert" wrote in message


.. .


Try this:


Instead of calling AddressOf directly call it via a function like
this:


Function FARPROC(ByVal pfn As Long) As Long


FARPROC = pfn


End Function


RBS


wrote in message
oups.com...
OK, so I'm pretty new to API's so forgive me if this is an idiot
question :-)


I'm putting together a class that uses API calls to user32 to
enumerate and list all running applications by their Title text.
One
of the functions uses "AddressOf AnotherFunctionName" to
accomplish
this. The code works fantastic in a module. However, when
trying
to
migrate this to a reusable class, the code crashes on that line
with
an error of:


"Invalid use of AddressOf operator"


Looking in Help it says:
"You tried to use AddressOf with the name of a class method.
Only the names of Visual Basic procedures in a .bas module can
be
modified with AddressOf. You can't specify a class method."


Well, shucks, that just popped my bubble of wanting to make this
code
really efficient by keeping it in a class amongst some other
utility
functions I've written. Seems I can only use it in a module
instead.


My question is this: Is there a way to work around this in a
class?
Here's my working module code that simply returns a Long greater
than
zero if an app with all or part of the passed title is found to
be
running:


==================================
Option Explicit


Private Declare Function EnumWindows Lib "user32" (ByVal
lEnumFunc
As
Long, ByVal wParam As Long) As Long


Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As
Long)
As
Long


Private Type AppWindow
sTitle As String
lHandle As Long
End Type


Public Function FindWindowByTitle(ByVal TheWindowTitle As
String)
As
Long
'We'll pass a custom structure in as the parameter to store
our
result...
Dim tParms As AppWindow
tParms.sTitle = TheWindowTitle


Call EnumWindows(AddressOf GetWindowTitles, VarPtr(tParms))


FindWindowByTitle = tParms.lHandle
End Function


Private Function GetWindowTitles(ByVal TheHandle As Long,
TheParms
As
AppWindow) As Long
Dim sTitleText As String


'set a generic 260 length empty string to catch the window text
sTitleText = Space(260)
'get the text
Call GetWindowText(TheHandle, sTitleText, 260)
'remove nulls from the text
sTitleText = TrimNull(sTitleText)


'check to see if all or part of the search string is found
'in the window text
If sTitleText Like TheParms.sTitle Then
'if a match is found, then set the handle number
TheParms.lHandle = TheHandle
'and then exit the function
GetWindowTitles = 0
End If


'reset to 1 to keep the recursive loop going if not match found
GetWindowTitles = 1
End Function


Private Function TrimNull(ByVal TheText As String)
'check to see if string has null characters on the end
If Not InStr(TheText, Chr$(0)) = 0 Then
'if so, then remove the null characters from the end
TheText = Left$(TheText, InStr(TheText, Chr$(0)) - 1)
End If
TrimNull = TheText
End Function
=======================================


Of course the usage of this would be to pass a string to the
only
public function FindWindowByTitle.


Thanks for any light that can be shed on this.


Cory- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -- Hide quoted text -


- Show quoted text -






All times are GMT +1. The time now is 12:42 PM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
ExcelBanter.com