Variable and Method Scope in Microsoft

Embed Size (px)

Citation preview

  • 8/19/2019 Variable and Method Scope in Microsoft

    1/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx

    Variable and Method Scope in Microsoft.NET

     Paul D. Sheriff

    PDSA, Inc.

    December 2001

    Summary: This article shows how to define the scope of variables, set the scope of function and sub procedures, and

    how to scope methods in a class in Microsoft .NET. 16 printed pages 

    Objectives

    Learn to define the scope of variables

    Set the scope of Function and Sub proceduresLearn how to scope methods in a class

    Assumptions

    The following should be true for you to get the most out of this document:

    You are familiar with code basics in Microsoft® Visual Basic®

    You are familiar with methods, classes, procedures, and modules

    Contents

    Definition of Scope 

    Variable Scope in Modules 

    Static Variables 

    Variable Scope in Classes 

    Procedure Scope in Modules 

    Procedure Scope in Classes 

    Shared Modifier 

    What's Different From Visual Basic 6.0? 

    Summary

    Definition of ScopeThe scope of a variable, sometimes referred to as accessibility of a variable, refers to where the variable can be read from

    and/or written to, and the variable's lifetime, or how long it stays in memory. The scope of a procedure or method refer

    to where a procedure can be called from or under what context you are allowed to call a method.

    There are many different ways you can declare variables and procedures. How you make these declarations controls the

    scope of variables and procedures. Before you see examples of how each of these different scoping rules can be used,

    let's take a quick look at the terms that you will need to know.

    Table 1. Scoping terms

    http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-http://-/?-

  • 8/19/2019 Variable and Method Scope in Microsoft

    2/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 2

    Term Used With… Visibility

    Public Variables/Properties/Methods/Types Anywhere in or outside of a project

    Private Variables/Properties/Methods/Types Only in the block where defined

    Protected Variables/Properties/Methods Can be used in the class where

    defined. Can be used within anyinherited class.

    Friend Variables/Properties/Methods Can only be accessed by code in

    the same project/assembly.

    ProtectedFriend Variables/Properties/Methods Combination of Protected and

    Friend

    Scope of Variables

    You can declare variables at four different locations in your programs. Where you choose to declare variables determin

    the scope.

    The following table provides the general rules for scope. Be aware that the rules may vary slightly depending on how yo

    declare the variable.

    Table 2. General scoping rules

    Location Description

    Block If you declare a variable within a block construct such as an If  statement, that variable's scope

    is only until the end of the block. The lifetime is until the procedure ends.

    Procedure If you declare a variable within a procedure, but outside of any If  statement, the scope is until

    the End Sub or End Function. The lifetime of the variable is until the procedures ends.

    Module/Class You can declare a variable outside of any procedure, but it must be within a Class…End Class

    or Module…End Module statement. The scope is any procedure within this module. The

    lifetime for a variable defined within a class is until the object is cleaned up by the garbage

    collector. The lifetime for a variable defined within a module is until the program ends.

    Project You can declare a Public variable within a Module…End Module statement, and that

    variable's scope will be any procedure or method within the project. The lifetime of the

    variable will be until the program ends.

    Scope of Properties/Methods

    Procedures can be declared in three locations, within classes, within structures and within modules. You may also assign

    five different modifiers to these procedures to give them different scope.

  • 8/19/2019 Variable and Method Scope in Microsoft

    3/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 3

    Table 3. Procedure modifiers

    Location Description

    Public A Public procedure, when declared within a module, can be called from anywhere within

    the project. A Public procedure, when declared within a class or structure, can be invoked

    from an object declared as the type of that class or structure.

    Private A Private procedure can only be called within the class, structure or the module in which it

    is declared. This means that only other procedures within the same module may call them.

    Protected A Protected procedure may only be declared within a class. Procedures declared within

    the same class can call it, as can other methods in inherited classes.

    Friend A Friend procedure may be accessed from any other code residing in the same

    project/assembly.

    ProtectedFriend A Protected Friend procedure may be accessed from the class it is defined in, a derivedclass, or other procedures in the same project/assembly.

    Variable Scope in ModulesYou will first use the scope of variables as you declare them within a module.

    Block‐Level Scope

    Although you will probably not use this type of scope very often, you are allowed to declare a variable with the Dim

    statement inside of block level constructs such as an If…End If  statement or a Try…End Try statement. This variablemay then only be used inside of this statement block.

    In the Click event procedure above, you declare the variable intValue inside the If  statement. The value is initialized to

    10 and then displayed in a message box. After the End If  statement, if you tried to reference this variable again, you

    would receive a compile‐time error.

    Private Sub BlockTest() Dim boolPerform As Boolean

    boolPerform = True

    If boolPerform Then

    Dim intValue As Integer = 10

    MsgBox("intValue = " & _intValue)

    End If

    ' The following will not work, outside of scope.

    'MsgBox(intValue)

    End Sub

  • 8/19/2019 Variable and Method Scope in Microsoft

    4/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 4

    Procedure‐Level Scope

    The most common place to declare variables is at the top of a procedure. These variables are then available to you

    throughout the procedure. It is a good practice to put variables at the top of your procedure, as you will always know

    where to look for variable declarations in all procedures. If you do not put them all at the top, you never know where

    another variable might be declared, and it might take you longer to track down a bug related to a variable.

    In the above Click event procedure, the variable intValue is declared at the top. Its value is available anywhere within th

    procedure, including within any block constructs.

    Module‐Level Scope

    You might want to use a variable in more than one routine within a program. It can become quite cumbersome to alwa

    have to pass variables from one routine to another via a parameter. Or if you need to keep track of a value between

    invocations of a specific procedure, you need to have a variable that can stay around even after a procedure ends. To

    accomplish these tasks, you need to use a module‐level variable.

    Consider the following module created from the Microsoft Visual Studio® menu by clicking Project, and then clicking

    Add Module.

    In the above module you have created a Private variable called mintLoop. Use "m" as the prefix to indicate that this

    variable is scoped at the module level. This Private variable can now be accessed by any procedure in this module. Both

    the LoopIncrement and LoopDisplay procedures can access and use this variable.

    Now consider the following Click event procedure that is declared in a Form class in another file.

    Private Sub ScopeTest() Dim intValue As Integer

    intValue = 10

    MsgBox("intValue = " & _

    intValue)

    ' After the End Sub, intValue is released

    End Sub

    Module modVar1

    Private mintLoop As Integer

    Public Sub LoopIncrement()

    mintLoop += 1

    End Sub

    Public Sub LoopDisplay()

    MsgBox( _"mintLoop = " & mintLoop)

      End Sub

    End Module

  • 8/19/2019 Variable and Method Scope in Microsoft

    5/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 5

    In this Click event procedure, you can see that the mintLoop variable cannot be used from this routine. If you attempt

    to, you will receive a compile‐time error that this variable is not declared. You can call the LoopIncrement and

    LoopDisplay procedures to change the value and report the value back to this routine.

    Static VariablesStatic variables are supported by Microsoft Visual Basic .NET.

    Project‐Level Scope

    If you wish to have a "global" variable, one that can be seen by any procedure anywhere in your program, you need to

    declare this type of variable as a Public scope in a module somewhere in your program.

    In the module shown above, the gintValue variable is declared as Public. This makes this variable available anywhere in

    your project, or from other projects referencing your project. You can see that the GlobalModuleValue procedure uses

    that variable. In the code below, you can see that a Click event procedure will change this variable, and read it back as

    well.

    Private Sub ModuleTest() ' Can't see the following variable

    ' mintLoop = 10

    ' Can call a routine inside the module

    ' to change the value

    LoopIncrement()

    LoopDisplay()

    End Sub

    Module modVar2

    Public gintValue As Integer

    Public Sub GlobalModuleValue()

      MsgBox( _

    "gintValue = " & gintValue)

    End Sub

    End Module

    Private Sub PublicModuleTest() ' Declared in module, you can change

    it here

    gintValue = 10

    ' You can read it here

    MsgBox("gintValue = " & gintValue)

    ' You can call any procedure anywhere,

  • 8/19/2019 Variable and Method Scope in Microsoft

    6/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 6

    Of course, you'll want to limit the use of global variables. Globals are very hard to keep track of, and you never know

    when another routine is using that value without careful tracking. This can cause a lot of wasted time and effort tracking

    down a bug that is related to the wrong data in the wrong variable at the wrong time.

    Shadowing

    Following some sort of naming standards for your variables can help immensely. Notice in the previous examples, that

    variables declared at the module level used an "m" as the prefix, and global variables used a "g" as a prefix. This naming

    standard can help you quickly identify what scope a particular variable has. Consider the following example:

    In the module modShadow2, a variable named MyLoop is created as an integer. Now look at the module shown below

    modShadow1:

    In the modShadow1 module, you declare another variable called MyLoop. This variable is declared as a Private variable

    so it has module‐level scope. Because this variable has a lower scope than the Public variable declared as MyLoop, any

    time you reference MyLoop in this module, this Private variable is the one you reference. In fact, there is only one

    mechanism you can use to get at the Public variable named MyLoop, and that is by prefixing the module name in whic

    it was declared to the variable. You can see a sample of this in the above code.

      ' and that procedure can see it or change it

    GlobalModuleValue()

    End Sub

    Module modShadow2

    Public MyLoop As Integer = 200

     

    End Module

    Module modShadow1

    ' This variable shadows MyLoop in modVar3

    Private MyLoop As Integer

    Public Sub ShadowTest()

    ' Use the Private variable

      MyLoop = 300

    Msgbox( _

    "MyLoop = " & MyLoop)

    MsgBox( _

    "modShadow2.MyLoop = " & modShadow2.MyLoop)

    ' Change the Public variable

    modShadow2.MyLoop = 500

    MsgBox( _

    "modShadow2.MyLoop = " & modShadow2.MyLoop)

    End Sub

    End Module

  • 8/19/2019 Variable and Method Scope in Microsoft

    7/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 7

    Variable Scope in ClassesLet's look at the different ways you can use scope when declaring variables within a class.

    Public Variables in Classes

    When you build your own classes, you need to create properties. There are two ways you can create properties for a

    class. You can create a Public variable outside of any procedure in the class, or you can create a Private variable and

    create a Property…End Property statement to expose that Private variable. To create a Public variable, you will write

    code like this:

    In the above code, you created a variable called PublicName. Notice that this Public variable is declared outside of any

    procedure in this class. You can now reference that variable through an object that is created as the type PublicTest as

    shown in the code below.

    The above code shows that, unlike a Public variable created in a module, a variable created in a class cannot be used by

    only including its name. Instead, you have to create an instance of the class containing the variable, and then reference

    the variable through the class instance.

    There are a variety of reasons why creating a Public variable in a class is not such a good idea. It does not allow you to

    restrict the access outside the class to read‐only, and it also does not give you the flexibility to put in any error handling

    or range‐checking code. In some properties, you may wish to check values prior to assigning them to a Private variable

    of the class. When you make a variable Public like this, you do not have that capability.

    Private Variables in Classes

    Public Class PublicTest

    Public PublicName As String

    End Class

    Private Sub PublicClassTest() ' PublicName is NOT accessible without

    an object

    'MsgBox("PublicName = " & PublicName)

    ' Now declare an object

    Dim PName As New PublicTest()

    ' You can see the value in PublicName

    MsgBox("PName.PublicName = " & _

    PName.PublicName)

    ' You can assign values to Product Name

    PName.PublicName = "John"

    MsgBox("PName.PublicName = " & _

    PName.PublicName)

    End Sub

  • 8/19/2019 Variable and Method Scope in Microsoft

    8/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 8

    You can declare variables as Private as well as Public outside of any procedures in a class. When you do this, these

    variables can only be read and written to in procedures within the class. This is just like the rules for a Private variable

    within a module.

    In the above class, you can see that the mstrName variable is declared outside of any procedure. It can be read and

    written to within the class, but is not visible outside of the class at all.

    Protected Variables in Classes

    Another type of scope is called Protected. This is a new type of scope in Visual Basic .NET. Protected is similar to Private

    in that it is visible within the class in which it is declared, as shown below.

    A Protected variable can also be seen from within any class that inherits from the same base class.

    Below is an example of another class that inherits from the ProtectedTest class. You can see in the GetCost2 method

    that it accesses the mcurCost variable just like it was a part of this new class. But in fact, it is being inherited from the

    base class.

    Public Class PrivateTest

    ' Can not be seen outside of this class

    Private mstrName As String

    Public Sub NameInit()

    ' Can change mstrName here

      mstrName = "Jane Doe"

    End Sub

    Public Sub NameChange()

    ' Can change mstrName here

      mstrName = "Janie Doe"

    End Sub

    End Class

    Public Class ProtectedTest

    Protected mcurCost As Decimal = 100

    Public Function GetCost() As Decimal

    Return mcurCost

    End Function

    End Class

    Public Class ProtectedInheritance

    Inherits ProtectedTest

    Public Function GetCost2() As Decimal

  • 8/19/2019 Variable and Method Scope in Microsoft

    9/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 9

    Friend

    A variable declared with the Friend access specifier can only be seen by other classes within the same program. Thismeans that if a class has a Friend variable and that class resides in a DLL, then only other classes within the same DLL ca

    see that Friend variable. Any other program that uses that DLL cannot see that variable.

    Protected Friend

    This is a union of the capabilities of the Protected specifier and the Friend specifier.

    Procedure Scope in ModulesYou will next learn how to apply these same keywords, Public, Private, Protected, and Shared, to procedures and

    methods that you write in your application. There are only two scopes that you can apply to procedures within modulesPublic and Private.

    Public Scope

    When you declare a Public procedure Sub or Function  as Public, that procedure can be called from anywhere in your

    entire project. It cannot be called from any other project in your solution. Below is an example of a module that would

    declare within a file in your project.

    Note  You can use the same name for a Public procedure within two different modules. When you call

    that procedure, you must prefix the name with the module name or you will receive a compiler error.

    Private Scope

    When you declare a procedure as Private within a module, only other procedures within that module may call that

    procedure. Consider the following example:

      ' Can still access the variable,

    ' just like it is local

    Return mcurCost

    End Function

    End Class

    Module modProc1Public Sub PublicProc()

    MsgBox( _

    "Hello from modProc1.PublicProc()")

    End Sub

    End Module

    The procedure PublicProc can be called by using the following syntax:

    Private Sub btnPublicMod_Click(ByVal sender As Object, _

    ByVal e As System.EventArgs) Handles btnPublicMod.Click

    PublicProc()

    End Sub

  • 8/19/2019 Variable and Method Scope in Microsoft

    10/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 10

    In the module, modProc2, there are two procedures. One is Public and the other is Private. PublicProc2 can be called

    from anywhere in your project. The PrivateProc procedure can only be called from PublicProc2 because it is declared

    Private. If you add other procedures to this module, you would be able to call PrivateProc from those procedures aswell.

    Privately scoped procedures are typically used as "helper" procedures. These are routines that only do some specific tas

    related to one of the Public procedures within the same module. Although these are not used too often in modules, yo

    will most likely use them quite a bit within classes.

    Procedure Scope in ClassesNow you will learn use scope in methods that you write in your classes.

    Public Scope

    A procedure within a class that is declared as Public can be called from any object of that type of class. Take, for

    example, the listing of code below.

    In the above code, you see a class named PublicMethodTest. Within this class is a Public function called NameGet  .

    The NameGet  method can be called from any object that is declared of the type PublicMethodTest.

    Module modProc2

    Public Sub PublicProc2()

    ' Can call the Private proc from here

    PrivateProc()

    MsgBox( _

    "Hello from modProc2.PublicProc()")

    End Sub

    Private Sub PrivateProc()

    ' Can only be called from within this module

    MsgBox( _

    "Hello from PrivateProc()")

    End Sub

    End Module

    Public Class PublicMethodTest

    Public Function NameGet() As String

    Return "PublicMethodTest.NameGet()"

    End Function

    Private Function PrivateProc() As String

    Return "PublicMethodTest.PrivateProc()"

    End Function

    End Class

  • 8/19/2019 Variable and Method Scope in Microsoft

    11/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 1

    In the above code, you can see that you are allowed to call the NameGet method by prefixing it with the oPublic objec

    variable. Because this variable is created as a type of PublicMethodTest, all Public procedures are available to it.

    Private Scope

    A Private procedure is one that cannot be seen outside of a class module. In the PublicMethodTest class, you saw a

    Private procedure named PrivateProc. This procedure can only be called from a procedure within the same class. If you

    tried to call it from the oPublic variable you declared in the previous code listing, you would get a compiler error.

    Protected Scope

    A procedure that is declared as Protected is similar to a Private procedure in that it can be called from other methods

    within the same class. However, it may also be called from any other classes that inherit the class in which the Protectedprocedure is declared. Consider the following code.

    In the above code, you declared a function called NameGet. This method can only be seen within this class, or any

    inherited class. You can now create an inherited class by typing in code like the following.

    In this PMInheritedTest class, you use the Inherits keyword to retrieve all of the functionality of the

    ProtectedMethodTest class, including any Protected functions. If you then create a Public function called NameRetur

    this method can call the NameGet function.

    Shared ModifierThe Shared keyword is a modifier that may be applied to either a variable in a class or a method inside of a class. If you

    declare a variable with this modifier, that variable will only be created once no matter how many instances of the class

    Private Sub PublicScopeTest() Dim oPublic As New PublicMethodTest()

    MsgBox("oPublic.NameGet() = " & _

    oPublic.NameGet())

    End Sub

    Public Class ProtectedMethodTest

    Protected Function NameGet() As String

    Return "ProtectedMethodTest.NameGet()"

    End Function

    End Class

    Public Class PMInheritedTest

    Inherits ProtectedMethodTest

    Public Function NameReturn() As String

    Return NameGet()

    End Function

    End Class

  • 8/19/2019 Variable and Method Scope in Microsoft

    12/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 12

    are created. If you access this variable from any instance, or change this variable from any instance, then the value will b

    the same across all instances. A method declared as Shared can be called without creating an instance of that class.

    Think of the MessagBox.Show method. You do not have to create a MessageBox object, you just use the Show

    method.

    Shared Variables in Classes

    A shared variable is created just once for any objects that are declared of a certain class type. One common use of a

    Shared variable is when you wish to keep track of how many objects of a certain class type are currently declared. To do

    this, you use the keyword Shared in front of any variable that you wish to expose as a property of a class.

    In the SharedMemberTest class, you create a Public variable called NumInstances and identify it is as a Shared

    variable. This means that only one memory location is allocated for NumInstances. There is no individual memory

    location for each object instance.

    In the constructor, you increment this variable value by one. Each time a new object is created, the variable increases in

    value. As an example, you could now write some code like the following to create a couple of different variables of thetype SharedMemberTest.

    Public Class SharedMemberTest

    Public Shared NumInstances As Integer

    Public Sub New()

    NumInstances += 1

    End Sub

    Public Sub Dispose()

    NumInstances ‐= 1

    End Sub

    End Class

    Private Sub SharedTest()

    Dim oShared1 As SharedMemberTest _

    = New SharedMemberTest()

    MessageBox.Show("oShared1.NumInstances = " & _

    oShared1.NumInstances.ToString())

    Dim oShared2 As SharedMemberTest _

    = New SharedMemberTest()

    MessageBox.Show("oShared2.NumInstances = " & _

    oShared2.NumInstances.ToString())

    MessageBox.Show("oShared1.NumInstances = " & _

    oShared1.NumInstances.ToString())

    ' Call Dispose to decrement the # of instances

    oShared1.Dispose()

  • 8/19/2019 Variable and Method Scope in Microsoft

    13/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    https://msdn.microsoft.com/en-us/library/ms973875(d=printer).aspx 13

    Notice that you create the first variable, oShared1, and when you display the NumInstances property, it displays a 1.

    After creating the oShared2 object, the NumInstances property is incremented, so it now contains a 2. You can prove

    this by once again displaying the NumInstances property from the oShared2 and the oShared1 variables to see that a

    2 is displayed.

    It is good coding practice to call a Dispose method on the object prior to the object going out of scope. This allows yo

    to decrement the NumInstances property for each object that will be destroyed. If you do not do this, the

    NumInstances property may continue to report a 3, as the garbage collector may take a while before it cleans up all

    instances of these objects.

    Shared Methods

    When you use the Shared keyword as part of a Public method in a class, that procedure can be called just by prefixing

    the name of the method with the class name. There is no need to create an object of the class. Consider the following

    class declaration.

    In the MyBox class, you create a Public Shared Sub named Show. This method can now be called, as shown in the

    following code:

    As you can see in the above code, you used the Show method in the MyBox class without creating an object variable

    first. This type of method can come in very handy. This class/method can be used anywhere throughout your project an

    any projects that you include this class within.

    There are a couple of items you must be aware of when using the Shared keyword in conjunction with methods in a

    class. 1 . You may not reference any variable or method using the Me, MyClass or the MyBase keywords. This makes

    sense since these assume an instance has been created, when in fact, none has. 2 . No shared method may use the

    modifiers Overridable, NotOverridable, or MustOverride keywords.

    What's Different From Visual Basic 6.0?There are quite a few changes to how you can change the scope of variables, functions, and methods in Visual Basic .N

    compared to Visual Basic 6.0.

      oShared2.Dispose()

    End Sub

    Public Class MyBox

    Public Shared Sub Show(ByVal strValue As String)

    MsgBox(strValue)

    End Sub

    End Class

    Private Sub SharedMethodTest()

    MyBox.Show("Hi There")

    End Sub

  • 8/19/2019 Variable and Method Scope in Microsoft

    14/14

    1/4/2016 Variable and Method Scope in Microsoft .NET

    Here are some new ways of doing things that had no equivalent in previous versions of Visual Basic.

    You may now declare variables within a block of code.

    You now have a Protected scope of properties and methods.

    You may declare a variable within a class as Shared.

    One thing has changed from previous versions of Visual Basic:

    You now declare a method as Shared instead of setting a property on a class as Global Multi‐Use.

    Visual Basic .NET has also removed one way of doing things:

    Static variables can no longer be declared. You must use module‐level variables instead.

    SummaryIn this document, you learned the different rules of scope as they apply to variables and procedures. There are many

    different rules that you need to keep in mind as you develop your applications. A general guideline for scoping variable

    is that you want to keep the scope of variables as local as possible. Avoid global variables as much as you can, as this w

    lead to fewer errors in your programs. As far as procedures go, you simply need to decide which scope to use based on

    your particular needs.

    About the Author

    Paul D. Sheriff  is the owner of PDSA, Inc., a custom software development and consulting company in Southern

    California. Paul is the MSDN Regional Director for Southern California, is the author of a book on Visual Basic 6 called

    Paul Sheriff Teaches Visual Basic, and has produced over 72 videos on Visual Basic, SQL Server, .NET and Web

    Development for Keystone Learning Systems. Paul has co‐authored a book entitled ASP.NET Jumpstart. Visit the PDSA,

    Inc. Web site www.pdsa.com  for more information.

    About Informant Communications Group

    Informant Communications Group, Inc. www.informant.com  is a diversified media company focused on the informatio

    technology sector. Specializing in software development publications, conferences, catalog publishing and Web sites,

    ICG was founded in 1990. With offices in the United States and the United Kingdom, ICG has served as a respected

    media and marketing content integrator, satisfying the burgeoning appetite of IT professionals for quality technical

    information.

    Copyright © 2001 Informant Communications Group and Microsoft Corporation

    Technical Editing: PDSA, Inc.

    © 2016 Microsoft

    http://service.bfast.com/bfast/click?bfmid=43945&sourceid=0039384188&bfpid=0672323575&bfmtype=Bookmailto:[email protected]