Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

WMI: Program Crashes When Setting Enabled Property of Button 1

Status
Not open for further replies.

TheInsider

Programmer
Jul 17, 2000
796
CA
Hi,

I'm new to VB.Net, so I'm probably not understanding a basic concept here.

I found some code (below) that will trigger an event whenever someone plugs in a USB drive. I need this check to be running constantly in the background. When a device is plugged in, I want to perform an action like enable a button or open another form.

The code works, except I get a
"A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll"
error if I try to change any of control properties or do just about anything else.

You can test this code by simply creating a form with a button on it called "Button1". Right now it's set up to display a message box when a pen drive is plugged in, and then on the next line, it should try to disable the command button. The latter is where the program crashes.

I'm pulling my hair out. Obviously, an event is useless if you can't take any action when it's triggered. Any help is much appreciated!!!!!!

TIA

PS. I'm not sure if the GetDriveLetterFromDisk() method is part of the problem or not, so I included it anyway.

Code:
Imports System.Management

Public Class Form1
    Private WithEvents m_MediaConnectWatcher As ManagementEventWatcher

    Private Sub Arrived(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs) Handles m_MediaConnectWatcher.EventArrived
        Dim mbo, obj As ManagementBaseObject

        ' the first thing we have to do is figure out if this is a creation or deletion event
        mbo = CType(e.NewEvent, ManagementBaseObject)
        ' next we need a copy of the instance that was either created or deleted
        obj = CType(mbo("TargetInstance"), ManagementBaseObject)

        Select Case mbo.ClassPath.ClassName
            Case "__InstanceCreationEvent"
                If obj("InterfaceType") = "USB" Then
                    MsgBox(obj("Caption") & " (Drive letter " & GetDriveLetterFromDisk(obj("Name")) & ") has been plugged in")
                    Button1.Enabled = True
                End If
            Case "__InstanceDeletionEvent"
                If obj("InterfaceType") = "USB" Then
                    MsgBox(obj("Caption") & " has been unplugged")
                    Button1.Enabled = False
                End If
        End Select

    End Sub

    Private Function GetDriveLetterFromDisk(ByVal Name As String) As String
        Dim oq_part, oq_disk As ObjectQuery
        Dim mos_part, mos_disk As ManagementObjectSearcher
        Dim obj_part, obj_disk As ManagementObject
        Dim ans As String = ""

        ' WMI queries use the "\" as an escape charcter
        Name = Replace(Name, "\", "\\")

        ' First we map the Win32_DiskDrive instance with the association called
        ' Win32_DiskDriveToDiskPartition.  Then we map the Win23_DiskPartion
        ' instance with the assocation called Win32_LogicalDiskToPartition

        oq_part = New ObjectQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & Name & """} WHERE AssocClass = Win32_DiskDriveToDiskPartition")
        mos_part = New ManagementObjectSearcher(oq_part)
        For Each obj_part In mos_part.Get()

            oq_disk = New ObjectQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & obj_part("DeviceID") & """} WHERE AssocClass = Win32_LogicalDiskToPartition")
            mos_disk = New ManagementObjectSearcher(oq_disk)
            For Each obj_disk In mos_disk.Get()
                ans &= obj_disk("Name") & ","
            Next
        Next

        Return ans.Trim(","c)
    End Function

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        m_MediaConnectWatcher.Stop()
    End Sub
 
Oops, I forgot to mention that the button should be set to disabled initially... or the Button1.Enabled = True / Button1.Enabled = False lines should be reversed.
 
Update: I put a Try / Catch block around the problem area, and got a more descriptive error message:

[System.InvalidOperationException] = {"Cross-thread operation not valid: Control 'Button1' accessed from a thread other than the thread it was created on."}

OK, so that verified my original hunch that this was to do with threads.

I tried creating a delagate and placing the Button1.Enabled = True and Button1.Enabled = False statements inside of two methods: EnableButton() and DisableButton, respectively. However, the program still crashes.

Can anyone please show me the correct way to use delegates to get this code to function correctly?

Thanks!
 
You should post what you changed. Here is one way to set that short of thing up.

Code:
    Private Sub EnableDisable(ByVal value As Boolean)
        If Me.InvokeRequired Then
            Me.BeginInvoke(New delEDButton(AddressOf EDButton), value)
        Else
            EDButton(value)
        End If
    End Sub

    Private Delegate Sub delEDButton(ByVal value As Boolean)
    Private Sub EDButton(ByVal value As Boolean)
        Button1.Enabled = value
    End Sub
Then you just call EnableDisable(true) to enable and EnableDisable(false) to disable the button.


-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Sorry, you're right I should have posted my edit. I wasn't at my dev computer when I posted the last comment.

In any case, my attempt at using delegates wasn't correct. As soon as I plugged in the code you gave me, everything worked perfectly!

Code:
...
        obj = CType(mbo("TargetInstance"), ManagementBaseObject)
        Try
            Select Case mbo.ClassPath.ClassName
                Case "__InstanceCreationEvent"
                    If obj("InterfaceType") = "USB" Then                        
                        EnableDisable(True)
                    End If
                Case "__InstanceDeletionEvent"
                    If obj("InterfaceType") = "USB" Then
                        EnableDisable(False)
                    End If
            End Select
        Catch ex As Exception
            MsgBox(ex)
        End Try
    End Sub

    Private Sub EnableDisable(ByVal value As Boolean)
        If Me.InvokeRequired Then
            Me.BeginInvoke(New delEDButton(AddressOf EDButton), value)
        Else
            EDButton(value)
        End If
    End Sub

    Private Delegate Sub delEDButton(ByVal value As Boolean)
    Private Sub EDButton(ByVal value As Boolean)
        Button1.Enabled = value
    End Sub
...

I guess there's a lot I still have to learn about .Net. Anyway, thanks for all your help!
 
NP. Glad to help.

-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top