Wait for dialogue to load before running code.

Wait for dialogue to load before running code.

JhoelForshav
Mentor Mentor
703 Views
3 Replies
Message 1 of 4

Wait for dialogue to load before running code.

JhoelForshav
Mentor
Mentor

Hi,

At my company we use Frame Generator a lot. In order to make everything work with our vault and resource planning it is crucial that this ckeckbox is unchecked when a frame member is placed (picture below)

FGckeckbox.PNG

I wrote this code to handle the problem in inventor 2018:

 
Public Class FGBox
	Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA"(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
	Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA"(ByVal hWndParent As Integer, ByVal hWndChildAfter As Integer, ByVal lpszClass As String, ByVal lpszWindow As String) As Integer
	Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
	Private Const BM_CLICK As Integer = &HF5&
	Private Const BM_SETCHECK As Integer = &HF1&

	Sub Main
		If ThisDoc.Document Is ThisApplication.ActiveDocument Then
			Dim oCommandMgr As CommandManager
			oCommandMgr = ThisApplication.CommandManager
			Dim oControlDef As ControlDefinition
			oControlDef = oCommandMgr.ControlDefinitions.Item("AFG_CMD_InsertProfile")
			If oControlDef.Enabled = False Then
				oControlDef.Enabled = True
			End If


			Call oControlDef.Execute

			Dim h1 = FindWindow(Nothing, "Insert")

			Dim h2 = FindWindowEx(h1, 0, Nothing, Nothing)
			Dim count As Integer = 0
			Do While h2 <> 0
				h2 = FindWindowEx(h1, h2, Nothing, Nothing)
				count += 1
				If count = 33 Then
					SendMessage(h2, BM_SETCHECK, False, 0)
					h2 = FindWindowEx(h1, h2, Nothing, "Cancel")
					SendMessage(h2, BM_CLICK, 0, 0)
					Exit Do
				End If
			Loop
		End If
	End Sub

End Class

 And had it triggered on new document and document open. The code basically opens the dialogue, finds the checkbox and unchecks it. Then closes the dialouge. Even though it's an ugly way of doing it it worked just fine.

 

In Inventor 2020 however, you have to have the assembly saved before the dialouge can be opened, so the code cant do anything on a new document...

 

Therefore i thought i should write an addin that simply ckecks for the "Insert Frame" command to execute, and when it does, uncheck the box.

My problem now is that i cant find the appropriate event.

 

Doing it this way tries to uncheck the box before the dialogue is shown:

Public Sub FGopen(CommandName As String, Context As NameValueMap) Handles m_UserInputEvents.OnActivateCommand
            If CommandName = "AFG_CMD_InsertProfile" Then
                Dim h1 = FindWindow(Nothing, "Insert")
                Dim h2 = FindWindowEx(h1, 0, Nothing, Nothing)
                Dim count As Integer = 0
                Do While h2 <> 0
                    h2 = FindWindowEx(h1, h2, Nothing, Nothing)
                    count += 1
                    If count = 33 Then
                        SendMessage(h2, BM_SETCHECK, False, 0)
                        Exit Do
                    End If
                Loop
            End If
        End Sub

I also tried looping until h1 <> 0 but then the dialogue never opened and i ended up with an infinity loop.

 

This way ran the code first when the dialogue was closed:

        Public Sub FGopen(CommandName As String, Context As NameValueMap) Handles m_UserInputEvents.OnTerminateCommand
            If CommandName = "AFG_CMD_InsertProfile" Then
                Dim h1 = FindWindow(Nothing, "Insert")
                Dim h2 = FindWindowEx(h1, 0, Nothing, Nothing)
                Dim count As Integer = 0
                Do While h2 <> 0
                    h2 = FindWindowEx(h1, h2, Nothing, Nothing)
                    count += 1
                    If count = 33 Then
                        SendMessage(h2, BM_SETCHECK, False, 0)
                        Exit Do
                    End If
                Loop
            End If
        End Sub

So my question is:

Is there a way to see if the dialogue is shown before running the code, or does anybody have a better approach to the entire situation? 🙂

 

Any help would be much appreciated.

 

Accepted solutions (1)
704 Views
3 Replies
Replies (3)
Message 2 of 4

JhoelForshav
Mentor
Mentor

box.PNG

Unclear picture above. Its this box i'm talking about 🙂

Message 3 of 4

JhoelForshav
Mentor
Mentor
Accepted solution

Never mind. I solved it myself now using System.Windows.Automation to add an event handler for when a new window is opened. Then once the checkbox is unchecked i remove the handler.

Final code:

Imports Inventor
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.Windows.Automation

Namespace UncheckFG
    <ProgIdAttribute("UncheckFG.StandardAddInServer"), _
    GuidAttribute(g_simpleAddInClientID)> _
    Public Class StandardAddInServer
        Implements Inventor.ApplicationAddInServer
        Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
        Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWndParent As Integer, ByVal hWndChildAfter As Integer, ByVal lpszClass As String, ByVal lpszWindow As String) As Integer
        Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
        Private Const BM_CLICK As Integer = &HF5&
        Private Const BM_SETCHECK As Integer = &HF1&

#Region "ApplicationAddInServer Members"

        Public Sub Activate(ByVal addInSiteObject As Inventor.ApplicationAddInSite, ByVal firstTime As Boolean) Implements Inventor.ApplicationAddInServer.Activate
            Try
                g_inventorApplication = addInSiteObject.Application
                System.Windows.Automation.Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Subtree, AddressOf OnWindowOpened)

            Catch ex As Exception
                MsgBox("Unexpected failure in the activation of the add-in ""UncheckFG""" & vbCrLf & vbCrLf & ex.Message)
            End Try
        End Sub

        Private Sub OnWindowOpened(sender As Object, oAutomationEventArgs As AutomationEventArgs)
            Try
                Dim element As AutomationElement = sender
                If element Is Nothing OrElse element.Current.Name <> "Insert" Then Return
                Dim h1 = element.Current.NativeWindowHandle
                Dim h2 = FindWindowEx(h1, 0, Nothing, Nothing)
                Dim count As Integer = 0
                Do While h2 <> 0
                    h2 = FindWindowEx(h1, h2, Nothing, Nothing)
                    count += 1
                    If count = 33 Then
                        SendMessage(h2, BM_SETCHECK, False, 0)
                        System.Windows.Automation.Automation.RemoveAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, AddressOf OnWindowOpened)
                        Exit Do
                    End If
                Loop

            Catch
            End Try
        End Sub

        Public Sub Deactivate() Implements Inventor.ApplicationAddInServer.Deactivate

            g_inventorApplication = Nothing

            System.GC.Collect()
            System.GC.WaitForPendingFinalizers()
        End Sub


        Public ReadOnly Property Automation() As Object Implements Inventor.ApplicationAddInServer.Automation
            Get
                Return Nothing
            End Get
        End Property

        ' Note:this method is now obsolete, you should use the 
        ' ControlDefinition functionality for implementing commands.
        Public Sub ExecuteCommand(ByVal commandID As Integer) Implements Inventor.ApplicationAddInServer.ExecuteCommand
            ' Not used.
        End Sub

#End Region



    End Class
End Namespace


Public Module Globals
    Public g_inventorApplication As Inventor.Application
    Public Const g_simpleAddInClientID As String = "70a12713-c230-44b6-ab41-aef9c744279c"
    Public Const g_addInClientID As String = "{" & g_simpleAddInClientID & "}"
End Module
Message 4 of 4

JhoelForshav
Mentor
Mentor

In the unlikely event that anybody finds this code and wants to use it I'll post an update below to my sub OnWindowOpened. With the Inventor update Build 310, Release: 2020.2 the sub above is obsolete.

 

This seems to be a more stable solution:

Private Sub OnWindowOpened(sender As Object, oAutomationEventArgs As AutomationEventArgs)
            Try
                Dim element As AutomationElement = sender
                If element Is Nothing OrElse element.Current.Name <> "Insert" Then Return
                Dim h1 = element.Current.NativeWindowHandle
                Dim h2 = GetDlgItem(h1, Convert.ToInt32(211, 16))
                If h2 <> 0 Then
                    SendMessage(h2, BM_SETCHECK, False, 0)
                    System.Windows.Automation.Automation.RemoveAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, AddressOf OnWindowOpened)
                End If
            Catch
            End Try
        End Sub