Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Visual Studio 2005 (2006) [eng]

.pdf
Скачиваний:
117
Добавлен:
16.08.2013
Размер:
21.9 Mб
Скачать

Chapter 37

ByVal e As System.EventArgs) _

Handles BtnRetriveCounters.Click

If Not Me.TxtUserName.Text = “” Then

Dim userName as string = Me.TxtUserName.Text

Dim pathString as String = String.Format(CUserPath,userName) Dim path as New System.Management.ManagementPath(pathString) Dim cu As New ROOT.CIMV2.UserAccount(path)

My.Forms.UserInformation.UserPropertyGrid.SelectedObject = cu My.Forms.UserInformation.ShowDialog()

End If End Sub

End Class

In this example, the Path property is taken from the UserAccount1 object and the user name component is replaced with a string replacement token, {0}. When the button is clicked, the user name entered into the text box is combined with this path using String.Format to generate the full WMI path. The path is then used to instantiate a new UserAccount object, which is in turn passed to the UserInformation form. The UserInformation form is a simple form that contains a docked PropertyGrid through which the user can change attributes of the UserAccount object. This is shown in Figure 37-6.

Figure 37-6

Changes made in this form are immediately committed to the computer, although you can alter this behavior by changing the AutoCommit property on the UserAccount class.

This is only a single example of how you can work with the management classes to retrieve and work with computer information using the WMI interface.

Management Events

In the previous section you learned how you can drag a management class from the Server Explorer onto the form and then work with the generated classes. The other way to work with the WMI interface is through the Management Events node. A management event enables you to monitor any WMI data type and have an event raised if an object of that type is created, modified, or deleted. By default, this node will be empty, but you can create your own by selecting Add Event Query, which will invoke the dialog shown in Figure 37-7.

496

Server Explorer

Use this dialog to locate the WMI data type in which you are interested. Because there are literally thousands of these, it is useful to use the Find box. In Figure 37-7, the search term “user account” was entered, and it was found under the root\CIMV2 node. You are interested in all event types, so select “Object creation, modification or deletion” from the drop-down menu.

Figure 37-7

After clicking OK, a User Accounts Event Query node is added to the Management Events node. If you use Computer Management to enable or disable a user, you will see events being progressively added to this node. In the Build Management Event Query dialog shown in Figure 37-7, the default polling interval was set to 60 seconds, so you may need to wait up to 60 seconds for the event to show up in the tree once you have made the change.

When the event does finally show up, it will appear along with the date and time in the Server Explorer, and it will also appear in the Output window, as shown in the lower pane of Figure 37-8. If you select the event, you will notice that the Properties window is populated with a large number of properties that don’t really make any sense. This is where the management classes become really useful, as you can use the information contained in the management event to populate an instance of the class you generated earlier.

497

Chapter 37

Figure 37-8

To continue the example, drag the User Accounts Event Query node onto a form. This generates an instance of the System.Management.ManagementEventWatcher class, with properties configured so it will listen for changes to user account information. The actual query can be accessed via the QueryString property of the nested ManagementQuery object. As with most watcher classes, the ManagementEventWatch class triggers an event when the watch conditions are met — in this case, the EventArrived event. To generate an event handler, double-click the event in the Properties window and add the following code:

Private Sub ManagementEventWatcher1_EventArrived(ByVal sender As System.Object, _ ByVal e As System.Management.EventArrivedEventArgs) _

Handles ManagementEventWatcher1.EventArrived For Each p As System.Management.PropertyData In e.NewEvent.Properties

If p.Name = “TargetInstance” Then

Dim mbo As System.Management.ManagementBaseObject = _

CType(p.Value, System.Management.ManagementBaseObject) Dim msp As New ROOT.CIMV2.UserAccount.ManagementSystemProperties(mbo) Dim path As New System.Management.ManagementPath(msp.PATH)

Dim cu As New ROOT.CIMV2.UserAccount(path) My.Forms.UserInformation.UserPropertyGrid.SelectedObject = cu My.Forms.UserInformation.ShowDialog()

Return

End If

Next

End Sub

Private Sub ChkUserMonitor_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _

Handles ChkUserMonitor.CheckedChanged

If Me.ChkUserMonitor.Checked Then Me.ManagementEventWatcher1.Start()

Else

Me.ManagementEventWatcher1.Stop() End If

End Sub

498

Server Explorer

In the event handler, you need to iterate through the Properties collection on the NewEvent object. Where an object has changed, two instances are returned: PreviousInstance, which holds the state at the beginning of the polling interval, and TargetInstance, which holds the state at the end of the polling interval. It is possible for the object to change state multiple times within the same polling period. If this is the case, an event will only be triggered when the state at the end of the period differs from the state at the beginning of the period. For example, no event is raised if a user account is enabled and then disabled within a single polling interval.

Notice also from this code snippet the addition of a checkbox to the form to control whether the form is watching for user events. The generated code for the event watcher does not automatically start the watcher.

Message Queues

The Message Queues node, expanded in Figure 37-9, gives you access to the message queues available on your computer. You can use three types of queues: private, which will not appear when a foreign computer queries your computer; public, which will appear; and system, which is used for unsent messages and other exception reporting. In order for the Message Queues node to be successfully expanded, you need to ensure that MSMQ is installed on your computer. This can be done via Add/Remove Windows Components accessible from Start Settings Control Panel Add or Remove Programs. Some features of MSMQ are only available when a queue is created on a computer that is a member of a domain.

Figure 37-9

In Figure 37-9, the SampleQueue has been added to the Private Queues node by selecting Create Queue from the right-click context menu. Once you have created a queue, you can create a properly configured instance of the MessageQueue class by dragging the queue onto your form. To demonstrate the functionality of the MessageQueue object, use the following code to add a couple of text boxes and a Send button. The Send button is wired up to use the MessageQueue object to send the message entered in the first text box. In the Load event for the form, a background thread is created that continually polls the queue to retrieve messages, which will populate the second text box:

499

Chapter 37

Public Class MessagingForm

Private Sub BtnSend_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles BtnSend.Click

Me.TheQueue.Send(Me.TxtMessageToSend.Text, “Message: “ & _

Now.ToShortDateString & “ “ & Now.ToShortTimeString)

End Sub

Private Sub MessagingForm_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load Dim monitorThread As New Threading.Thread(AddressOf MonitorMessageQueue) monitorThread.IsBackground = True

monitorThread.Start() End Sub

Private Sub MonitorMessageQueue()

Dim m As Messaging.Message While True

Try

m = Me.TheQueue.Receive(New TimeSpan(0, 0, 0, 0, 50)) Me.ReceiveMessage(m.Label, m.Body)

Catch ex As Messaging.MessageQueueException If Not ex.MessageQueueErrorCode = _

Messaging.MessageQueueErrorCode.IOTimeout Then

Throw ex End If

End Try Threading.Thread.Sleep(10000)

End While End Sub

Private Delegate Sub MessageDel(ByVal lbl As String, ByVal msg As String) Private Sub ReceiveMessage(ByVal lbl As String, ByVal msg As String)

If Me.InvokeRequired Then

Me.Invoke(New MessageDel (AddressOf ReceiveMessage), lbl, msg) Return

End If Me.TxtReceived.Text = msg

Me.LblMessageLabel.Text = lbl End Sub

End Class

Note in this code snippet that the background thread is never explicitly closed. Because the thread has the IsBackGround property set to True, it will automatically be terminated when the application exits. Because the message processing is done in a background thread, you also need to switch threads when you update the user interface. This is done via the Invoke method. Putting this all together, you get a form like the one shown in Figure 37-10.

As messages are sent to the message queue, they will appear under the appropriate queue in Server Explorer. Clicking on the message will display its contents in the Properties window.

500

Server Explorer

Figure 37-10

Performance Counters

One of the most common things developers forget to consider when building an application is how it will be maintained and managed. For example, consider an application that was installed a year ago and has been operating without any issues. All of a sudden, requests start taking an unacceptable amount of time. It is clear that the application is not behaving correctly, but there is no way to determine the cause of the misbehavior. One strategy for identifying where the performance issues are is to use performance counters. Windows has many built-in performance counters that can be used to monitor operating system activity, and a lot of third-party software also installs performance counters so administrators can identify any rogue behavior.

The Performance Counters node in the Server Explorer tree, expanded in Figure 37-11, has two primary functions. First, it enables you to view and retrieve information about the currently installed counters. You can also create new performance counters, as well as edit or delete existing counters. As you can see in Figure 37-11, under the Performance Counters node is a list of categories, and under those is a list of counters.

Figure 37-11

501

Chapter 37

To edit either the category or the counters, select Edit Category from the right-click context menu for the category. To add a new category and associated counters, right-click the Performance Counters node and select Create New Category from the context menu. Both of these operations use the dialog shown in Figure 37-12. Here, a new performance counter category has been created that will be used to track a form’s open and close events.

Figure 37-12

The second function of the Performance Counters section is to provide an easy way for you to access performance counters via your code. By dragging a performance counter category onto a form, you gain access to read and write to that performance counter. To continue with this chapter’s example, drag the new .My Application performance counters, Form Open and Form Close, onto your form. Also add a couple of text boxes and a button so you can display the performance counter values. Finally, rename the performance counters so they have a friendly name. This should give you a form similar to the one shown in Figure 37-13.

In the properties for the selected performance counter, you can see that the appropriate counter — in this case, Form Close — has been selected from the .My Application category. You will also notice a Machine Name property, which is the computer from which you are retrieving the counter information, and a Read| Only property, which needs to be set to False if you want to update the counter. (By default, the ReadOnly property is set to True.) To complete this form, add the following code to the Retrieve Counters button:

Private Sub BtnRetriveCountersClick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _

Handles BtnRetriveCounters.Click

Me.TxtFormOpen.Text = Me.PerfCounterFormOpen.RawValue

Me.TxtFormClose.Text = Me.PerfCounterFormClose.RawValue

End Sub

502

Server Explorer

Figure 37-13

You also need to add code to the main application to update the performance counters. For example, you might have the following code in the Load and FormClosing event handlers:

Private Sub MainFormClosing(ByVal sender As Object, _

ByVal e As System.Windows.Forms.FormClosingEventArgs) _ Handles Me.FormClosing

Me.PerfCounterFormOpen.Increment() End Sub

Private Sub MainFormLoad(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Me.Load Me.PerfCounterFormClose.Increment()

End Sub

When you dragged the performance counter onto the form, you may have noticed a smart tag on the performance counter component that had a single item, Add Installer. When the component is selected, as in Figure 37-13, you will notice the same action at the bottom of the Properties window. Clicking this action in either place adds an Installer class to your solution that can be used to install the performance counter as part of your installation process. Of course, for this installer to be called, the assembly it belongs to must be added as a custom action for the deployment project (for more information on custom actions, see Chapter 47).

A word of caution when you have multiple performance counters in the same application: If you try to click the Add Installer shortcut for each of the performance counters, Visual Studio 2005 will simply direct you back to the first installer that was created. It is then up to you to modify this installer to create multiple installers, which can be done by selecting the PerformanceCounterInstaller component on the design surface for the PerformanceInstaller. In the Properties window, selecting the Counters property will open the Collection Editor, shown in Figure 37-14, enabling you to add counters in the same category.

503

Chapter 37

Figure 37-14

You can also add counters in other categories by adding additional PerformanceCounterInstaller components to the design surface. You are now ready to deploy your application with the knowledge that you will be able to use a tool such as perfmon to monitor how your application is behaving.

Services

It’s often necessary to stop and start services while developing an application — for example, you might want to start the SQL Server service if you don’t have it running by default. The Services node, expanded in Figure 37-15, shows the registered services for the computer. Each node indicates the state of that service in the bottom-right corner of the icon. Possible states are stopped, running, or paused, and you can start, stop, or pause a service from its right-click context menu. Some services can’t be paused or stopped, in which case these options will be disabled.

Figure 37-15

504

Server Explorer

As with other nodes in the Server Explorer, each service can be dragged onto the design surface of a form. This generates a ServiceController component in the nonvisual area of the form. By default, the ServiceName property is set to the service that you dragged across from the Server Explorer, but this can be changed to access information and control any service. Similarly, the MachineName property can be changed to connect to any computer to which you have access. The following code shows some of properties and methods that can be invoked on a ServiceController component:

Private Sub ServiceControlClick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _

Handles BtnServiceControl.Click Console.WriteLine(“Service: “ & Me.ServiceController1.DisplayName) Console.WriteLine(“Service Name: “ & Me.ServiceController1.ServiceName) Console.WriteLine(“Type: “ & Me.ServiceController1.ServiceType.ToString) Console.WriteLine(“Machine: “ & Me.ServiceController1.MachineName) Console.WriteLine(“Status: “ & Me.ServiceController1.Status.ToString)

Console.WriteLine(“Can be Paused = “ & _ Me.ServiceController1.CanPauseAndContinue)

Console.WriteLine(“Can be Stopped = “ & Me.ServiceController1.CanStop) Console.WriteLine(“Should be notified on system Shutdown = “ & _

Me.ServiceController1.CanShutdown)

Console.WriteLine(“Service dependent on”)

For Each srv As System.ServiceProcess.ServiceController _

In Me.ServiceController1.DependentServices Console.WriteLine(“< {0} >” & srv.DisplayName)

Next

If Me.ServiceController1.CanPauseAndContinue And _

Me.ServiceController1.Status = ServiceProcess.ServiceControllerStatus.Running Then

Me.ServiceController1.Pause()

Me.ServiceController1.Continue()

End If

If Me.ServiceController1.CanStop And _

Me.ServiceController1.Status = ServiceProcess.ServiceControllerStatus.Running Then

Me.ServiceController1.Stop()

Me.ServiceController1.Start()

End If

End Sub

In addition to the three main states — running, paused, or stopped — there are additional transition states: ContinuePending, PausePending, StartPending, and StopPending. If you are about to start a service that may be dependent on another service that is in one of these transition states, you can call the WaitForStatus method to ensure that the service will start properly.

Summar y

In this chapter you learned how the Server Explorer can be used to manage and work with computer information. The next chapter continues with the Server Explorer, covering the Data Connections node in more detail.

505