Backup CD to ISO Images

AID: 3635
  • Status: Published

7570 points

  • Byegl1044
  • TypeTips/Tricks
  • Posted on2010-08-27 at 13:52:21
Awards
  • Community Pick
  • Experts Exchange Approved
This article will discuss how to programmatically backup data CDs under Visual Basic.NET.

If you haven't already noticed, .NET framework doesn't provide a direct method to copy from a CDRom drive to a  specified destination.   The following example shows that you can't directly obtain a stream over the CDRom device using the drive letter.
Dim fStream As New System.IO.FileStream("d:\", IO.FileMode.Open, _ 
IO.FileAccess.Read, IO.FileShare.ReadWrite, 65536)

                                    
1:
2:

Select allOpen in new window


(It halts with an UnauthorizedAccessException error.)  The following try also fails:
FileSystem.FileCopy("d:\", "c:\test\mydisc.iso")

                                    
1:

Select allOpen in new window



How to Create a Stream Over the CDRom Drive


In order to obtain a stream over the CDRom drive in .NET you must use PInvoke signature with the  CreateFile() function.  In addition, we will be using the SafeFileHandle Class.

Most importantly we need to use both of these classes you'll need a direct access handle to the disk drive in addition you can pass the SafeFileHandle object to the FileStream class to generate the stream over the device drive.

pseudo code
Dim hDevice As Microsoft.Win32.SafeHandles.SafeFileHandle = Nothing
hDevice = CreateFile("\\.\d:", GenericRead, FileShare.ReadWrite, _ 
IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)
deviceStream = New System.IO.FileStream(hDevice, FileAccess.Read, BufferSize)

                                    
1:
2:
3:
4:

Select allOpen in new window


Notice that in this call we use the format CreateFile("\\.\d:"...) this informs the system that we want to request a volume handle on that device.  Remember that no trailing backslash should be specified in that prefix or you will tell Windows you are requesting a directory handle instead.

After you obtain a stream over the device drive you can get the data from the CDRom disc directly using the Stream methods Read/Write/Seek. It's also important that you use a multiple sector aligned buffer that is a multiple of the CDRom sector size.


Creating the ISO Image of the CDRom Data Disc (Source Code)


The DataDisc Class (that we'll create below) shows how to make an exact copy of the CDRom disc to an ISO file using the methods described above. The class takes things one step further by also calculating the file checksum hash value of the disc in either MD5 or SHA1.

The calculated file hash can be used to determine whether the image is in it's original working state. You can use the hash value to verify that it hasn't been corrupted.

As an example if you copy to your local disk then decide to move the image to a network drive you can verify the integrity of the .ISO image by checking that the file on the network returns the same hash value that was returned from the original copy.

It also has the benefit that you don't need re-read the same file again after it was completed rather it's calculated during the copy operation which can increase the downtime for larger files.

You may also use this hash value as part of the filename in the format hashvalue_label.iso so you always know the original checksum value without saving it to another document.

Usage:
Tip: If your using a Windows Form with the example code feel free to make use of the background worker to support progress and cancellation you may also use a seperate thread as the class uses synchronous methods.
Dim myDisc As New DataDisc
myDisc.Copy(New System.IO.DriveInfo("f:\"), _ 
"c:\users\username\documents\mydisc.iso", DataDisc.HashProvider.MD5)

                                    
1:
2:
3:

Select allOpen in new window


1) Create a new class named: DataDisc.vb
2) Add the following code:
Imports System.IO
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Imports System.Security.Cryptography

Public Class DataDisc
    'egl1044
    Private Const BufferSize As Integer = 65536 '// multiple sector aligned buffer.
    Private Const GenericRead As Integer = &H80000000
    Public Enum HashProvider
        MD5 = 0
        SHA1 = 1
    End Enum
    <DllImport("Kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Public Shared Function CreateFile(ByVal lpFileName As String, _
                               ByVal dwDesiredAccess As Integer, _
                               ByVal dwShareMode As Integer, _
                               ByVal lpSecurityAttributes As IntPtr, _
                               ByVal dwCreationDisposition As Integer, _
                               ByVal dwFlagsAndAttributes As Integer, _
                               ByVal hTemplateFile As IntPtr) As SafeFileHandle
    End Function
    Public Sub New()
    End Sub
    Public Sub Copy(ByVal discDrive As DriveInfo, ByVal imageFileName As String, ByVal provider As HashProvider)

        Dim hDevice As SafeFileHandle = Nothing             '// The volume handle to the CDRom device.
        Dim deviceStream As FileStream = Nothing            '// The device stream.
        Dim imageStream As FileStream = Nothing             '// The image stream.
        Dim hashStream As HashAlgorithm = Nothing           '// The hash stream.
        Dim hashBuffer(BufferSize - 1) As Byte              '// Bogus hash output buffer.
        Dim hashValue As String = String.Empty              '// The final hash checksum value of the image.
        Dim dataBuffer(BufferSize - 1) As Byte              '// multiple sector aligned buffer.
        Dim dataBytesRead As Integer = 0                    '// The bytes read from the stream.
        Dim fOk As Boolean = True                           '// failure bit flag.

        If discDrive IsNot Nothing Then

            ' Verify that the drive points to a CDRom device.
            If discDrive.DriveType <> DriveType.CDRom Then
                Debug.Print("Invalid CDRom device drive.")
                Return
            End If

            ' Verify that the drive has media inserted.
            If Not discDrive.IsReady Then
                Debug.Print("Device not ready")
                Return
            End If

            ' Open the CDRom device for direct access.
            hDevice = CreateFile("\\.\" & discDrive.Name.Substring(0, 2), GenericRead, _
                                 FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)

            ' Verify the device handle is valid.
            If hDevice.IsInvalid Then
                Debug.Print("CreateFile failed" & Marshal.GetLastWin32Error)
                Return
            End If

            ' Prepare the streams for the copy operation.
            Try
                ' Generate file hash checksum using either MD5 or SHA1.
                hashStream = CType(IIf(CBool(provider), New SHA1CryptoServiceProvider, New MD5CryptoServiceProvider), HashAlgorithm)

                ' Create a stream over the CDRom device using the direct access volume handle.
                deviceStream = New FileStream(hDevice, FileAccess.Read, BufferSize)

                ' Create a stream that will contain the CDRom data read from the device.
                imageStream = New FileStream(imageFileName, _
                                             FileMode.Create, FileAccess.Write, FileShare.None, BufferSize)

                ' Begin copying the the disc data to the image file.
                Do
                    ' Read disc data into multiple sector aligned buffer.
                    dataBytesRead = deviceStream.Read(dataBuffer, 0, BufferSize)

                    ' Transform the data for MD5 or SHA1 hash value.
                    hashStream.TransformBlock(dataBuffer, 0, dataBytesRead, hashBuffer, 0)

                    ' Write the disc data to the image file.
                    imageStream.Write(dataBuffer, 0, dataBytesRead)

                Loop Until dataBytesRead = 0

                ' TransformFinalBlock must be called when finished.
                hashStream.TransformFinalBlock(dataBuffer, 0, 0)

                ' Get the file hash checksum of the image.
                If hashStream IsNot Nothing Then
                    hashValue = BitConverter.ToString(hashStream.Hash).Replace("-", "").ToLower
                End If

            Catch ex As Exception

                fOk = False ' failure bit flag.

                MsgBox(ex.Message)

            Finally

                ' cleanup 
                If deviceStream IsNot Nothing Then
                    deviceStream.Close()
                    deviceStream.Dispose()
                End If

                If imageStream IsNot Nothing Then
                    imageStream.Close()
                    imageStream.Dispose()
                End If

                If hDevice IsNot Nothing Then
                    hDevice.Close()
                    hDevice.Dispose()
                End If

            End Try

            If fOk Then
                ' TODO:\\ Work with the image file. (rename,move etc..)
                Debug.Print("Copy Complete. File checksum: {0}", hashValue)
            Else
                ' TODO:\\ delete image file.
                Debug.Print("Copy Failed.")
                If File.Exists(imageFileName) Then
                    File.Delete(imageFileName)
                End If
            End If

        End If

    End Sub

End Class

                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:

Select allOpen in new window



Important Things To Consider


The following method only works for Data Disc CD's these are discs such as Games, Operating System CD's, Driver CD's, Software or Installation CD's etc...

You can't use this method to Copy CD's that are Audio, DVD movies, etc.  These types of media have different structures and are formatted differently.


Important, But Optional Considerations When Copying Data CDRom Discs.


  • Locking the media tray to prevent accidental removal of the disc while it's being copied.
  • Locking the device for exclusive access to prevent other applications from obtaining access to the disc until the copy has completed.
  • Extending reads past the disc that would otherwise not be visible using the traditional methods.
  • Ejecting the CDRom disc when the Copy has completed to flush internal cache that is left behind by the operating system.
  • Ensure the target drive has enough available disk space to store the entire ISO Image.


I won't cover how to do the above in this article, but if you need help implementing the optional features, you can open a question and I or another EE Expert will be glad to help you.


How to Determine an Audio CD or DVD Movie


You can use the same method that the windows Auto Play feature uses to detect different media disc types.

Audio CD
Audio/Music discs that you would play in your home entertainment system, when you insert them into the computer windows reads the disc and generates track files on the fly.  These files aren't actually on the disc but generated by windows only when you insert them into the computer.
' Determines that the media present in the drive is an AudioCD.
Public Function IsDiscAudioCD(ByVal rootDrive As String) As Boolean
Dim audio As String = Path.Combine(rootDrive, "track01.cda")
Return File.Exists(audio)
End Function

                                    
1:
2:
3:
4:
5:

Select allOpen in new window



DVD Movie
DVD movies can be determined by the video_ts.ifo file located in the video_ts folder.
' Determines that the media present in the drive is an DVD Movie.
Public Function IsDiscDVDMovie(ByVal rootDrive As String) As Boolean
Dim dvd As String = Path.Combine(rootDrive, "video_ts\video_ts.ifo")
Return File.Exists(dvd)
End Function

                                    
1:
2:
3:
4:
5:

Select allOpen in new window




Final thoughts...


If you're not already using Virtual CloneDrive I highly recommend that you do.  It's free and works great with the example. The utility allows you to mount the ISO images as CDRom drives.  If you're running Windows 7 there is also a feature to directly burn the image to a blank_cd (Windows Disc Image burner).  Just right click the .ISO file and it will be available on the context menu.  Enjoy!

     Slysoft's Virtual CloneDrive (freeware download)
     http://www.slysoft.com/en/virtual-clonedrive.html
Asked On
2010-08-27 at 13:52:21ID3635
Tags

Create

,

Backup

,

Copy CDROM Data Disc CD

,

ISO Image

Topic

Microsoft Visual Basic.Net

Views
2356

Comments

Author Comment

by: egl1044 on 2010-08-31 at 23:11:15ID: 18976

The Asynchronous DataDisc Class is available.
The asynchronous version while more complex works just like the background worker providing many benefits such as reporting progress, completion and cancellation.

Under a Windows Form Project add the following controls to the Form.
2 Buttons
1 ProgressBar

' Usage:

Public Class Form1

    Dim WithEvents myDisc As New DataDisc

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ' Copy Button
        Dim myDiscDrive As New System.IO.DriveInfo("d:\")
        If Not myDisc.IsBusy Then
            myDisc.BeginCopy(myDiscDrive, "c:\users\username\documents\disc.iso", DataDisc.HashProvider.MD5, Nothing)
        Else
            Debug.Print("Copy already in progress.")
        End If
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ' Cancel Button
        myDisc.Cancel()
    End Sub

    Private Sub myDisc_CopyCompleted(ByVal sender As Object, ByVal e As CopyDiscCompletedEventArgs) Handles myDisc.CopyCompleted
        If e.Cancelled Then
            Debug.Print("Cancelled!")
            ' TODO:// When the copy has been cancelled.
            '       for example you can delete the image file
            '       from the disk.
            DeleteImageFile(e.ImageFileName)
        ElseIf e.Error IsNot Nothing Then
            Debug.Print("Error! {0}", e.Error.Message)
            ' TODO:// When an error occurs at any time during the
            '           copy operation.
            DeleteImageFile(e.ImageFileName)
        Else
            Debug.Print("Complete! image={0} hash={1}", e.ImageFileName, e.Hash)
            ' TODO:// When the copy is completed.
            '           for example you can rename the image file.
        End If
        ' Reset progress bar value.
        ProgressBar1.Value = 0
    End Sub

    Private Sub myDisc_ProgressChanged(ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles myDisc.ProgressChanged
        ' Copy Progress
        ProgressBar1.Value = e.ProgressPercentage
    End Sub

    Private Sub DeleteImageFile(ByVal imageFile As String)
        If System.IO.File.Exists(imageFile) Then
            System.IO.File.Delete(imageFile)
        End If
    End Sub
End Class
' DataDisc.vb

Imports System.ComponentModel
Imports System.IO
Imports System.Threading
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
Imports System.Security.Cryptography

Public Class DataDisc
    '   egl1044
    '   Windows 2000 or later
    '   .NET 2.0 framework or later
    Private Const BufferSize As Integer = 65536 '// multiple sector aligned buffer.
    Private Const GenericRead As Integer = &H80000000
    Public Enum HashProvider
        MD5 = 0
        SHA1 = 1
    End Enum
    <DllImport("Kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Public Shared Function CreateFile(ByVal lpFileName As String, _
                               ByVal dwDesiredAccess As Integer, _
                               ByVal dwShareMode As Integer, _
                               ByVal lpSecurityAttributes As IntPtr, _
                               ByVal dwCreationDisposition As Integer, _
                               ByVal dwFlagsAndAttributes As Integer, _
                               ByVal hTemplateFile As IntPtr) As SafeFileHandle
    End Function

    Public Delegate Sub ProgressChangedEventHandler(ByVal e As ProgressChangedEventArgs)

    Public Delegate Sub CopyDiscCompletedEventHandler(ByVal sender As Object, _
                                                      ByVal e As CopyDiscCompletedEventArgs)
    Private Delegate Sub CopyDiscHandler(ByVal discDrive As DriveInfo, _
                                         ByVal imageFile As String, _
                                         ByVal provider As HashProvider, _
                                         ByVal asyncOp As AsyncOperation)
    Private onProgressDelegate As SendOrPostCallback
    Private onCompletedDelegate As SendOrPostCallback
    Public Event ProgressChanged As ProgressChangedEventHandler
    Public Event CopyCompleted As CopyDiscCompletedEventHandler

    Private fCancel As Boolean = False
    Private fBusy As Boolean = False

    Public Sub New()
        InitDelegates()
    End Sub

    Protected Overridable Sub InitDelegates()
        onProgressDelegate = New SendOrPostCallback(AddressOf Progress)
        onCompletedDelegate = New SendOrPostCallback(AddressOf Completed)
    End Sub

    Public Sub BeginCopy(ByVal discDrive As DriveInfo, _
                         ByVal imageFile As String, _
                         ByVal provider As HashProvider, _
                         ByVal stateObject As Object)

        fBusy = True
        fCancel = False

        Dim asyncOp As AsyncOperation = _
            AsyncOperationManager.CreateOperation(stateObject)

        Dim workerDelegate As New CopyDiscHandler( _
            AddressOf DoCopy)

        ' kick off
        workerDelegate.BeginInvoke( _
            discDrive, imageFile, provider, asyncOp, Nothing, Nothing)

    End Sub

    Public Sub Cancel()
        fCancel = True
    End Sub

    Private Sub DoCopy(ByVal discDrive As DriveInfo, _
                       ByVal imageFile As String, _
                       ByVal provider As HashProvider, _
                       ByVal asyncOp As AsyncOperation)

        Dim e As ProgressChangedEventArgs = Nothing         '// Progress handler
        Dim ExceptionObj As Exception = Nothing             '// Error object
        Dim hDevice As SafeFileHandle = Nothing             '// The volume handle to the CDRom device.
        Dim deviceStream As FileStream = Nothing            '// The device stream.
        Dim imageStream As FileStream = Nothing             '// The image stream.
        Dim hashStream As HashAlgorithm = Nothing           '// The hash stream.
        Dim hashBuffer(BufferSize - 1) As Byte              '// Bogus hash output buffer.
        Dim hashValue As String = String.Empty              '// The final hash checksum value of the image.
        Dim dataBuffer(BufferSize - 1) As Byte              '// multiple sector aligned buffer.
        Dim dataBytesRead As Integer = 0                    '// The bytes read from the stream.
        Dim dataBytesTotal As Long = 0                      '// The total size of the stream.
        Dim progressValue As Integer = 0                    '// Progress value
        Static progressValueLast As Integer = 0             '// Last known progress value

        ' Verify that the drive points to a CDRom device.
        If discDrive.DriveType <> DriveType.CDRom Then
            Me.CompleteMethod(hashValue, imageFile, _
                              New ArgumentException("The specified drive is invalid."), False, asyncOp)
            Return
        End If

        ' Verify that the drive has media inserted.
        If Not discDrive.IsReady Then
            Me.CompleteMethod(hashValue, imageFile, _
                              New ArgumentException("Device not ready. Please insert disc into drive."), False, asyncOp)
            Return
        End If

        ' Open the CDRom device for direct access.
        hDevice = CreateFile("\\.\" & discDrive.Name.Substring(0, 2), GenericRead, _
                             FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)

        ' Verify the device handle is valid.
        If hDevice.IsInvalid Then
            Me.CompleteMethod(hashValue, imageFile, _
                              New Win32Exception(Marshal.GetLastWin32Error), False, asyncOp)
            Return
        End If

        ' The total size of the CDRom disc in bytes.
        dataBytesTotal = discDrive.TotalSize

        ' Prepare the streams for the copy operation.
        Try
            ' Generate file hash checksum using either MD5 or SHA1.
            hashStream = CType(IIf(CBool(provider), _
                                   New SHA1CryptoServiceProvider, _
                                   New MD5CryptoServiceProvider), HashAlgorithm)

            ' Create a stream over the CDRom device using the direct access volume handle.
            deviceStream = New FileStream(hDevice, FileAccess.Read, BufferSize)

            ' Create a stream that will contain the CDRom data read from the device.
            imageStream = New FileStream(imageFile, _
                                         FileMode.Create, FileAccess.Write, FileShare.None, BufferSize)

            ' Begin copying the the disc data to the image file.
            Do
                ' Check if the user wants to abort/cancel the operation.
                If fCancel Then
                    Exit Do
                End If

                ' Read disc data into multiple sector aligned buffer.
                dataBytesRead = deviceStream.Read(dataBuffer, 0, BufferSize)

                ' Transform the data for MD5 or SHA1 hash value.
                hashStream.TransformBlock(dataBuffer, 0, dataBytesRead, hashBuffer, 0)

                ' Write the disc data to the image file.
                imageStream.Write(dataBuffer, 0, dataBytesRead)

                ' Calculate percentage value for progress handler.
                progressValue = CInt(CSng(deviceStream.Position) / CSng(dataBytesTotal) * 100)

                ' Update status for progress handler.
                If progressValue <> progressValueLast Then
                    ' update progress last known value.
                    progressValueLast = progressValue
                    e = New CopyDiscProgressChangedEventArgs(progressValue, _
                                                             asyncOp.UserSuppliedState)
                    asyncOp.Post(Me.onProgressDelegate, e)
                End If

            Loop Until dataBytesRead = 0

            If Not fCancel Then

                ' TransformFinalBlock must be called when finished.
                hashStream.TransformFinalBlock(dataBuffer, 0, 0)

                ' Get the file hash checksum of the image.
                hashValue = BitConverter.ToString(hashStream.Hash).Replace("-", "").ToLower

            End If

        Catch ex As Exception

            ' failure
            ExceptionObj = ex

        Finally

            ' cleanup 
            If deviceStream IsNot Nothing Then
                deviceStream.Close()
                deviceStream.Dispose()
            End If

            If imageStream IsNot Nothing Then
                imageStream.Close()
                imageStream.Dispose()
            End If

            If hDevice IsNot Nothing Then
                hDevice.Close()
                hDevice.Dispose()
            End If

            If hashStream IsNot Nothing Then
                hashStream.Clear()
            End If

        End Try

        ' finish
        If fCancel Then
            Me.CompleteMethod(hashValue, imageFile, ExceptionObj, True, asyncOp)       'Cancel
        Else
            Me.CompleteMethod(hashValue, imageFile, ExceptionObj, False, asyncOp)      'Complete
        End If

    End Sub

    Private Sub CompleteMethod(ByVal hashValue As String, _
                               ByVal imageFile As String, _
                               ByVal ex As Exception, _
                               ByVal canceled As Boolean, _
                               ByVal asyncOp As AsyncOperation)

        ' Post the completed event handler.
        Dim e As New CopyDiscCompletedEventArgs(hashValue, _
                                                imageFile, _
                                                ex, _
                                                canceled, _
                                                asyncOp.UserSuppliedState)

        asyncOp.PostOperationCompleted(onCompletedDelegate, e)

        ' Reset busy flag.
        fBusy = False
    End Sub

    Private Sub Completed(ByVal state As Object)
        Dim e As CopyDiscCompletedEventArgs = CType(state, CopyDiscCompletedEventArgs)
        OnCopyDiscCompleted(e)
    End Sub

    Private Sub Progress(ByVal state As Object)
        Dim e As ProgressChangedEventArgs = CType(state, ProgressChangedEventArgs)
        OnProgressChanged(e)
    End Sub

    Protected Sub OnCopyDiscCompleted(ByVal e As CopyDiscCompletedEventArgs)
        RaiseEvent CopyCompleted(Me, e)
    End Sub

    Protected Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)
        RaiseEvent ProgressChanged(e)
    End Sub

    Public ReadOnly Property IsBusy As Boolean
        Get
            Return fBusy
        End Get
    End Property

End Class

Public Class CopyDiscProgressChangedEventArgs
    Inherits ProgressChangedEventArgs
    Public Sub New(ByVal progressPercentage As Integer, _
                   ByVal UserState As Object)
        MyBase.New(progressPercentage, UserState)
    End Sub
End Class

Public Class CopyDiscCompletedEventArgs
    Inherits AsyncCompletedEventArgs
    Private _hashValue As String = String.Empty
    Private _imageFile As String = String.Empty
    Public Sub New(ByVal hashValue As String, _
                   ByVal imageFile As String, _
                   ByVal e As Exception, _
                   ByVal canceled As Boolean, _
                   ByVal state As Object)
        MyBase.New(e, canceled, state)
        Me._hashValue = hashValue
        Me._imageFile = imageFile
    End Sub
    Public ReadOnly Property Hash As String
        Get
            RaiseExceptionIfNecessary()
            Return _hashValue
        End Get
    End Property
    Public ReadOnly Property ImageFileName As String
        Get
            Return _imageFile
        End Get
    End Property
End Class

                                        
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:

Select allOpen in new window

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top Visual Basic.NET Experts

  1. CodeCruiser

    1,541,075

    Genius

    8,400 points yesterday

    Profile
    Rank: Genius
  2. kaufmed

    303,871

    Wizard

    500 points yesterday

    Profile
    Rank: Genius
  3. Idle_Mind

    230,817

    Guru

    2,010 points yesterday

    Profile
    Rank: Savant
  4. nepaluz

    192,076

    Guru

    0 points yesterday

    Profile
    Rank: Sage
  5. PaulHews

    161,438

    Guru

    520 points yesterday

    Profile
    Rank: Genius
  6. BuggyCoder

    150,598

    Guru

    0 points yesterday

    Profile
    Rank: Sage
  7. JamesBurger

    123,179

    Master

    0 points yesterday

    Profile
    Rank: Sage
  8. emoreau

    112,211

    Master

    0 points yesterday

    Profile
    Rank: Genius
  9. Masteraco

    102,128

    Master

    0 points yesterday

    Profile
    Rank: Wizard
  10. TheLearnedOne

    80,982

    Master

    0 points yesterday

    Profile
    Rank: Savant
  11. Dhaest

    63,803

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  12. MlandaT

    53,803

    Master

    2,100 points yesterday

    Profile
    Rank: Genius
  13. wdosanjos

    53,796

    Master

    0 points yesterday

    Profile
    Rank: Genius
  14. mlmcc

    53,048

    Master

    0 points yesterday

    Profile
    Rank: Savant
  15. RolandDeschain

    41,679

    10 points yesterday

    Profile
    Rank: Sage
  16. srosebabu

    31,025

    2,000 points yesterday

    Profile
    Rank: Guru
  17. mas_oz2003

    28,400

    0 points yesterday

    Profile
    Rank: Genius
  18. sedgwick

    27,350

    0 points yesterday

    Profile
    Rank: Genius
  19. jacko72

    26,596

    0 points yesterday

    Profile
    Rank: Genius
  20. tommyBoy

    25,850

    0 points yesterday

    Profile
    Rank: Genius
  21. dlmille

    22,160

    0 points yesterday

    Profile
    Rank: Genius
  22. imnorie

    21,664

    1,600 points yesterday

    Profile
    Rank: Genius
  23. Cluskitt

    21,418

    0 points yesterday

    Profile
    Rank: Wizard
  24. robert_schutt

    20,440

    0 points yesterday

    Profile
    Rank: Guru
  25. navneethegde

    20,332

    0 points yesterday

    Profile
    Rank: Wizard

Hall Of Fame