dcsimg
Results 1 to 13 of 13

Thread: Sub Reacting Differently depending on where called from

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Sub Reacting Differently depending on where called from

    Hi All!

    Im writing a standalone app to run alongside AutoDesk Inventor, and i olny say that because part of my code was received from them and therefore im unsure if im allowed to post it anywhere... however my problem is this... I am using a sub, "filler" to fill textboxes with properties of inventor files, i have a sub that runs whenever Inventor detects a change in a given file's properties (which is the part im unsure if i can show). Currently, for testing purposes, "filler" looks like this

    Friend Sub Filler()
    TextBox1.Text = "In-1"

    MessageBox.Show("Working")

    TextBox1.Text = "In-2"

    End Sub

    If i call this sub from a method on the same class (i.e. - form1.button1.click) it runs perfectly fine, however if it is called from the auto-updating sub that i received from autodesk, which exists in its own, separate class, the messagebox fires, but neither of the textbox lines run...any ideas?

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,626

    Re: Sub Reacting Differently depending on where called from

    Oh, they probably run just fine, they just aren't updating the textboxes you think they should be updating. This is most likely a problem stemming from the default instance of the form. The default instance is a special instance, either the sub is updating the default instance while you are looking at a different instance, or the sub is updating a specific instance while you are looking at the default instance. It's most likely going to be one of those, and the bottom line is that the sub is not updating the form you are looking at, it's updating some form that you aren't displaying. Being more specific is kind of hard without seeing the code, which, as you say, you aren't sure you can (or should) show.

    If you aren't familiar with default instances, that's the place to look. The brief summary is that, since 2005, there is an instance for every form that has a default constructor (one that takes no arguments, which is ALL forms unless you get rid of the default constructor and replace it with one that takes arguments). This is pretty much like having a module with this line in it:

    Public Form1 As New Form1

    In other words, you have a form instance in a variable with the same name as the form type. That little change was added to make .NET seem more familiar to people coming from VB6, but it has sewn confusion ever since, because it blurs the line between what is a type and what is an instance. Normally, Form1 is a type. You don't have one until you create an instance with New, and you can only work with an instance. When MS added the default instance, you now have an instance that is created for you, so you don't create it, and it has the same name as the type, which is really a mess.

    Still, if you write Form1.Textbox, then you are not dealing with a textbox on "any instance of Form1", you are dealing with the Textbox on the default instance. If that's not the instance you are showing, then you won't see any changes made there.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    Well, i added the line :

    MessageBox.Show(TextBox1.Text)

    to the end of that sub, and it does indeed reflect that the textbox has been changed to read "In-2"... Kudos on picking that out... i am unsure how to go about correcting that, but it definitely gives me a direction to look in.

  4. #4
    Fanatic Member kpmc's Avatar
    Join Date
    Sep 2017
    Posts
    977

    Re: Sub Reacting Differently depending on where called from

    Unless they provided some kind of EULA, which is highly unlikely, you are most certainly free to post the code they provided to you. Are there any comments in the code that declare ownership of the code?

  5. #5

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    Well, i added the line :

    MessageBox.Show(TextBox1.Text)

    to the end of that sub, and it does indeed reflect that the textbox has been changed to read "In-2"... Kudos on picking that out... i am unsure how to go about correcting that, but it definitely gives me a direction to look in.

  6. #6

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    Sorry all, i unintentionally double posted that last bit... there are no such notices about posting or publicizing the code, so ill just throw it up here there are 3 classes in total (Form1 and 2 others). For a little more clarity i put a ">>>>" in front of code ive added...

    ive separated the classes with a "----------" line. In order they are "AppEventsManager.vb" , "InventorProcess.vb", and "Form1.vb"



    Code:
    Imports Inventor
    
    Public Class AppEventsManager
        Private _app As Inventor.Application
        Private WithEvents _appEvents As ApplicationEvents
    
        Public Sub New(app As Inventor.Application)
            _app = app
            _appEvents = _app.ApplicationEvents
        End Sub
    
        Public Sub m_appEvents_OnDocumentChange(DocumentObject As _Document, BeforeOrAfter As EventTimingEnum,
                                                 ReasonsForChange As CommandTypesEnum, Context As NameValueMap,
                                                 ByRef HandlingCode As HandlingCodeEnum) Handles _appEvents.OnDocumentChange
            HandlingCode = HandlingCodeEnum.kEventHandled
            If (BeforeOrAfter = EventTimingEnum.kAfter) Then
                If ((ReasonsForChange And CommandTypesEnum.kFilePropertyEditCmdType) <> 0) Then
                    Debug.Print(" -------- iProperty Change")
                    For i As Integer = 1 To Context.Count
                        Dim name = Context.Name(i)
                        Dim value = Context.Item(i)
                        If (name = "InternalNamesList") Then
                            Dim internalNames() As String = value
                            Debug.Print("  InternalNames : {0}", String.Join(",", internalNames))
                        Else
                            Debug.Print("  Name : {0}, Value: {1}", name, value)
                        End If
                    Next
                End If
    >>>>            MessageBox.Show("afdd")
    >>>>            Call Form1.Filler()
            End If
        End Sub
    End Class
    
    ---------------------------
    
    
    
    Imports System.IO
    Imports System.Windows
    
    Public Class InventorProcess
    
        Private inventorApp As Inventor.Application
        Public m_quitInventor As Boolean = False
    
        Public Sub StartInventor()
            Try
                ' Try to get an active instance of Inventor
                Try
                    Debug.Print("StartInventor - Trying to find Inventor application")
                    inventorApp = TryCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application"), Inventor.Application)
                    'inventorApp = DirectCast(Interaction.GetObject(Nothing, "Inventor.Application"), Inventor.Application)
                    Debug.Print(" - Found it")
                Catch ex As Exception
                    MessageBox.Show("There was a problem getting an Inventor object.", "Error")
                End Try
    
                ' If not active, create a new Inventor session
                If inventorApp Is Nothing Then
                    LaunchInventor()
                End If
    
                'If (inventorApp IsNot Nothing) Then
                'MessageBox.Show(inventorApp.SoftwareVersion.DisplayName, "Inventor Version")
                'End If
            Catch ex As Exception
                MessageBox.Show("There was a problem starting Inventor.", "Error")
            End Try
        End Sub
    
        Public Sub StopInventor()
            Debug.Print("StopInventor")
            If m_quitInventor = True Then
                'Debug.Print(" - Quitting Inventor")
                'inventorApp.Quit()
                'WaitForInventorToDie()
            End If
    
            inventorApp = Nothing
        End Sub
    
        Friend ReadOnly Property Application() As Inventor.Application
            Get
                Return inventorApp
            End Get
        End Property
    
    
        Sub LaunchInventor()
    
            Debug.Print("InventorInfo - Launching Inventor...")
            Dim inventorAppType As Type = System.Type.GetTypeFromProgID("Inventor.Application")
            inventorApp = System.Activator.CreateInstance(inventorAppType)
            'm_inventorAppEvents = inventorApp.ApplicationEvents
    
            WaitForInventorToBeReady()
    
            inventorApp.Visible = True
            m_quitInventor = True
    
        End Sub
    
        Sub WaitForInventorToBeReady()
            Dim inventorReady As Boolean = False
            While Not inventorReady
                System.Threading.Thread.Sleep(100)
                '	System.Windows.Forms.Application.DoEvents()
                If inventorApp.Ready Then inventorReady = True
            End While
            Debug.Print("InventorInfo - Inventor Ready")
        End Sub
    
        Sub WaitForInventorToDie()
            ' Wait for Inventor to be gone
            Do While Not inventorApp Is Nothing
                Try
                    inventorApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application")
                    System.Threading.Thread.Sleep(100)
                Catch ex As Exception
                    Debug.Print(" - Inventor is dead")
                    inventorApp = Nothing
                End Try
            Loop
        End Sub
    
    End Class
    
    ------------------------
    
    
    Public Class Form1
    
        Private _eventsManager As AppEventsManager
        Private _inventorProcess As InventorProcess
    
    
    >>>>    Friend Sub Filler()
    >>>>        TextBox1.Text = "fffff"
    >>>>        MessageBox.Show("Worxed@")
    >>>>        TextBox1.Text = "afdsadf"
    >>>>        MessageBox.Show(TextBox1.Text)
    >>>>    End Sub
    
    
        Protected Overrides Sub OnLoad(e As EventArgs)
            MyBase.OnLoad(e)
            _inventorProcess = New InventorProcess()
            _inventorProcess.StartInventor()
            _eventsManager = New AppEventsManager(_inventorProcess.Application)
        End Sub
    
        Protected Overrides Sub OnClosed(e As EventArgs)
            MyBase.OnClosed(e)
            _inventorProcess.StopInventor()
        End Sub
    
    >>>>    Private Sub TextBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles TextBox1.MouseUp
    >>>>        Call Filler()
    >>>>    End Sub
    End Class
    Last edited by Shaggy Hiker; May 15th, 2019 at 12:51 PM. Reason: Added CODE tags.

  7. #7

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    ok, so , i have no idea why it triple posted that..... my apologies

  8. #8
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,626

    Re: Sub Reacting Differently depending on where called from

    I removed the duplicate, then added a bit of formatting to the code. You can do that by pressing the # button and pasting the code between the resulting [CODE][/CODE] tags, or paste in the code, then highlight it and press the # button. Some folks prefer the VB button with =VB, but I feel it adds work for little benefit.

    As to the code, this line:

    Call Form1.Filler()

    is using the default instance of Form1. There are a couple ways that may not be the form you are showing. If you created some other instance:
    Code:
    Dim someInstance As New Form1
    
    someInstance.Show
    then that would not be the default instance. However, in this case, it seems like you might be using Form1 as the startup instance, in which case it would be the default instance....unless that other method is running on a different thread. Default instances are thread specific, so if it is running on a different thread, then it created its own instance.

    What I would be doing is passing a form instance to the AppEventsManager class. You could give it a property with the type Form1, then, in the load event where you create the AppEventsManager instance, you could then set the form with something like:
    Code:
    _eventsManager.YourForm1Property = Me
    Then, in place of the Form1 in AppEventsManager, you'd use the contents of the property (there are two ways to do that, and I don't know which you'd be using).
    My usual boring signature: Nothing

  9. #9

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    GAH......
    i added this to form1.vb:
    Code:
        _eventsManager.apro = Me
    and this to AppEventsManager.vb:
    Code:
    Private f As Form1
    
    Public Property apro() As Form1
            Get
                Return f
            End Get
            Set(value As Form1)
                f = value
            End Set
        End Property
    and switched the call line to :
    Code:
      Call apro.Filler()
    Throws a cross-thread error, which thankfully is further than i was before, but im soooooo sure i did something wrong in there

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,078

    Re: Sub Reacting Differently depending on where called from

    When you want to update the textbox, try invoking it since the code you're running in is a different thread, not the GUI thread.
    I guess apro must be a reference to the form, so try

    apro.Invoke(Sub() Filler())

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,626

    Re: Sub Reacting Differently depending on where called from

    Quote Originally Posted by ziro View Post
    GAH......
    i added this to form1.vb:
    Code:
        _eventsManager.apro = Me
    and this to AppEventsManager.vb:
    Code:
    Private f As Form1
    
    Public Property apro() As Form1
            Get
                Return f
            End Get
            Set(value As Form1)
                f = value
            End Set
        End Property
    and switched the call line to :
    Code:
      Call apro.Filler()
    Throws a cross-thread error, which thankfully is further than i was before, but im soooooo sure i did something wrong in there
    No, that's excellent information. What that means is that the event is being raised on a thread other than the UI thread. I saw no evidence of that, but that exception confirms it. That was one of the alternatives I suggested, and one of the strangest little details of default instances: Every thread creates its own. So, now we KNOW that you were working with the wrong instance, and we know WHY.
    My usual boring signature: Nothing

  12. #12

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    11

    Re: Sub Reacting Differently depending on where called from

    Alright, ya'll are amazing, i couldnt possibly thank you enough for all this help, invoking it worked! .... AND , as another plus, it gives me some more stuff to learn and get to know, and be comfortable with. @shaggy hiker, although the invoking worked, if there was a different direction you were headed down , id still like to know what it was, more knowledge never hurt anyone, except for the minor programming headaches

  13. #13
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    33,626

    Re: Sub Reacting Differently depending on where called from

    No, that's the only option that looks possible. All UI elements (forms and the like) are owned by the UI thread. Technically, you could have some on other threads, but it's awkward and not at all worth doing unless no other alternative is available. What Invoke is doing is moving the call onto the UI thread. It wasn't clear that the problem had to do with threading, but once it became clear that the event was being raised on a different thread, invoking the call on the UI thread is the only good solution. There are a couple ways to do it that are harder than the one shown, but they also have no advantage going for them.
    My usual boring signature: Nothing

Posting Permissions

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



Featured


Click Here to Expand Forum to Full Width