Interop Forms Toolkit UserControls Can Launch a .NET Form!

At work, we’re heavily invested in the Interop Forms Toolkit while our product is slowly being migrated from VB6 to .NET.

When you are creating a .NET control to be hosted on a VB6 form, there are several limitations mentioned in the documentation, including:

You should not show a .NET form from an Interop UserControl. The .NET form will not close if the parent form is closed first, and tabbing on the .NET form will not work.

This was going to be a problem for us. Our product has lookup text boxes that launch a search dialog when the user leaves the field with a partial or ambiguous value. The search dialog is a .NET form, so we were concerned that this was going to cause problems.

We tried it anyway. Our interop user controls are always composite controls that can include multiple lookup text boxes. We figured that maybe things would be a little different because we were showing the form modally from within a contained control.

We found that it worked, mostly. The big stickler was when a highly productive worker was entering data using the keyboard. The TAB key would launch the search dialog, but then the focus got stuck somewhere that would not respond to the keyboard any more. They had to use the mouse to get focus back on the form, which was disruptive to their flow.

Other workflow scenarios, such as explicitly launching the search dialog with a function key (i.e. not tabbing) were working just fine and not losing focus.

I won’t rehash all the details of the debugging effort. We added lots of debug statements to event handlers and overrides of methods that were related to key input and focus. We were able to identify this sequence of events that was relevant:

  1. “Entered” event on the constituent lookup control.
  2. “ProcessTabKey” method on the host user control.
  3. “Leave” event on the constituent lookup control.
  4. “Leave” event on the host user control.
  5. Search dialog is displayed…
  6. “Validating” event on the constituent lookup control.
  7. “Validated” event on the constituent lookup control.
Using the bolded items, we were able to design a state diagram to handle this issue and force focus back to where it should have gone in the first place. The following region of code lives on the top user control. My wish is that this code could be useful to somebody else experiencing a similar problem.

#Region " Custom search focus handling "
    ' When this control is hosted on a VB6 form using interop, tabbing out of a field that
    ' launches a custom search dialog causes focus to leave the control and the user
    ' can no longer navigate with the keyboard unless they use the mouse to put focus
    ' back into the control. This block of code detects the scenario and sets focus to the
    ' appropriate control.

    ' Two textboxes on the new item use custom search:
    '   Lookup1
    '   Lookup2

    ' The following sequence of events leads to the problem. These events can also
    ' occur in other scenarios, but they will not occur in this exact sequence.
    ' Lookup control is entered
    ' Tab key is pressed (ProcessTabKey)
    ' Custom search dialog makes this control lose focus (OnLeave)

    ' The fix will set focus back to the appropriate field after the dialog
    ' returns. This will happen when the control is validated, but only when
    ' the appropriate sequence of events has occurred. A state machine enum
    ' is used to manage this.

    Private Enum CustomSearchFieldState
        Null
        Editing
        Tabbing
        NeedsFocus
    End Enum

    Dim mCustomSearchFieldState As CustomSearchFieldState = CustomSearchFieldState.Null
    Dim mCustomSearchField As MyCustomLookupTextBox
    Dim mCustomSearchFieldTabForward As Boolean = False

    Private Sub CustomSearchEnter(sender As Object, e As System.EventArgs) _
    Handles Lookup1.Enter, Lookup2.Enter
        ' The problem only occurs when the control is hosted in VB6. We can detect that specific
        ' scenario through the ParentForm property. In .NET, we will have a parent form. In VB6,
        ' the parent form is null.
        If Me.ParentForm Is Nothing AndAlso
        mCustomSearchFieldState = CustomSearchFieldState.Null Then
            mCustomSearchField = DirectCast(sender, MyCustomLookupTextBox)
            mCustomSearchFieldState = CustomSearchFieldState.Editing
        End If
    End Sub

    Protected Overrides Function ProcessTabKey(forward As Boolean) As Boolean
        If mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus Then
            ' This state indicates that the user canceled out of a previous custom
            ' search. They may have chosen to change direction, so we update
            ' the direction flag.
            mCustomSearchFieldTabForward = forward
        End If
        If mCustomSearchFieldState = CustomSearchFieldState.Editing Then
            mCustomSearchFieldState = CustomSearchFieldState.Tabbing
            mCustomSearchFieldTabForward = forward
        End If
        Return MyBase.ProcessTabKey(forward)
    End Function

    Protected Overrides Sub OnLeave(e As System.EventArgs)
        If mCustomSearchFieldState = CustomSearchFieldState.Tabbing Then
            mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus
        End If
        MyBase.OnLeave(e)
    End Sub

    Private Sub CustomSearchValidated(sender As Object, e As System.EventArgs) _
    Handles Lookup1.Validated, Lookup2.Validated
        If mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus Then
            Me.Focus()
            Me.SelectNextControl(mCustomSearchField, mCustomSearchFieldTabForward, True, True, True)
        End If
        ' Validation is the final event in all states and resets the custom search workaroud.
        mCustomSearchFieldState = CustomSearchFieldState.Null
        mCustomSearchField = Nothing
    End Sub

#End Region

Leave a comment

Amen, Brother Wirth!

From an interview with Niklaus Wirth (added emphasis is mine):

RM:
‟Do you think better education is the answer to poor software? Surely teaching people better would be cheaper in the long run and certainly avoid the huge bloat we see today and we would be able to use simpler and less power-hungry hardware?”
NW:
‟A proper education certainly would help. However, the belief is wide-spread that programming is easy, can be learned on the job, and does not require specific training or talent. However, it is not programming in the sense of coding that is the problem, but design. Applications have become very demanding and their tasks complex. Mastering this growing complexity is the primary challenge. To tackle this task requires experience and an explicit ability for abstraction on many levels. It is difficult to learn this, and even more so to teach it. Not every programmer is a born designer.

All I can say to this is “Amen, Brother!” I have worked side-by-side with a number of developers over the years, and I consider this statement to be an absolute truth.

I also believe that programmers who have a natural ability to easily context-switch between details and abstract concepts fall into the category of programmers who are an order of magnitude more productive than many of their peers.

I think algebra is a good precursor to identifying programming potential. Prior to algebra, math education in the United States focuses on the mechanics. Success in algebra requires an ability to take abstract problems (i.e. word/story problems) and translate them into concrete details.

In school, I tutored a handful of friends and classmates who were taking algebra. Some just needed a different viewpoint to grasp the concept they were struggling with. Others, however, just did not get the concepts, and I believe their brains are simply not wired to think that way. These were not stupid people! They had talents in other areas that just didn’t fit into the abstract concepts of algebra.

Leave a comment

Foul on Microsoft: Improper verbification

From the ZDNet blog, with my own emphasis:

“We’ve been gradually realizing customers who consumer more proactive services are happier and healthier and require less reactive services with their charge models.”

I hope this is a typo, but knowing the propensity for Microsoft-speak, I would not be surprised if the marketing team has made this noun into a verb.

One of the synonyms of consumer is customer. If you make that subsitution, the phrase becomes “…customers who customer more proactive services…”

Leave a comment

Remote administration of COM+ through a firewall

Goal: Administer COM+ applications on remote computers.

Problem: Windows firewall on the remote computer blocks the connection.

Solution: Set up the firewall to accept dynamic RPC ports.

The most relevant article to this topic is available here.

I searched Google for an hour, and could not find anywhere that somebody had documented how to set up a firewall to allow remote administration of COM+ Applications. The Component Services snap-in lets you add another computer. If that computer has the basic Windows Firewall active, you will not be able to connect to or see anything on the other computer. This is indicated by a nice red arrow on the icon for the remote computer.

Component Services uses dynamic RPC ports to communicate with other computers. The article describes how to restrict the ports that RPC uses.

I used the rpccfg.exe tool from the resource kit. A link to download it is in the support article. This is run on the remote PC. I used it to restrict RPC to ports 5001-5100.

The next problem was how to tell the Windows Firewall to allow these ports through from the administration PC. Windows Firewall does not allow port ranges in the exceptions. Powershell to the rescue! The following Powershell script set up exceptions for each port:

PS C:\> 5001..5100 | % { `
netsh firewall add portopening `
protocol = TCP port = $_ `
name = "Remote admin RPC $_" `
scope = CUSTOM addresses = 192.168.1.111}

Leave a comment

Nullable types and boolean comparisons

I’ve begun studying to take the 70-536 exam. I read about Nullable types in my study material and decided to review MSDN’s topic on the subject. The documentation includes a complicated truth table regarding tri-state boolean logic.

Here’s how I think of it, without having to worry about looking up the value in a large truth table.

And comparisons:

  • True: Both operators are true
  • False: Either operator is false
  • Nothing/Null: Any other combination.

Or comparisons:

  • True: Either operator is true
  • False: Both operators are false
  • Nothing/Null: Any other combination.

2 Comments

John Philip Sousa at Interlochen

Recently, my brass quintet did a performance at a senior center in honor of Veterans Day. We opened the concert with Under the Double Eagle, by J. F. Wagner. I explained that this march was a favorite of John Philip Sousa. We closed the performance with Semper Fidelis, by John Philip Sousa.

After the performance, one of the residents at the center came up and told an interesting story. I don’t know if it is true, but I thought it was a nice story.

The resident told us she was a violin student at Interlochen in 1930. Interlochen was founded only a few years earlier, and construction on the campus was not yet complete. In particular, one of the performance venues was going to have an organ, but it was not ready yet. John Philip Sousa visited Interlochen while she was there, and apparently he was distressed because there was no organ.

According to the story, Sousa put out a letter requesting saxophone players. The response was overwhelming, and 75 saxophonists came to Interlochen. They played for a grand concert with Sousa, and they sounded just like an organ!

2 Comments

Lambda is the new nuclear

I was listening to the latest Polymorphic Podcast, and I had to laugh when Craig Shoemaker mentioned lambda expressions. He pronounced lambda as “lam-bah-da”. It made me want to get up and dance.

I wonder how common it is to add an extra syllable, like saying “nu-ku-ler” instead of “nu-clear”?

Leave a comment

Follow

Get every new post delivered to your Inbox.