inside ms vb 6

Upload: suhail-qadir

Post on 05-Apr-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/31/2019 Inside MS VB 6

    1/16

  • 7/31/2019 Inside MS VB 6

    2/16

  • 7/31/2019 Inside MS VB 6

    3/16

    January 2005www.elementkjournals.com

    tify the current form as the parent. Finally, we used aBoolean variable to make sure the splash screen firesonly once.

    Note: If you do need a splash screen to fill timebefore your form loads, instead of using the formsActivated() event, add the code that creates andshows the form below the call to InitializeCompo-nent() in the New() method. This loads the splashscreen before loading the form. Also, be sure to usethe plain Show() method and call Me.SendToBack() inthe Activated event of the main form.

    Varying the splash screen dataIf you were to press [F5] and launch the program,youd probably see your bare-bones splash screenfollowed by the empty default form. However, ifyou recall, we hard-coded the version number in thesplash form. In Visual Basic 6, you can keep yoursplash screen data fresh using the App class. In Visual

    Basic .NET, you have the Application class.

    Using the Application classJust like the App class, the Visual Basic .NET Applica-tion class contains information about the application,such as current version, company name, and appli-cation name. However, unlike Visual Basic 6, youcant set this information using the project properties.Although .NET keeps the version up to date for you,youll have to manually set the other values, such asApplication.ProductName, in the AssemblyInfo.vb file,as weve done in Figure C.

    Passing the dataOnce you create a new instance of a form, you havefull access to all public members of that form, includ-ing variables and controls. This means you can set thesplash forms application information labels usingthe actual label names or the global public variableswe assigned to the labels. For example, to set the ver-sion label, place the next line of code immediatelyabove the showDialog call:

    frmSplash.setVersion = Application.ProductVersion

    Figure D shows our sample screen with the versionnumber we obtained from .NET. If youd like to

    shorten the amount of time the splash screen dis-

    plays, use the setTimer variable to assign a smallernumber of milliseconds to the Timers Intervalproperty.

    Splashy first impressionsIn this article, weve shown you how easily youcan create a splash screen for your .NET applica-tion. Although some users and developers frown onsplash screens, theyre still an excellent way to intro-duce your application and keep the user aware ofthe current version and licensing information. Justkeep the design simple and the display time short,

    and your splash screen is sure to make a great firstimpression.

    Shaping up splash screensFor a truly unique splash screen, leverage the powers of GDI+ to cre-

    ate shaped forms with three sides, five sides, or no sides at all. You

    can even mold your form into a string of text. To discover how, check

    out the August 2004 article Whip VB .NET forms into shape with

    GDI+ objects and methods.

    Figure C: Modify the AssemblyInfo.vb file to store an important

    application.

    Figure D: Passthe applicationinformation to thsplash screen tokeep it fresh and

    up to date.

    Meet people, get advice, find resources, shareideas, and make friends! You and your fellow EKJForum members create the contentreal, current,

    and always changing. Moderated by our expert edi-

    tors, there are many different EKJ Forums to choosefrom. Check them out today!

    Visit The EKJ ForumsElement K

    Journals NEW bulletin boardsGo to www.elementkjournals.com/forums

  • 7/31/2019 Inside MS VB 6

    4/16

    Inside Microsoft Visual Basic4

    W hen your program needs to read or manipulate files from another program,

    its nice if the files are in text or a standard data format. But sometimes yourcode will have to make sense of a binary file. For instance, if your software

    replaces or supplements a legacy program that uses a proprietary data format and has noadequate import/export capability or API, you may wonder how youre going to get thedata. Some people just throw up their hands and re-enter records by hand. Of course, ifthe file in question is in a standardized binary format, such as MIDI for music or JPEG for

    graphics, APIs and ready-made COM objects often exist to interpret these files for you. But even then, youmay want the flexibility to alter the file in ways the makers of the ready-made solutions didnt anticipate.

    But, while its easy to obtain documentation on the basics of working with binary files, its harder to

    find rich, real-world examples written in Visual Basic. So, well present a case study for you involving thesimplified Musical Instrument Digital Interface (MIDI) processor shown in Figure A to give you a realisticoverview of whats involved.

    Deftly decipher binary files, part 1: Dataformats in a MIDI headerby Jonathan Rabson

    Application: Microsoft Visual Basic 6

    Download: http://download.elementkjournals.com/vbasic/200501/midi.zip

    VB Classic

    A MIDI case studyIn this article, well focus on some key techniques forworking with binary formats. The main commandswell use are Open, Close, Get, and Seek. While youll seethe syntax of these commands in action through somesimple examples, well focus on the process of work-ing with binary files. Well start with a comparisonbetween the simple table-structure files you might

    find under Help and the more complex binary filesyou may need to deal with on the job.

    To give you the flavor of real-life binary formats,we created a bare-bones utility that reads simple filesin the MIDI format. While our utility, which you canobtain by downloading the file midi.zip from theURL listed at the beginning of the article, simplifiesthings quite a bit (i.e., it assumes theres one track,no instructions on what instrument to use, no pedal-ing, and none of what the MIDI standard calls systemexclusive messages), it does demonstrate basic tech-niques. For instance, well use our example to showhow to work with various forms of data, such asbytes, unsigned integers, and signed integers. Wellalso show how handy the And operator is for work-ing with binary data. Although well only be readingfiles, the concepts we cover will be crucial if you wantto go to the next step and add data to a file, repaircorrupted files, or change files in ways not possiblethrough existing software.

    Note: This article contains many binary terms that,if youve never worked with binary files or havent

    worked with them since your teenage years, mayseem unfamiliar. For this reason, weve provided abinary cheat sheet of sorts in the article Key binaryterms every developer should know, which youllfind in this months issue.

    Binary files using table structuresThe Visual Basic binary file examples youre liable toencounter generally make the assumption that the fileis constructed of segments that share the same organ-ization, much like rows (or records) in a database

    Figure A: Knowing how to work with binary files in VisualBasic enables you to write a utility that makes sense of the bytesin a MIDI music file.

  • 7/31/2019 Inside MS VB 6

    5/16

    January 2005www.elementkjournals.com

    table. For instance, a typical example may involvea file for storing sales items, containing a series ofrecords that each store a sequence of fields, such asID, item name, category number, and priceeachstored using a particular data type that Visual Basicsupports (Integer, String, etc.).

    Given this scenario, you can create a user-definedtype similar to the following:

    Public Type SalesItems

    ID As Integer

    ItemName As String

    CatNumber As Integer

    Price As Currency

    End Type

    You can then dimension a variable of that type andan array to hold instances of that variable:

    Dim StoreItems As SalesItems

    Dim arrayItems() As SalesItems

    Dim lCount As Long

    Doing so enables you to read the data in chunks, onerecord at a time, into your array, like so:

    Open c:\store.texmex For Binary _

    Access Read As #1

    While LOF(1) > Loc(1)

    ReDim Preserve arrayItems(lCount)

    Get #1, , StoreItems

    arrayItems(lCount) = StoreItems

    lCount = lCount + 1

    WendClose #1

    Typical complexities in real-world examplesA reasonable question is: Are the binary files youencounter in real life going to be like that? The answeris yes and no. Clearly, a table structure is an extraor-dinarily useful way of organizing binary files, andits a good place to start if you have to decipher anundocumented file format for storing tabular infor-mation. But it isnt the only possible approach. Binaryfiles in real life may be more complicated. Often theyhave some sort of header identifying the file as a cer-tain type, and they may have footer information. Inaddition, there may be a number of different sub-organizations within the filesimilar to having manydatabase tables instead of one. And since one of the

    What defines the structure in a binary file? You!If youre new to working with binary files, you may wonder whats

    inside the file that says when a field or record ends, or what the data

    type is. The answer is, typically nothing. Certain data, such as a variable-

    length string, may do something special on the last byte to show whenthat piece of data ends; and some data may instruct your code on how

    to read other data. But typically, binary files dont reveal their structure

    the way comma-delimited and XML files do. After all, one of the main

    reasons for using binary is to pack information into a small space. So,

    the only thing that determines how to interpret the file is your code

    following whatever format youve devised, or whatever specification

    documentation youve gotten from a company or downloaded off the

    internet. In other words, if your code expects the next four bytes to con-

    stitute what Visual Basic calls a Long data type, thats what youll get.

    Of course, if youre one byte off so what youre reading is intended to

    represent something completely different, Visual Basic wont complain

    (as long as there are bytes to read). However, the data you get probably

    wont be very useful.

    Table A: Header information in a MIDI file

    Number of bytes Information stored What your code is supposed to interpret it as

    4 Chunk type Fixed-length string; should spellMThd in a valid file, whichmeans that this chunk of data is a header

    4 Length Unsigned integer (usually 6), signifying how many bytes arein the header

    2 Format Unsigned integer

    2 Number of tracks Unsigned integer2 Division If leftmost bit is 0: Unsigned integer

    If leftmost bit is 1: Leftmost byte signed integer*, rightmostbyte unsigned integer

    Variable Unknown (provided forfuture expandability)

    Skip over number of bytes as determined by the Length (rowtwo in this table) minus 6

    *Technically, only the seven bits to the right of the first bit form the signed integer for what MIDI calls SMPTE format (Society of Motion

    Picture and Television Engineers). But, if the leftmost bit is 1, taking the next seven bits as a signed integer is mathematically equivalent to

    taking all eight. Similarly, if the leftmost bit is 0, taking the entire two bytes is the same as taking only the rightmost 15 bits.

  • 7/31/2019 Inside MS VB 6

    6/16

    Inside Microsoft Visual Basic6

    main uses for binary files is to store information com-pactly, there may be certain rules whereby a field maybe skippedsort of like a database table with a dif-ferent number of filled columns in each row. Finally,the data may not correspond to any data types thatVisual Basic provides. In which case, youd need tointerpret the data yourself from the bytes, followingthe documentation you have for the file structure.

    Organizations of data you may encounterOne of your first tasks for interpreting data from abinary file is to set up any code youll need to callrepeatedly, such as the SalesItems type we created inthe previous example. However, in many cases, yoursetup activity will be quite a bit different. For exam-ple, consider the MIDI specification. MIDI files startwith a header, which follows the format specified inTable A on the previous page. A few things stand outin the table. First, some of the information is in theformat of unsigned integers, which dont correspond

    to any data type in Visual Basic. Second, if yourewriting a program to read such a file, there are condi-tional decisions your code has to make to determinehow to proceed.

    Taking a byteThe most basic task youll need to complete is grab-bing a byte of data. This way, if you need data thatdoesnt correspond to any Visual Basic data type, youcan always construct what you need from the bytes.Listing A shows a ready-made function that allowsyou to grab a byte from any position in a file. Thisfunction takes two arguments:

    intF is the file number you used in the Open statementto open the file.

    lPos (included for flexibility in case you want toskip to a byte) is the byte in the file to start at (e.g.,1 if youre reading the file from the beginning, 9 ifyouve read 8 bytes so far and want to read the nextone). TakeAByte() uses the Seek() function to findwhat the next byte is if you havent specified lPos.

    Reading unsigned integersNext, well look at the concept of an unsigned inte-ger. The distinction between signed and unsigned maynot make a difference for the small numbers youllusually encounter in MIDI headers, but the conceptis fundamentaland its something youll need toknow to deal with the rest of a MIDI file or to workwith other binary formats.

    Visual Basics Integer and Long types representsigned integers; that is, they can be positive ornegative. To represent both positive and nega-tive numbers, computers generally use the twoscomplement system, meaning simply that youcount the largest bit negatively. For instance, con-sider a typical 16-bit signed integer. (Well con-sider a generic case, not a Visual Basic Integer,since theres a slight complication, which youllsee soon.) The rightmost, or 0th bit, represents 1 ifin the on position. Any other bit n in the on posi-tion represents 2n, with the exception of the left-

    most (15th

    ) bit, which represents not 215

    , but -215

    .So, 1,000,000,000,000,011 represents -32,765 (i.e.,-32,768 + 2 + 1). In contrast, in a 16-bit unsignedinteger, the leftmost bit represents 215meaningthat 1,000,000,000,000,011 represents 32,771 (i.e.,32,768 + 2 + 1). The idea of inverting the largest bit(also known as the most significant bit, or MSB) torepresent signed integers is a great way to simplifythe algorithm the computer uses to add numbers.Unfortunately, it can pose problems if your fileformat specifies unsigned integers and youre try-ing to interpret these with signed data types.

    There are three valid strategies for dealing with

    unsigned integers in Visual Basic:

    Use deduction to determine that the data willlook the same whether you interpret as signed orunsigned.

    Loop through the bytes to generate the number.

    Mathematically convert from a signed integer.

    Simplifying through deductionThe first approach may be reasonable for simpleapplications. For example, if you know from the

    data that your two bytes will only represent a posi-tive integer less than 215, or your four bytes repre-sent an integer less than 231, then there shouldntbe any difference between signed or unsigned. Inthat case, you might consider grabbing data usingMicrosofts native types, and later doing what-ever mathematics are required to implement thespecified logic for any of the data. Accordingly, youmight consider extracting the information similarlyto the way we did the SalesItems example, using thefollowing user-defined type:

    Listing A:Function to take a byte

    Public Function TakeAByte(intF As Integer, _Optional lPos As Long = 0) As Byte

    Dim bytByte As Byte

    If lPos = 0 Then

    lPos = Seek(intF)

    End If

    Get #intFile, , bytByte

    TakeAByte = bytByte

    End Function

  • 7/31/2019 Inside MS VB 6

    7/16

    January 2005www.elementkjournals.com

    Type Header

    ChunkType As String * 4

    Length As Long

    Format As Integer

    NTracks As Integer

    Division As Integer

    End Type

    There are three big problems with this, however:

    If a file violates your assumptions, you may end upwith a bug at the most inconvenient moment.

    Visual Basics Long and Integer types store theirbytes with the MSB on the right (i.e., the bytes foran Integer 1 are 10, not 01); whereas, in MIDI, its onthe leftanother complication.

    In our experience, reading and writing with a user-defined type all at once wont give you the bytes inthe order you expect. Reading files with individualvariables (or individual members of a Type) gives

    you more control and predictability.

    Counting byte by byteAn alternative approach you can take is to simply addup the bytes yourself. While this isnt the best approachperformance-wise, it isnt bad because in practice wereonly looping up to four times. This is also the best wayto illustrate whats happening, and its the most flex-ible method, allowing you to read a number whetherits 1, 2, 3, or 4 bytes. To use this approach, simply copythe function shown in Listing B.

    This function takes three arguments, includ-ing two similar to our TakeAByte() function, and anargument called intLen containing the number ofbytes for representing the number. To understandhow this function works, remember that each nextbyte (counting back from the right) represents eightplaces (bits) over from the last byte, so the value ofeach next bytes bits is 28 (i.e., 256) times the bits ofthe previous byte. Of course, since we get the datafrom left to right, we start with the highest numbersfirst. We know the number of bytes from intLen, sowe can simply populate the variable lCount to repre-sent the appropriate exponent of 256, and loop backusing Step - 1.

    Certainly, this simplified example is far from per-fect because were still using Long, so we really onlyget the data for 378 bytes. A 4-byte unsigned integercan be as large as 4,294,967,295; whereas, ours canonly be 2,147,483,647. To get around that, you mayneed to store the results as Currencyor as arrays of

    bytes, using your own algorithms for any calcula-tions you need to do.

    Converting from signed to unsignedPerhaps the most elegant solution for dealing withunsigned integers is to use mathematical calcula-tions to convert data types where necessary. (Wewont tackle reversing byte order purely via mathhere, but well discuss some conversions using sim-ple arithmetic.) For instance, suppose you use anInteger to represent the number of tracks. To accountfor the possibility (albeit unlikely) of 32,768 or moreMIDI tracks, you could convert the Tracks number

    to a Long using the function shown in Listing C. Ifthe leftmost bit is 1 (representing 32,768), we addtwice that amount (65,536) to flip it from negativeto positive. We represent the number as a Long, sincewe know a Long has more than enough room to rep-resent a 2-byte unsigned integer. Listing D on thenext page is similar, but converts an unsigned inte-ger to the corresponding signed integer that uses thesame pattern of bits.

    Listing B:Function to read unsigned integers byte by byte

    Public Function _

    ReadFixdLenPosNum(intF As Integer, _

    intLen As Integer, _

    Optional lPos As Long = 0) _

    As Long

    Dim lCount As Long

    Dim bytByte As Byte

    Dim lResult As Long

    If lPos = 0 Then

    lPos = Seek(intF)End If

    lResult = 0

    For lCount = intLen - 1 To 0 Step -1

    Get #intF, lPos, bytByte

    lResult = lResult + (bytByte * 256 ^ lCount)

    lPos = Seek(intF)

    Next lCount

    ReadFixdLenPosNum = lResult

    End Function

    Listing C: Function to convert a signed Integer to anunsigned Long

    Public Function _

    IntToUnsignedLong(intSigned as Integer) As Long

    If (intSigned And 32768) > 0 Then

    IntToUnsignedLong = intSigned + 65536

    Else

    IntToUnsignedLong = intSigned

    End If

    End Function

  • 7/31/2019 Inside MS VB 6

    8/16

    Inside Microsoft Visual Basic8

    Using And to compare bytes and extractdata from larger chunksOne important technique in Listings C and D isthe use of the And operator. If the variables x and yrepresent numbers, then the expression (x And y)returns the number youd form by taking all thebits that are the same in both x and y. This means

    that if you want to know if a number contains acertain bit (i.e., power of 2), you can use And, asshown in the listings.

    Another use of And is to extract data from alarger chunk that youve already collected. Forexample, consider the second to last row of TableA, which specif ies what the MIDI standard callsthe Division. Suppose youve extracted that infor-mation either by using the Integer data type andconverting to unsigned using our IntToUnsigned-Long(), or by calling our ReadFixdLenPosNum() func-tion. In either case, you have more work to do,because the standard says youre supposed to

    read the leftmost bit and then interpret the rest ofthe data accordingly.

    Listing E demonstrates one way to do this. Simplyfeed your MIDI header values into an object youvedefined with a class module, and use a Property Let toperform any remaining calculations. In our PropertyLet, we store the raw value to a module-level vari-able for future reference. Then we compare the value

    with 215 to see what the first bit is. If the leftmost bitis 1, we set a property in the class to signal that thedata is stored using the second of the two possibili-ties shown in Table A for Division.

    You can see from the table that the leftmost byteis supposed to be a signed integer and the rightmostan unsigned integer. Now heres the clincher: To getthe rightmost (i.e., lowest value) byte, we simply take(lVal And 255). The 255 value is the sum of the bitsin a byte (mathematically, 20 + 21 + 22 + +2n-1 =2n - 1). So that gets us our second byte. We subtractto get the first byte, which we convert back to twoscomplement notation. (We cant use CInt() to do thatbecause were working with numbers in Visual Basic,not with memory directly.) Of course, we could prob-ably make this more elegant so we arent convertingto an unsigned integer and then back to a signed one,but the process here is more useful for demonstrationpurposes. (In most MIDI files, the leftmost bit is 0anyway.)

    Warning: When you use And and other similaroperators to compare or manipulate bits, makesure your expression results in the correct datatype and has parentheses as needed. Consider the

    following incorrect versions of the If statementfrom Listing C:

    If intSigned And 32768 Then

    If intSigned And 32768 > 0 Then

    The first always acts as if the expression is False,because the expression returns a number insteadof a Boolean. Visual Basic reads the second as if itsaid this:

    If intSigned And (32768 > 0) Then

    Having taken the first byte While weve only begun the journey of reading aMIDI file, weve highlighted much of the conceptualterritory youll need to work with binary files. Nodoubt, some files you work with will have more com-plex or unique ways of representing data. However,once youre able to extract bytes, write functions tointerpret data from a file, and use math to convertdata in any way you need, youll have little problemreading or editing just about any binary format.

    Listing D: Function to convert from unsigned to signed

    Public Function ConvertPosToTwosComp(lNum As Long, _

    Optional intBits As Integer = 16) As Long

    Dim lTwosComplement As Long

    Dim lMSBValue As Long

    lMSBValue = 2 ^ (intBits - 1)

    If (lNum And lMSBValue) > 0 Then

    lTwosComplement = (lNum - lMSBValue)

    ConvertPosToTwosComp = -lMSBValue + _

    lTwosComplement

    Else

    ConvertPosToTwosComp = lNum

    End If

    End Function

    Listing E: Using And to extract data

    Public Property Let Division(lVal As Long)

    lModDivision = lVal

    Dim lFirstByte as long

    If (lVal And (32768)) > 0 Then

    UsesSMPTEFormat = True

    TicksPerFrame = (lVal And 255)

    lFirstByte = lVal - TicksPerFrame

    SMPTECodes = ConvertPosToTwosComp( _

    lFirstByte, 8)

    Else

    UsesSMPTEFormat = False

    TicksPerQuarterNote = lVal

    End If

    End Property

  • 7/31/2019 Inside MS VB 6

    9/16

    January 2005www.elementkjournals.com

    Binary file. A file not intended for interpretation astext, usually containing some bytes of funny-lookingcharacters when viewed in a text editor. Binary files

    conserve space by making full use of every possiblevalue a byte can represent, not just the values thatcorrespond to readable characters.

    Binary number. A number in base two. You canconvert to regular base 10 numbers by multiplyingthe digits by 2n, where n is the number of places fromthe right, starting at 0.

    Bit. The fundamental unit in computer storage, havingan on and off position represented respectively as 1and 0. You can interpret a sequence of bits as a binarynumber.

    Byte. A sequence of eight consecutive bits, capableof representing 256 different values; also, a datatype in Visual Basic for storing a byte and a unit formeasuring computer memory.

    Fixed-length. A word, group of words, or datatype that always contains the same number of bitsor bytes; any unused portion usually shows up as0s. For instance, the Long data type always takes upfour bytes in Visual Basic, so the number 1 has onebit set to 1 and 31 bits set to 0. Fixed-length data canwaste space if some of the data requires less than theamount specified.

    Least significant bit (LSB). The bit representingthe smallest power of two (i.e., 20, which is 1) in asequence of bitstypically the rightmost bit.

    Most significant bit (MSB). The bit representingthe largest power of two in a sequence of bitstypically the leftmost bit. For instance, in a 4-bit

    sequence, the leftmost bit is the most significant bitand represents 23, so the sequence 1,000 stands forthe number 8.

    Signed. A number format where negative numbersare possible.

    Text file. A file whose bytes are intended forinterpretation as readable characters. For instance,the bit sequence 01000001 is 64, which, in a text file,represents the letter A.

    Twos complement. A system for representingnumbers in which the most significant bit is

    counted negatively. It gets its name because youcan make the number negative by flipping (i.e.,complementing) each bit and adding 1. The partof the number other than the most significant bitis also called the twos complement.

    Unsigned. A number format where only positivenumbers are possible.

    Variable length. A word, group of words, or datatype that can contain different amounts of memoryin different situations. For instance, the String datatype in Visual Basic is variable length, unless you

    specify a fixed length. Using variable length datacan save space, but it requires extra processing toread, since the code must interpret how long thedata is.

    Key binary terms every developer should knowby Jonathan Rabson

    Avoid duplicate coding: Place common classesin a .NET class libraryby Matthew MacDonald

    Application:Microsoft Visual Basic .NET

    Download: http://download.elementkjournals.com/vbasic/200501/classlibrary.zip

    Its no secret that applications often need to share functionality. For example, you might build a web pageand a Windows application that both need to access the same database component to retrieve a productcatalog. In the world of .NET, you solve this problem by building a shared class library. The class library,

    when built, becomes a separate DLL file that any other .NET application can use, regardless of its language.Best of all, there are absolutely no versioning or configuration headaches, thanks to .NETs newfound loveof metadata.

  • 7/31/2019 Inside MS VB 6

    10/16

    Inside Microsoft Visual Basic10

    Listing A:A class for encrypting data to a file

    Imports System.Security.Cryptography

    Imports System.IO

    Public Class FileEncryptor

    Private Crypt As New RijndaelManaged()

    Public Sub New(ByVal password As String)

    (Code for initializing object omitted.

    End Sub

    Public Sub EncryptFile(ByVal filePath As _

    String, ByVal data As String)

    Open a file for writing.

    Dim fs As New FileStream(filePath, _

    FileMode.Create)

    Set up the encryption.

    Dim Transform As ICryptoTransform = _

    Crypt.CreateEncryptor()

    Dim cs As New CryptoStream(fs, _

    Transform, CryptoStreamMode.Write)

    Encrypt and write the data.

    Dim w As New StreamWriter(cs)w.Write(data)

    w.Flush()

    cs.FlushFinalBlock()

    w.Close()

    End Sub

    Public Function DecryptFile(ByVal filePath As _

    String) As String

    Open the file for reading.

    Dim fs As New FileStream(filePath, _

    FileMode.Open)

    Set up the decryption..

    Dim Transform As ICryptoTransform = _

    Crypt.CreateDecryptor()

    Dim cs As New CryptoStream(fs, _

    Transform, CryptoStreamMode.Read)

    Read and decrypt the data into a string.

    Dim r As New StreamReader(cs)

    DecryptFile = r.ReadToEnd()

    r.Close()

    End Function

    End Class

    A class actIn this article, youll see how you can use Visual Stu-dio .NET to quickly build your own class library.Youll learn the rules you need to follow to build anddeploy class libraries to the clients that use them. Bestof all, youll find that all of these steps are much sim-pler than they were with traditional Visual Basic 6and COM programming.

    Class libraries 101Technically, a .NET class library, or component, isnothing more than a collection of one or moreclasses compiled together as a unit. For example,when you install .NET, you install just over a dozenMicrosoft-authored assemblies that provide all thetools youll use for building Windows applications,web applications, connecting to a database, readingfiles, and so on.

    The most important thing to understand abouta class library is that a user cant directly launch it.Instead, a class library groups together some relatedfeatures that another .NET application uses.

    Class libraries have many benefits. Most impor-tantly, they allow you to create pluggable applica-tions, where you can debug, enhance, replace, andmodify components individually without having torebuild the entire application. Theyre also a greatway to reuse code in different applications.

    Creating a basic class libraryTo create a new class library project in Visual Studio.NET, follow these steps:

    1. Select File | New | Project from the menu, if youarent already at the New Project dialog box.

    2. Under the Visual Basic group, choose ClassLibrary.

    3. Choose your directory and project name (just asyou would with any other project), and click OK.

    By default, youll start off with one class file,although you can add as many classes or modulesas you want. Inside your class library, you can putthe same code you would use in a Windows or webapplication. The difference is that you wont interactwith user interface at all. Instead, youll write func-tions that read files, retrieve data from databases,perform calculations that are specific to your busi-ness, and so on.

    Accessing classes with shared methodsThere are two basic ways you can design classes.You can use shared methods, in which case the user

    can call the method without needing to create anobject. Heres an example of a class with a sharedmethod:

    Public Class AccountUtility

    Public Shared Sub Deposit( _

    acctID As String, amount As Decimal)

    (Code omitted.)

    End Sub

    End Class

  • 7/31/2019 Inside MS VB 6

    11/16

    January 2005www.elementkjournals.com

    The next line of code shows how the client mightcall this method. Notice that you use the name of theclass, rather than creating a new object:

    AccountUtility.Deposit(342-42, 34.99)

    Accessing classes through an instanceYou can also use normal instance methods to access

    a class. As you might expect, in this case your codeneeds to create an instance of the class before it canuse it, like so:

    Dim objAU as new AccountUtility

    Thats the approach well adopt in the next example.

    Building a simple classTo understand class libraries, it helps to consider asimple component. Listing A shows portions of asample class that consists of two instance methods.These methods allow you to encrypt data and store itin a file, or decrypt data and retrieve it from the file.

    Note: For a complete listing of our test program,navigate to the URL listed at the beginning of thearticle and download classlibrary.zip.

    This component is useful, because it combines twotasks: cryptography and file I/O. (In a full-fledgedapplication, you might take even more steps, such asvalidating the data.)

    Note that when you create an instance of the File-Encryptor class, you need to supply the password you

    want to use. If you dont use the same password toread data as you used to write it, youll receive scram-bled information. This makes the FileEncryptor class ahandy way to keep information safe from prying eyes!

    Once youve perfected your class library, you canbuild it. (Just right-click on your project in the Solu-tion Explorer and choose Build.) Visual Studio .NETwill compile all your code into a single DLL assemblyfile. However, before you can actually test this classlibrary component, youll need to build an executableapplication, as we describe in the next section.

    Creating a patron for your libraryAny .NET application can use your class library, evenif its written in another language. (This makes per-fect sense, of course, as all the .NET libraries are writ-ten in C#, and theyre easily usable in Visual Basic.NET programs.)

    To create a client for your class library, followthese steps:

    1. Open an existing project or create a new WindowsApplication.

    2. Right-click on References in the Solution Explorer,and choose Add Reference. Then, click the .NETtab. Dont bother searching through the list pro-vided for you; it corresponds to all the assembliesin the GAC (Global Assembly Cache), not the pri-vate assemblies designed for internal use.

    3. To add your reference, click the Browse button at

    the .NET tab, and hunt for the DLL file from yourclass library project.

    4. Once youve chosen the right file, click OK tocontinue.

    Visual Studio .NET copies the DLL file to the bindirectory of the current project. This is an importantfact to remember, because any new changes in yourclass library project wont be available in your cli-ent project until you copy the newly compiled DLLfile and overwrite the previous copy in the clientproject. Visual Studio .NET takes this step automati-

    cally if the assembly at the source location has beenmodified.

    Note: As a shortcut, add both the class libraryand the client project to the same solution. Then,when you add the reference, choose the Projectstab, and pick the class library project name fromthe list. This way, Visual Studio .NET ensuresthat the client always gets the most recent ver-sion of the class library every time you build thesolution.

    Using the library classesThe classes defined in your class library project arenow automatically available in your current project,just as though you had defined them in that proj-ect. The only difference is that you need to use thenamespace of your project library to access its classes.Heres what you need to access the EncryptLibraryclass library:

    Imports EncryptLibrary

    Now, its easy to respond to a button click and encryptsome text to a file. Just take a look at the followingcode to encrypt some text:

    Private Sub cmdEncrypt_Click( _

    sender As Object, e As EventArgs) _

    Handles cmdEncrypt.Click

    Dim Encryptor As New _

    FileEncryptor(txtPassword.Text)

    Encryptor.EncryptFile( _

    encrypt.bin, txtText.Text)

    End Sub

  • 7/31/2019 Inside MS VB 6

    12/16

    Inside Microsoft Visual Basic12

    become easier as Microsoft streamlines the upgradeprocess and probably starts sneaking the .NET filesinto such applications as Microsoft Internet Explorerand Windows operating system upgrades.

    Revisiting DLL HellMost programmers are familiar with a program-

    ming problem affectionately known as DLL Hell.This problem is experienced most acutely whenyou install a new software product that updates ashared component used by other applications withan incompatible version. The end result is that aseemingly innocent taskupdating a system com-ponentbackfires miserably, rendering one or moreapplications unusable.

    Relief through private assembliesDLL Hell has its roots in the early days of Windows,when disk space and memory space were at such apremium that it didnt make sense for different appli-

    cations to use different copies of the same components.In todays world, where hard drives and RAM chipsare plentiful, the opposite is true: Its generally muchbetter to save developer time and troubleshootingheadaches by giving each application its own versionof a component. In .NET, a component thats only usedby a single application is called aprivate assembly. Wecompiled the FileEncryptor class library into a privateassembly. That means that if two applications needto use it, youll make two copies and put one in eachdirectory. Usually, this approach wont pose a prob-lem. However, in some cases, this method falls short.

    Going to the GACIf you want to control how versioning works, or youhave an extremely large component that you dont wantto copy multiple times, then you need to step beyondprivate assemblies and into the GAC (global assemblycache). The GAC is a new system-wide storage place forshared components. Its better than the Windows sys-tem directory, because it has the ability to store multipleversions of a single component. If youd like to learnmore about the GAC, check out the June 2004 articleTake advantage of the global assembly cache to avoid

    Decrypting text is just as easy. The code in Listing Bsimply displays the decrypted text in a message box.

    You can play with this example to get a betterunderstanding of how class libraries work. Clearly,you could have added the encryption code directly tothe client, but this separation gives much more flex-ibility for dividing the problem (and reusing yourhard work).

    Deploying your class libraryWhen you decide to deploy your new client proj-ect, youll notice how dramatic the differences arebetween COM and .NET. In COM development, youwould need to first copy the custom component tothe Windows system directory on the new computer,register it, and then use the client program.

    No registration requiredIn .NET development, no registration is required. Youcan copy the class library DLL and client EXE files to

    any directory on the new computer, and theyll workautomatically. The EXE file has all the informationthat .NET needs about dependencies. It will auto-matically locate the class library DLL, as long as itspresent in the same directory. (In fact, you can evenreplace the class library with a new version, and itwill work seamlessly, provided you dont change thename of the methods youre using, or the number ortype of parameters each method uses.)

    But the .NET Framework is requiredOf course, this simple deployment still isnt quite as

    easy now as it should be in a few years. The problemis that while your assemblies have all the metadatathey need to identify themselves and their dependen-cies, theyll still only work on another computer withthe .NET Framework. If you copy your applicationto a program that doesnt have .NET, it wont work.Fortunately, .NET is easy to install, if you dont minda 23 MB download. In the future, the task should

    Listing B: Code to display decrypted text using the class library

    Private Sub cmdDecrypt_Click( _

    sender As Object, e As EventArgs) _

    Handles cmdDecrypt.Click

    Try

    Dim Encryptor As New _

    FileEncryptor(txtPassword.Text)

    MessageBox.Show( _

    Encryptor.DecryptFile(encrypt.bin))

    Catch

    MessageBox.Show( _

    File not found or invalid password.)

    End Try

    End Sub

    Got .NET?Any client that you want to share your class library with must have

    .NET installed. To complete this step, just use the Windows Update

    feature by following these steps:

    1. Go to the Windows Update website. You can select Windows

    Update from the Start menu, or just point your browser to http:

    //windowsupdate.microsoft.com.

    2. Scan for updates.

    3. Select .NET Framework Version.

    4. Install it.

  • 7/31/2019 Inside MS VB 6

    13/16

    January 2005www.elementkjournals.com

    .NETs DLL hell, which shows you how to place theFileEncryptor class library in the GAC.

    .NETs Dewey decimal systemIn this article, weve shown you how to take advantageof .NETs class library feature to catalog your reusableclasses. When you use class libraries, you avoid dupli-cate coding and can take advantage of other .NET fea-tures, such as the GAC, which allow you to store allyour classes in a nice and orderly fashion.

    Matthew MacDonald is an author, educator,and MCSD developer with a passion for emerg-ing technologies. Hes a contributor to severalbooks about .NET, including titles at OReilly andApress. Email him at [email protected],or browse his website at www.prosetech.com. Inaddition, check out The Book of VB .NET from No

    Starch Press, which demystifies .NET developmentfor VB programmers.

    Maximize performance by executing SQL storedprocedures with a DataReaderby Sheila M. DavisApplications: Microsoft Visual Basic .NET, Microsoft ADO.NET

    Download: http://download.elementkjournals.com/vbasic/200501/datareader.zip

    SQL stored procedures have been around for quite some time. Developers routinely use them to retrievedata from a SQL database more securely and efficiently. If youre using SQL stored procedures for theperformance boost, then you should be mindful that you can lose part of those gains by choosing the

    wrong method to execute the stored procedure and retrieve the data in .NET. In most cases, an ADO.NETDataReader works just fine for these tasks and it carries less baggage than a DataSet, giving you a little extraperformance boost. (Were using the generic ADO.NET terms here. Keep in mind that in code, youll precedethese terms with a specific provider, like SQLDataReader.)

    Dont bring an Uzi to a duck huntBoth the DataReader and the DataSet are excellent toolsfor retrieving data from a stored procedure. However,if you only need to retrieve small amounts of data forthe purpose of displaying it, all the overhead of theDataSet to support two-way communication betweenthe database and your .NET program is unnecessary.With the .NET DataReader, you can retrieve a read-only, forward-only stream of data from a stored pro-cedure and dump it out one row at a time, as wevedone in Figure A.

    In this article, well provide a couple of examples

    on how to retrieve data from a SQL stored procedureusing a SQLDataReader. First, well show you how toexecute a parameterized stored procedure and returnthe data shown in Figure A. Then, well go a stepfurther and use a DataReader to retrieve multiple resultsets from a stored procedure.

    A DataReader primerThe first few steps for creating a SQLDataReader areexactly the same as those youll take to create a Data-

    Set. You start with a Connection, pass it a Connection-

    String, create a Command object, and open the Connection.However, this is where the similarities stop. For theDataReader, you dont need to pass the command to aDataAdapter or call the Fill() method to populate a Data-Set. You just need to call the ExecuteReader command.The following lines of code illustrate the process:

    Dim cn As SqlConnection =New SqlConnection( _

    connection info)

    Dim myCMD As SqlCommand = _

    Figure A: If you only need to display data, theDataReader allows you to do so more efficientlythan the DataSet.

  • 7/31/2019 Inside MS VB 6

    14/16

    Inside Microsoft Visual Basic14

    New SqlCommand(sql query, cn)

    myCMD.CommandType =CommandType.Text

    Dim myReader As SqlDataReader = _

    myCMD.ExecuteReader()

    Retrieving the DataReader dataOnce you create the SQLDataReader, youll treat itjust like you would a Recordset in classic ADO. Yourepeatedly call the Read() method until the DataReaderretrieves all the rows. A While loop, similar to the onein the next set of code, works wonderfully:

    Do While myReader.Read()

    get data

    Loop

    The DataReader returns False when there are no rowsleft to retrieve. To obtain the column information,call the DataReaders GetSring() or GetValue() methodsinside the loop with a column index value, like so:

    myReader.GetString(0)

    Accessing a stored procedure with the DataReaderWhen accessing a stored procedure with a DataReader,you only need to make a few changes from the origi-

    nal syntax we provided. First, youll replace the sqlquery in the Command with a stored procedure name.Then, youll change the CommandType to StoredProcedure,and finally to access the parameter youll create aParameter object and supply the name of the parame-ter and its SQL data type, as the following code snip-pit illustrates:

    Dim myCMD As SqlCommand =New SqlCommand( _ storedprocedurename, cn)

    myCMD.CommandType = CommandType.StoredProcedure

    Dim param As SqlParameter =myCMD.Parameters.Add( _

    parametername, parametertype)

    param.Direction = ParameterDirection.Input

    Youll use the SqlDbType enumeration to select avalid parameter type. Also, set the Direction propertyto Input to show data going into the stored procedure.

    A parameterized stored procedureAs you know, a parameterized stored procedurerequires additional input before it can execute prop-erly. Consider the following stored procedure againstthe SQL Server Northwind database:

    Create procedure dbo.[n Most Expensive Products]

    @GetRowCount int AS

    SET ROWCOUNT @GetRowCount

    SELECT Products.ProductName AS nMostExpensiveProducts,

    Products.UnitPrice

    FROM Products

    ORDER BY Products.UnitPrice DESCGO

    The name of this stored procedure is n Most Expen-sive Products. It retrieves the most expensive itemsfrom the Northwind products database. The parame-ter @GetRowCount controls how many records the queryretrieves.

    Putting it all togetherWeve just shown you a parameterized stored pro-cedure and earlier we showed you how to load aDataReader using one. In Listing A, we put the twopieces together inside a Buttons Click() event to pro-duce the debug data shown in Figure A. (If testingthis code, be sure to create the stored procedure inSQL Server, add a TextBox control to the form, andimport System.Data.SQLClient in your .NET code.)

    A tale of two result setsOftentimes, it may be necessary to return multipleresult sets in a single stored procedure. For example,the stored procedure in Listing B named Ten Best and

    Listing A:Code to load a DataReader from a parameterizedstored procedure

    Dim cn As SqlConnection = New SqlConnection( _

    server=svr1;uid=uid1;pwd=pw1;database=Northwind)

    Dim cmdExpensive As SqlCommand = _New SqlCommand(n Most Expensive Products, cn)

    cmdExpensive.CommandType = CommandType.StoredProcedure

    Dim rowcount As SqlParameter = cmdExpensive. _

    Parameters.Add(@GetRowcount, SqlDbType.Int)

    rowcount.Direction = ParameterDirection.Input

    If Len(Trim(TextBox1.Text)) = 0 Then TextBox1.Text = 6

    Dim recs As Short = CLng(TextBox1.Text)

    rowcount.Value = recs

    cn.Open()

    Dim myReader As SqlDataReader = _cmdExpensive.ExecuteReader( _

    CommandBehavior.CloseConnection)

    Do While myReader.Read()

    Dim x As String = Space(50)

    x = x.Insert(0, Trim(myReader.GetString(0)))

    x = x.Insert(25, Trim(myReader.GetValue(1)))

    Debug.WriteLine(x)

    Loop

  • 7/31/2019 Inside MS VB 6

    15/16

    www.elementkjournals.com

    Inside Microsoft

    Visual Basic(ISSN 1066-7555) is published monthly by Element KJournals, 500 Canal View Blvd., Rochester, N.Y., 14623.

    Customer Relations

    U.S. toll-free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (800) 223-8720Canada toll-free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (877) 203-5248Outside the U.S. and Canada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (585) 240-7301Customer Relations fax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (585) 292-4392

    For subscriptions, fulfillment questions, and requests for group subscriptions, addressyour letters to

    Element K Journals Customer Relations500 Canal View Blvd.Rochester, NY 14623

    Or contact Customer Relations via our website atwww.elementkjournals.com/contact.asp.

    Element K Journals

    Publisher. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Doreen BierylaAssociate Publisher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Michelle RogersManager of Customer Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Nicole PateManager, Journals Production . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Danielle RumseyGraphic Design Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chuck WilleyDirector of Marketing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lynne DundasProduct Marketing Manager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sean McPartland

    Postmaster

    Postmaster: Send address changes to

    Inside Microsoft Visual BasicP.O. Box 92880Rochester, NY 14692

    Editorial

    Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sheila M. Davis

    Managing Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mike D. JonesCopy Editors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Christine Hunt

    Carrie WeihContributing Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Matthew MacDonald

    Jonathan RabsonGraphic Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Amy Palermo

    You may address tips, special requests and other correspondence to

    The Editor, Inside Microsoft Visual Basic

    Element K Journals500 Canal View Blvd.Rochester, NY 14623

    Editorial Department fax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (585) 292-4391

    Or contact us via internet email at [email protected].

    Sorry, but due to the volume of mail we receive, we cant always promise a reply,although we do read every letter.

    Price

    Domestic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . $147/yr.Outside the U.S.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . $157/yr.

    Our Canadian GST # is 88903 7958 RT0001. CPM # is 40031405.Our QST # is 1018491237.

    Back Issues

    To order a back issue, call Customer Relations at (800) 223-8720. You can pay MasterCard, VISA, Discover, or American Express.

    Copyright

    2005 Element K Journals, a division of Element K Press LLC (Element K). EleK and the Element K logo are trademarks of Element K LLC. This work is an indedently produced publication of Element K Journals, the content of which is the propeElement K or its affiliates or third-party licensors and which is protected by copyrighin the U.S. and elsewhere. The right to copy and publish the Content is reserved, eveContent made available for free such as sample articles, tips, and graphics, none of may be copied in whole or in part or further distributed in any form or medium withoexpress written permission of Element K. Questions or requests for permission to corepublish any content may be directed to [email protected].

    Visual Basic is a trademark of Microsoft Corporation. IBM is a registered trademark oCorporation. Windows is a registered trademark of Microsoft Corporation. All other pronames or services identified throughout this journal are trademarks or registered tmarks of their respective companies.

    Printed in the U.S.A.

    Are you moving?If youve moved recently or youre planning to move, you can guarantee uninterruservice on your subscription by calling us at (800) 223-8720 and giving us new address. Or you can fax us your label with the appropriate changes at (292-4392. Our Customer Relations department is also available via our websiwww.elementkjournals.com/contact.asp.

    To see a list of our products, visit our website at www.elementkjournals.com.

    January 2005

    Worst returns the top 10 best-selling items and thetop 10 worst selling items for the Northwind Order-Details table.

    Youre sure to see a performance differencebetween the DataSet and the DataReader in procedureslike this one. The DataAdapter would create two Data-Tables and return both result sets at once. However,the DataReader allows you to retrieve the result setsone at a time using the NextResult() method, like so:

    myReader.NextResult()

    Retrieving the result setsTo test the DataReader with multiple result sets, savethe Ten Best and Worst stored procedure to your SQLServer 2000 Northwind database. Then, create a new

    Windows Application and add two ListView con-trols and a Button control to the default form. Next,right-click on the form and select View Code from theshortcut menu. Add the following line to the top ofthe code window:

    Imports System.Data.SqlClient

    Then, copy the code from Listing C into your But-ton1_Click() event subroutine. Be sure to adjust theconnection information to reflect valid ones on yoursystem.

    Note: At any time, you may navigate to the URLlisted at the top of this article and download thesample code in the file datareader.zip.

    Listing B:Stored procedure that returns two result sets

    CREATE PROCEDURE dbo.[Ten Best and Worst] AS

    SELECT TOP 10

    productname AS [Product Name],

    SUM(quantity) AS [Units Ordered]

    FROM [order details] od, products pd

    WHERE od.productid = pd.productid

    GROUP BY od.productid, productname

    ORDER BY [Units Ordered] DESC;

    SELECT TOP 10

    productname AS [Product Name],

    SUM(quantity) AS [Units Ordered]

    FROM [order details] od, products pd

    WHERE od.productid = pd.productid

    GROUP BY od.productid, productname

    ORDER BY [Units Ordered]

    GO

    Listing C:Code to load the DataReader

    Dim cn As SqlConnection = _

    New SqlConnection(server=svr1;uid=uid1; & _

    pwd=pw1;database=Northwind)

    Dim cmdBestWorst As SqlCommand = _

    New SqlCommand(Ten Best and Worst, cn)

    cmdBestWorst.CommandType = _

    CommandType.StoredProcedure

    cn.Open()

    Dim myReader As SqlDataReader = _

    cmdBestWorst.ExecuteReader( _

    CommandBehavior.CloseConnection)

    LoadListview(myReader, ListView1)

    myReader.NextResult()

    LoadListview(myReader, ListView2)

    myReader.Close()

  • 7/31/2019 Inside MS VB 6

    16/16

    2035

    Please include account number from label with any correspondence.

    Coming up:

    Exploring COM+ with Visual Basic 6

    More on working with storedprocedures in .NET

    This code is pretty much the same as the previouscode to load a DataReader, except theres no parameterin this version and we use the NextResult() method toobtain the second result set.

    Loading data into a ListView

    In the previous block of code, we called the LoadList-View() subroutine to load each ListView control withits result set. This subroutine, shown in Listing D, usesthe same While loop to iterate the DataReader. To obtain

    the column headings for the list views, we use the Get-Name() method of the DataReader. Add this code to yourcode window after the Button Click() event.

    A multi-result set displayAfter youve added the stored procedure to your SQL

    Server database and added all the code, press [F5] tobuild and run the application. When you click the but-ton, .NET executes the stored procedure, retrieves thedata from each result set and loads the two ListViewcontrol. If all goes well, your form should resemble theone shown in Figure B.

    Take a performance runIn this article, weve shown you how to obtain datafrom a SQL Server stored procedure using a DataReader.In general, stored procedures are designed to be moreefficient than outside queries. The DataReader can alsoincrease an applications performance because itreturns the data one row at a time rather than big globslike the DataSet. Pairing these two structures togethercreate a perfect performance match.

    Listing D:Code to load the ListView controls from theDataReader

    Sub LoadListview(ByVal rdr As SqlDataReader, _

    ByVal lv As ListView)

    lv.Clear()

    set headersDim lvwColumn As ColumnHeader

    lvwColumn = New ColumnHeader

    lvwColumn.Text = rdr.GetName(0)

    lv.Columns.Add(lvwColumn)

    lvwColumn = New ColumnHeader

    lvwColumn.Text = rdr.GetName(1)

    lv.Columns.Add(lvwColumn)

    lvwColumn = Nothing

    get data

    Do While rdr.Read()

    Dim lvwRow As New ListViewItem

    lvwRow.Text = rdr.GetString(0)lvwRow.SubItems.Add(rdr.GetValue(1))

    lv.Items.Add(lvwRow)

    Loop

    show data

    lv.GridLines = True

    lv.View = View.Details

    End Sub Figure B: With the DataReader, you retrieve datafrom multiple result sets one at a time.