Consulting

Results 1 to 20 of 20

Thread: Loop through tasks to GetObject()

  1. #1

    Loop through tasks to GetObject()

    Hello everybody (first post!)!!

    Problem:
    I am trying to access multiple runnings instances as objects, and loop through them to find the right one. In particular, I am trying to access GetObject(, "Reflection2.Session"), but as you likely know, GetObject only gets the first running instance.

    Background:
    I stumbled onto this forum from google. It partially answered my question, but I have another question. Instead of resurrecting that thread, I am creating a new one with my specific problem.

    vbaexpress.com/forum/showthread.php?36318-Loop-through-active-window-applications
    (This forum won't let me post an URL link because I don't have enough posts, how dumb is that?)


    Partial Solution:
    That forum gave this code, which loops through all running tasks on your computer:
    Function getCache(num_port)
        Dim wd As Object
        Dim t, i As Long
        Set wd = CreateObject("word.application")
        For Each t In wd.Tasks
            i = i + 1
            Cells(i, 1) = t
            If t = "Reflection" Then
                getCache = t
                Exit Function
            End If
        Next
        wd.Quit
        Set wd = Nothing
    End Function
    My issue is that this function doesn't return an actual object. Does anybody know how I can do that?

    Thank you!
    Adam

  2. #2
    Knowledge Base Approver VBAX Wizard
    Joined
    Apr 2012
    Posts
    5,645
    Sub M_snb() 
        with CreateObject("word.application")
         For Each tsk In .Tasks 
            c00=c00 & vblf & tsk.name
            if instr(tsk.name,"Reflection") then c01=tsk.name
        Next 
    
        .tasks(c01).activate
       end with
        msgbox c00
    End Sub
    But I can hardly imagine when you would need such a code.
    Last edited by snb; 11-04-2013 at 10:43 AM.

  3. #3
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    This is your 6th post I believe and the same question as before. The forum limits url links until you have 5 posts to stop some spam robots and commercial advertisers that only post once.

    So Reflection2.Session is a class object for Word?

    See if this gives you any ideas. I alluded to this sort of method in the thread that you referenced.
    Option Explicit
    ' http://eileenslounge.com/viewtopic.php?f=27&t=11385
    Declare Function GetCurrentProcessId Lib "kernel32" () As Long
    
    
    ' http://www.vbaexpress.com/forum/showthread.php?48103-Loop-through-tasks-to-GetObject%28%29
        Sub StopOthers()
        '   Add a Reference to Microsoft WMI Scripting Library
           Dim hProcMe As Long
           hProcMe = GetCurrentProcessId
           Dim oWMI As Object
           Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
           Dim oList As Object
           Set oList = oWMI.ExecQuery("select * from win32_process where name like 'EXCEL%'")
           'http://msdn.microsoft.com/en-us/library/aa393741%28v=vs.85%29.aspx
           'Dim oProcess As SWbemObject
           Dim oProcess As Object
           For Each oProcess In oList
              Dim iErr As Integer, hProc As Long
              hProc = oProcess.ProcessID
              Debug.Print hProc, oProcess.Name
              'If hProc <> hProcMe Then
              '   iErr = oProcess.Terminate
              'End If
           Next oProcess
        End Sub
    
    'http://www.mrexcel.com/forum/excel-questions/599317-visual-basic-applications-code-work-reflection-unix.html
    
    'Reflections 2011 VBA Guide
    ' http://docs.attachmate.com/reflection/2011/r2/help/en/vba_guide/

  4. #4
    Snb,

    That works fantastic!! Thank you snb! The only thing I'm missing is setting it as an object. Right now I'm using this:
    Function M_snb() As Object
        With CreateObject("word.application")
            For Each tsk In .Tasks
                c00 = c00 & vbLf & tsk.Name
                If InStr(tsk.Name, "Scripts") Then
                    c01 = tsk.Name
                End If
            Next
            M_snb = .Tasks(c01)
        End With
    End Function
    Sub test2()
        Dim Session As Object
        Set Session = M_snb
        Session.Transmit "A"      ' Tests to see if it got it as an object.
    End Sub
    Quote Originally Posted by snb View Post
    But I can hardly imagine when you would need such a code.
    I can GetObject(, "Reflection2.Session") to get the first instance of this program, but I want to grab different instances. The people I roll my scripts out to often have multiple Reflections open, and I want to be able to grab the Reflection that is open to a certain spot, instead of making them close all other instances.

    Kenneth,
    Ah! I understand preventing bots spamming links. It actually wouldn't let me create a thread at all until I had 5 posts.

    Reflection2.Session is not a class object of Word. It's WRQ Reflection for UNIX and Digital (it's own program) made by AttachMate. I have no idea why the function I found references Word, but all I know is that it loops through all of your computers tasks, including this standalone program. I am hoping to modify it to take the result and reference it as an object.

    The code you gave me finds the processes, but I still need to set the function equal to the processes object once it finds it.
    Function getCache2() As Object
    '   Add a Reference to Microsoft WMI Scripting Library
       Dim hProcMe As Long
       hProcMe = GetCurrentProcessId
       Dim oWMI As Object
       Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
       Dim oList As Object
       Set oList = oWMI.ExecQuery("select * from win32_process where name like 'r2w%'")
       'Dim oProcess As SWbemObject
       Dim oProcess As Object
       For Each oProcess In oList
          Dim iErr As Integer, hProc As Long
          hProc = oProcess.ProcessID
          StopOthers = oProcess
       Next oProcess
    End Function
    Last edited by astranberg; 11-04-2013 at 11:47 AM.

  5. #5
    Knowledge Base Approver VBAX Wizard
    Joined
    Apr 2012
    Posts
    5,645
    Sub M_snb()
        For Each tsk In Tasks
            If InStr(tsk.Name, "Scripts") Then c01 = c01 & vblf & tsk.Name
        Next
        
        for each it in split(mid(c01,2),vblf)
        Set c02 = Tasks(it)
        With c02
            .Application.Close 0
        End With
        next
    End Sub
    I didn't find any property that discriminates between several instances of the same program; maybe your application produces those unique properties, reflected in the property 'name'.

  6. #6
    Well there is a reference to my program with some very unique attributes and commands and such (I don't know the technical terms). For example, you can GetText(StartRow, StartCol, EndRow, EndCol), .Transmit "Text", etc. I am going to be using GetText to discriminate between multiple instances, but I need to be able to access each instance first.

    The code just above works until

    c02.Application.Close 0
    That is what keeps hanging me up. I have set something to that task, but I can't seem to access it the same as if I had done:
    Dim Session as Object
    Set Session = GetObject(, "Reflection2.Session")
    If Instr(1, Session.GetText(0, 0, 24, 78), "Script Start Position") > 0 then
       ' Proceed
    End If

  7. #7
    Knowledge Base Approver VBAX Wizard
    Joined
    Apr 2012
    Posts
    5,645
    or ?

    For Each it In split(mid(c01,2),vblf) 
       Set c02 = Tasks(it) 
       msgbox c02.GetText(0, 0, 24, 78), "Script Start Position")
    Next


  8. #8
    c02.Activate works, but none of the custom functions that works with GetObject(, "Reflection2.Session") work.

  9. #9
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    While not foolproof, many find that knowing the classname of the application and the window's caption is sufficient to find the right instance of an application.

  10. #10
    Quote Originally Posted by Kenneth Hobs View Post
    While not foolproof, many find that knowing the classname of the application and the window's caption is sufficient to find the right instance of an application.
    I don't need a solution for figuring out which window to get. What I need is to access each window as an object. I can GetObject(, "Reflection2.Session"), but that only grabs the first instance. snb's solution successfully cycles through the windows perfectly, but I can't use the object as I normally do with that GetObject.

    I need

    obj_FoundWindow.Transmit "A" ' This .Transmit only works with a "Reflection2.Session," object.
    to work.

  11. #11
    Knowledge Base Approver VBAX Wizard
    Joined
    Apr 2012
    Posts
    5,645
    Did you activate the reference to "Reflection.Session" ?

  12. #12
    VBAX Master Aflatoon's Avatar
    Joined
    Sep 2009
    Location
    UK
    Posts
    1,720
    Location
    Quote Originally Posted by astranberg View Post
    I don't need a solution for figuring out which window to get. What I need is to access each window as an object.
    I disagree. If you can get the correct window handle you may be able to use the AccessibleObjectFromWindow API function to return the required automation object. Using Word's Tasks collection will not give you that object as far as I am aware.

    You might also find a solution in an Attachmate/Reflection user group since this doesn't really have anything to do with Excel (even if that's where you happen to be running the code).
    Be as you wish to seem

  13. #13
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    To use the method that Aflatoon mentioned, the IDespatch ID is needed. Since I don't use Unix, I would have no way of finding that. I have seen some examples using it for Excel and some for MSWord to a small degree.
    http://www.mrexcel.com/forum/excel-q...ject-hwnd.html

    One simple method that I used in the past was to close each instance of Excel until I got the one that I needed using GetObject().
    http://excel.tips.net/T009451_Findin...n_a_Macro.html

  14. #14
    Quote Originally Posted by snb View Post
    Did you activate the reference to "Reflection.Session" ?
    Yes.

    Quote Originally Posted by Aflatoon View Post
    You might also find a solution in an Attachmate/Reflection user group since this doesn't really have anything to do with Excel (even if that's where you happen to be running the code).
    Unfortunately, there is no such thing as a Reflection user group. Their customer service is awful.

    Quote Originally Posted by Kenneth Hobs View Post
    One simple method that I used in the past was to close each instance of Excel until I got the one that I needed using GetObject().
    http://excel.tips.net/T009451_Findin...n_a_Macro.html
    I wish I could use this, but they really need to have their spot saved in each instance.

    Quote Originally Posted by Aflatoon View Post
    I disagree. If you can get the correct window handle you may be able to use the AccessibleObjectFromWindow API function to return the required automation object. Using Word's Tasks collection will not give you that object as far as I am aware.
    Quote Originally Posted by Kenneth Hobs View Post
    To use the method that Aflatoon mentioned, the IDespatch ID is needed. Since I don't use Unix, I would have no way of finding that. I have seen some examples using it for Excel and some for MSWord to a small degree.
    http://www.mrexcel.com/forum/excel-q...ject-hwnd.html
    Okay, this idea sounds the most promising. This is Reflection for Unix and Open VMS, but I actually run this program on Windows 7. I have no idea what an IDispatch ID is or how to get it.

  15. #15
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    Getting the ID might not solve much for you since this is an advanced topic. I guess if you want to try, go into regedit and Find the class Reflection2.Session. Then expand the CLSID to get the value.

    Have you tried to open each Application to see if the Caption for each is different? This is done by double clicking the application(s) in the Application tab of the Task Manager. Post a screen print in an Excel file for us to see the application windows.

  16. #16
    Thank you Kenneth.

    Each window has the same caption, (i.e. you can open multiple instances of the same program).

    ReflectionScreenshot.xlsx

  17. #17
    VBAX Master Aflatoon's Avatar
    Joined
    Sep 2009
    Location
    UK
    Posts
    1,720
    Location
    If the captions are all the same, I don't know how you would plan to identify the one you want.
    Be as you wish to seem

  18. #18
    Quote Originally Posted by Aflatoon View Post
    If the captions are all the same, I don't know how you would plan to identify the one you want.
    The logic behind how I get the right one really isn't my question, but I'll explain anyways. After I am "in" the window (e.g. with GetObject), I can pull the PORT number, time window has been up, or where the window is in Reflection. Notice how the top left window is different from the other three. With a simple GetText() command, I can check to see if "ENTER ACCOUNT#, MPI#, STATEMENT# OR NAME" is in the window. Perhaps that text signifies the start position of this script, so I would loop through accessing each Reflection window until I find that text in it.

    But seriously, I'm just trying to figure out how to loop through these windows and "access" them with the commands I get to use when I access the first window through GetObject(, "Reflection2.Session").

  19. #19
    VBAX Master Aflatoon's Avatar
    Joined
    Sep 2009
    Location
    UK
    Posts
    1,720
    Location
    In that case, assuming you can obtain the correct IDispatch ID, you would have to call AccessibleObjectFromWindow on every window of the relevant class to get an object and then apply your tests to see if it is the one you want.
    Be as you wish to seem

  20. #20
    Quote Originally Posted by Aflatoon View Post
    In that case, assuming you can obtain the correct IDispatch ID, you would have to call AccessibleObjectFromWindow on every window of the relevant class to get an object and then apply your tests to see if it is the one you want.
    Thank you! I will now attempt to AccessibleObjectFromWindow.......

    Quote Originally Posted by Kenneth Hobs View Post
    I guess if you want to try, go into regedit and Find the class Reflection2.Session. Then expand the CLSID to get the value.
    Does F29799A0-4B0C-101B-AC7B-04021C007002 seem like a valid IDispatch ID? And will this ID be the same accross all computers?

    I am now trying to figure out this function. Can someone help me modify this code to work?

    Option Explicit
     
    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
     
    Private Declare Function IIDFromString Lib "ole32" _
    (ByVal lpsz As Long, ByRef lpiid As GUID) As Long
     
    Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
    (ByVal hWnd As Long, ByVal dwId As Long, ByRef riid As GUID, _
    ByRef ppvObject As Object) As Long
     
    Private Type GUID
        Data1 As Long
        Data2 As Integer
        Data3 As Integer
        Data4(7) As Byte
    End Type
     
    Private Const RETURN_OK As Long = &H0
    Private Const IID_IDispatch As String = "{F29799A0-4B0C-101B-AC7B-04021C007002}"   ' Found this for Reflection2.Session
    Private Const OBJID_NATIVEOM As Long = &HFFFFFFF0 '// This is supposed to go as the second input of AccessibleObjectFromWindow, _
                                                                               '// but I think I need to change this, as this was originally written for Excel.
    Sub ComplexTest()
         
        Dim iCounter As Long
        Dim hWndXL As Long
        Dim oXLApp As Object
        Dim oWB As Object
        Dim oWS As Object
         
         '// First the first Reflection Window
        hWndXL = FindWindowEx(0&, 0&, "r2Window", vbNullString)
         
         '// Got one, at least...?
        Do While hWndXL > 0
             
             '// Increment counter
            iCounter = iCounter + 1
             
             '// Print Instance & Handle to Debug window
            Debug.Print "Instance #" & iCounter & ": "; "Handle: " & hWndXL
             
             '// Get a reference to it
            If GetReferenceToApp(hWndXL, oXLApp) Then
                 '// Check if this is the window I want
            End If
             
             '// Find the next Reflection Window
            hWndXL = FindWindowEx(0, hWndXL, "r2Window", vbNullString)
             
        Loop
         
    End Sub
     
     '// Returns a reference to a specific instance of Excel.
     '// The Instance is defined by the Handle (hWndXL) passed
     '// by the calling procedure
    Function GetReferenceToApp(hWndXL As Long, oXLApp As Object) As Boolean
         
        Dim hWinDesk As Long
        Dim hWin7 As Long
         
        Dim obj As Object
        Dim iID As GUID
         
        Call IIDFromString(StrPtr(IID_IDispatch), iID) ' Outputs iID as the GUID
        
        If AccessibleObjectFromWindow(hWndXL, OBJID_NATIVEOM, iID, Session) = RETURN_OK Then
            Set oXLApp = obj.Application
            GetReferenceToXLApp = True
            Session.Transmit "IT WORKS!!!!!!!!!!!!!!!!!!!!!!!!"
        End If
    End Function
    Last edited by astranberg; 11-06-2013 at 11:59 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •