I saw a question on the Inventor Customization forum that I thought I knew the answer to, but after a quick test found that it wasn’t what I thought it was. They were having a problem with using the CommandManager.Pick method in a loop to select multiple entities. It worked ok unless the user pressed the Escape key and then it would skip some of the selections.
If you use the Pick method by itself, it will return the entity selected or if the user presses Escape it will return Nothing. If you have a loop, like the one shown below, when you press Escape it skips one of the pick operations. For example, when I run the program I see “Select face 1”, I press Escape, and then I see “Select face 3”, never getting a chance to select the face 2. The assumption in the forum was that the down and up of the Escape key is counting as two escapes.
Dim faces(9) As Inventor.Face For i As Integer = 0 To 9 faces(i) = invApp.CommandManager.Pick(Inventor.SelectionFilterEnum.kPartFaceFilter, "Select face " & i + 1) Next
I did a bit of experimenting and found that it’s not the up and down of the Escape button that causing the problem but that it’s a timing issue. I’m not sure exactly what’s happening, but one way to visualize it is that the Pick method is checking to see if the Escape key is down and returns Nothing if it is. So the behavior with the above code is that it’s waiting for me to pick the first entity, I press the Escape key and the Pick method finishes returning Nothing, the Pick method is called again within the loop, but because this happens so fast, the user hasn’t had a chance to release the Escape key, so the second call also returns Nothing. By the time it gets to the third call of the Pick, the Escape key is up and it works as usual. If the user is slow to release the Escape key it might skip more than one.
I was able to work around this behavior by pausing the program to give the user a chance to release the Escape button. Here’s my first successful test using a Windows Forms application in Visual Studio. You can see that I added a call to the Sleep method to pause for 1/5 of a second after the Pick method is called. This seems to work great but then I moved the code to VBA and iLogic and it didn’t work.
Windows Form Application (exe)
Private Sub btnTestPick_Click(sender As Object, e As EventArgs) Handles btnTestPick.Click Dim invApp As Inventor.Application = GetObject(, "Inventor.Application") Dim faces(9) As Inventor.Face For i As Integer = 0 To 9 faces(i) = invApp.CommandManager.Pick(Inventor.SelectionFilterEnum.kPartFaceFilter, "Select face " & i + 1) System.Threading.Thread.Sleep(200) Next Debug.Print(vbCrLf & "Final") For i As Integer = 0 To 9 Debug.Print(" " & TypeName(faces(i))) Next End Sub
The difference between a Windows Forms application and VBA, iLogic, and an Add-In is that the Windows Forms application is an exe and runs in its own process outside of Inventor. All of the other types of programs run within the Inventor application. In the case of a program running within Inventor, calling Sleep doesn’t just pause your program but pauses all of Inventor. To get it to work for these other cases I also had to add a DoEvents call. This turns control back over to the system to allow it to process any pending messages. Below is the VBA code that is working for me. The Sleep function is a Windows function and has to be declared to be able to use it.
VBA
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) Public Sub PickTest() Dim faces(9) As Inventor.Face Dim i As Integer For i = 0 To 9 Set faces(i) = ThisApplication.CommandManager.Pick(kPartFaceFilter, "Select face " & i + 1) DoEvents Sleep 200 DoEvents Next Debug.Print vbCrLf & "Final" For i = 0 To 9 Debug.Print " " & TypeName(faces(i)) Next End Sub
For iLogic or for an add-in, the code below is working for me. It’s basically the same as the VBA version but how you call Sleep and DoEvents is different.
iLogic or Add-In
Private Sub PickTest Dim faces(9) As Inventor.Face For i As Integer = 0 To 9 faces(i) = ThisApplication.CommandManager.Pick(Inventor.SelectionFilterEnum.kPartFaceFilter, "Select face " & i + 1) System.Windows.Forms.Application.DoEvents() System.Threading.Thread.Sleep(200) System.Windows.Forms.Application.DoEvents() Next End Sub