Page 1 of 1

ISO Maker / CD/DVD Checker

Posted: Sat Feb 17, 2007 6:00 pm
by peterb
Simple CD/DVD Checker and ISO Maker with GUI :D

2007.02.18 - fixed small bug ( Str( dg\DiskSize ) -> StrQ( dg\DiskSize ) )

Code: Select all

;- Author   : Petr Vavrin (peterb)
;- Location : Czech Republic

Structure DISK_GEOMETRY 
   Cylinders.q 
   MediaType.l 
   TracksPerCylinder.l 
   SectorsPerTrack.l 
   BytesPerSector.l 
EndStructure 

Structure DISK_GEOMETRY_EX 
  geometry.DISK_GEOMETRY 
  DiskSize.q 
  byte.b[1]; 
EndStructure 

#IOCTL_DISK_BASE        = 7 
#METHOD_BUFFERED        = 0
#FILE_ANY_ACCESS        = 0

#FILE_READ_ACCESS       = 1
#FILE_DEVICE_CD_ROM     = 2
#IOCTL_CDROM_BASE       = #FILE_DEVICE_CD_ROM 

#boxes                  = 1000
#box_width              = 7
#box_height             = 7
#box_distance           = 2

#boxes_width            = 290
#boxes_height           = 290

#cols                   = #boxes_width / (#box_width + #box_distance)

Global boxes_left.l
Global boxes_top.l
Global boxes_image_background.l = RGB (250, 250, 250)

Global box_blank_background.l   = RGB (240, 240, 240)
Global box_blank_outline.l      = RGB (220, 220, 220)

Global box_set_background.l     = RGB (  0, 255,   0)
Global box_set_outline.l        = RGB (100, 255, 100)

Global box_error_background.l   = RGB (255,   0,   0)
Global box_error_outline.l      = RGB (255, 100, 100)

Enumeration
  #main_window
  #boxes_gadget
  #boxes_image
  #OutputFile
  #BrowseOutput
  #Drive_Combo
  #Start
  #State
  #Check_Only
  #Disk_Size
  #Sectors
  #Actual_Sector
  #Percents
  #Error_List
  #Wrong_Sectors
  #File
  #Exit
EndEnumeration

Macro IIf (expr, truepart, falsepart)
  If expr : truepart : Else : falsepart : EndIf
EndMacro

Procedure make_blank_box ()

  If StartDrawing(ImageOutput(#boxes_image))
    For box_number = 0 To #boxes - 1

      x = #box_distance + ((box_number % #cols) * (#box_width  + #box_distance))
      y = #box_distance + ((box_number / #cols) * (#box_height + #box_distance))
      
      Box(x,     y,     #box_width,     #box_height,     box_blank_outline)
      Box(x + 1, y + 1, #box_width - 2, #box_height - 2, box_blank_background)

    Next

    StopDrawing()
    SetGadgetState(#boxes_gadget, ImageID(#boxes_image))
  EndIf  

EndProcedure

Procedure change_box_state (box_number, type.s)
  
  box_number = box_number - 1
  
  If StartDrawing(ImageOutput(#boxes_image))

    x = #box_distance + ((box_number % #cols) * (#box_width  + #box_distance))
    y = #box_distance + ((box_number / #cols) * (#box_height + #box_distance))
    
    outline    = RGB (255, 255, 255)
    background = RGB (255, 255, 255)
    
    Select type
      Case "blank"
        outline    = box_blank_outline
        background = box_blank_background

      Case "set"
        outline    = box_set_outline
        background = box_set_background
        
      Case "error"
        outline    = box_error_outline
        background = box_error_background
      
    EndSelect
    
    Box(x,     y,     #box_width,     #box_height,     outline)
    Box(x + 1, y + 1, #box_width - 2, #box_height - 2, background)

    StopDrawing()
    SetGadgetState(#boxes_gadget, ImageID(#boxes_image))

  EndIf

EndProcedure

Procedure.s Make_ISO ()

  make_blank_box ()
  ClearGadgetItemList( #Error_List )
  
  drive.s = GetGadgetText ( #Drive_Combo )
  return_state.s = "Finished"

  If GetDriveType_( drive + "\" ) <> #DRIVE_CDROM
    return_state = "Selected drive is not CD-ROM / DVD-ROM"

  Else  

    dg.DISK_GEOMETRY_EX 

    IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX = ((#IOCTL_CDROM_BASE) << 16) | ((#FILE_READ_ACCESS) << 14) | $50 | #METHOD_BUFFERED
    hDevice = CreateFile_("\\.\\" + drive, #GENERIC_READ, #FILE_SHARE_READ | #FILE_SHARE_WRITE, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0) 
    If Not hDevice 
      return_state = "Can't create handle to device!"
      
    Else
      output_file.s = GetGadgetText ( #OutputFile )
      
      file_status = #True
      If GetGadgetState ( #Check_Only ) = 1
        write = #False
      Else
        write = #True
        
        If Not CreateFile(#File, output_file )
          return_state = "Can't create the output file!"
          file_status = #False
        
        EndIf

      EndIf

      If file_status = #True
        DeviceIoControl_(hDevice, IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX, 0, 0, @dg, SizeOf(dg), @bytesret, 0) 
        If dg\geometry\BytesPerSector = 0
          return_state = "Invalid drive geometry!"
        Else
          
          If write = #False
            SetGadgetText ( #State, "Checking ... " )
          Else
            SetGadgetText ( #State, "Copying ... " )
          EndIf
            
          sectors.l = (dg\DiskSize / dg\geometry\BytesPerSector) - 1 
          bps.l = dg\geometry\BytesPerSector
          is_error = #False
          *pmembuf = AllocateMemory ( bps ) 
          *blank   = AllocateMemory ( bps ) 
            
          SetGadgetText ( #Disk_Size, StrQ( dg\DiskSize ) + " Bytes" ) 
          SetGadgetText ( #Sectors,   Str( sectors + 1 ) ) 
          SetGadgetText ( #Wrong_Sectors, "0" )
  
          For sector = 0 To sectors 
            
            SetGadgetText ( #Actual_Sector,   Str( sector + 1 ) ) 
        
            proz.f = (sector / sectors) * 100
            position = proz * 10
    
            SetGadgetText ( #Percents, StrF(proz, 1) + " %" ) 
    
            If ReadFile_(hDevice, *pmembuf, bps, @ret, 0) = 0 
              is_error = #True
              SetGadgetText (#Wrong_Sectors, Str ( Val ( GetGadgetText ( #Wrong_Sectors ) ) + 1 ) )
              
              AddGadgetItem (#Error_List, -1, GetGadgetText ( #Wrong_Sectors ) + Chr(10) + Str (sector) )
              return_state = "Wrong sectors"
              
              If write = #True
                WriteData(#File, *blank, bps)
              EndIf
          
            Else
              If write = #True
                WriteData(#File, *pmembuf, bps)
              EndIf
  
            EndIf
        
            If position <> last_position Or sector = sectors
                
              If is_error = #True
                change_box_state ( position, "error")
              
              Else
                change_box_state ( position, "set")
               
              EndIf
              is_error = #False
              
            EndIf
              
            last_position = position
              
            Repeat 
              Event = WindowEvent() 
              If Event = #PB_Event_Gadget And EventGadget() = #Start 
                return_state = "Stopped"
                Break 2 
              EndIf 
            Until Not Event 
    
          Next 
          
          FreeMemory(*pmembuf)
          FreeMemory(*blank)
  
        EndIf
        If IsFile(#File)
          CloseFile(#File)
        EndIf        
        
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn return_state

EndProcedure

If OpenWindow(#main_window, 0, 0, 600, 390, "ISO Maker / CD/DVD Checker", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(#main_window))

  TextGadget        (#PB_Any,            10, 15, 60, 20, "Input Drive:")
  ComboBoxGadget    (#Drive_Combo,       80, 10, 70, 100)

  For c = 65 To 90
    If GetDriveType_( Chr(c) + ":\" ) = #DRIVE_CDROM
      AddGadgetItem (#Drive_Combo, -1, Chr(c) + ":")
    EndIf
  Next

  SetGadgetState    (#Drive_Combo, 0)
  
  CheckBoxGadget    (#Check_Only,        180, 12, 150, 20, "Check Only (Don't Copy)")
  TextGadget        (#PB_Any,            410, 15, 150, 20, "Author: Petr Vavrin")
  ButtonGadget      (#Exit,              510, 10,  80, 20, "Exit", #BS_FLAT )
  TextGadget        (#PB_Any,            10,  40,  60, 20, "Output File:")
  StringGadget      (#OutputFile,        80,  35, 420, 20, "", #WS_EX_STATICEDGE | #WS_BORDER)
  ButtonGadget      (#BrowseOutput,      510, 35,  80, 20, "Browse", #BS_FLAT )
  TextGadget        (#PB_Any,            10,  65,  60, 20, "State:")
  TextGadget        (#State,             80,  65, 420, 20, "")
  ButtonGadget      (#Start,             510, 60,  80, 20, "Start", #BS_FLAT )
  
  CreateImage(#boxes_image, #boxes_width, #boxes_height)
  If StartDrawing(ImageOutput(#boxes_image))
    Box(0, 0, #boxes_width, #boxes_width, boxes_image_background)
    StopDrawing()
  EndIf
  
  boxes_left = 10
  boxes_top  = 90

  ImageGadget(#boxes_gadget, boxes_left, boxes_top, #boxes_width, #boxes_height, ImageID(#boxes_image))

  make_blank_box ()
  
  TextGadget        (#PB_Any,            310,   95,  60, 20, "Disk Size:")
  TextGadget        (#PB_Any,            310,  120,  60, 20, "Sectors:")
  TextGadget        (#PB_Any,            310,  145,  75, 20, "Actual Sector:")
  TextGadget        (#PB_Any,            310,  170,  75, 20, "Percents:")
  TextGadget        (#PB_Any,            310,  195,  75, 20, "Wrong Sectors:")
  
  TextGadget        (#Disk_Size,         400,   95,  150, 20, "")
  TextGadget        (#Sectors,           400,  120,  150, 20, "")
  TextGadget        (#Actual_Sector,     400,  145,  150, 20, "")
  TextGadget        (#Percents,          400,  170,  150, 20, "")
  TextGadget        (#Wrong_Sectors,     400,  195,   75, 20, "0")

  ListIconGadget    (#Error_List, 310, 220, 280, 160, "Error #", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines )
  AddGadgetColumn   (#Error_List, 1, "Sector #", 160):

  Repeat
    Event = WaitWindowEvent()

    If Event = #PB_Event_Gadget
  
      If EventGadget() = #BrowseOutput
        last_path.s = GetPathPart(GetGadgetText(#OutputFile))
        
        IIf ( last_path <> "", StandardFile$ = last_path, StandardFile$ = "C:\" )
        File$ = SaveFileRequester("Please choose file to save", StandardFile$, "ISO (*.iso)|*.iso", 0)
              
        If File$
          If UCase ( GetExtensionPart( File$ ) ) <> "ISO"
            File$ + ".iso"
          EndIf
        
          SetGadgetText( #OutputFile, File$ )
        EndIf
      EndIf 
      
      If EventGadget() = #Start

        SetGadgetText ( #Start, "Stop" )
        DisableGadget ( #OutputFile,    #True ) 
        DisableGadget ( #Drive_Combo,   #True ) 
        DisableGadget ( #Check_Only,    #True ) 
        DisableGadget ( #BrowseOutput,  #True ) 
        SetGadgetText ( #Disk_Size,     " " ) 
        SetGadgetText ( #Sectors,       " " ) 
        SetGadgetText ( #Wrong_Sectors, " " )
        SetGadgetText ( #Actual_Sector, " " ) 
        SetGadgetText ( #Percents,      " " ) 

        state.s = Make_ISO ()

        SetGadgetText ( #Start, "Start" )
        DisableGadget ( #Drive_Combo,  #False ) 
        DisableGadget ( #Check_Only,   #False ) 
        
        If GetGadgetState ( #Check_Only ) = 1
          DisableGadget ( #OutputFile,    #True ) 
          DisableGadget ( #BrowseOutput,  #True )
        Else
          DisableGadget ( #OutputFile,    #False ) 
          DisableGadget ( #BrowseOutput,  #False )
        EndIf
        SetGadgetText ( #State, state )

      EndIf
      
      If EventGadget() = #Check_Only
        If GetGadgetState ( #Check_Only ) = 1
          DisableGadget ( #OutputFile,    #True ) 
          DisableGadget ( #BrowseOutput,  #True )
        Else
          DisableGadget ( #OutputFile,    #False ) 
          DisableGadget ( #BrowseOutput,  #False )
        EndIf          
      EndIf
      
      If EventGadget() = #Exit 
        End
      EndIf

    EndIf
     
   Until Event = #PB_Event_CloseWindow
 EndIf
End


Posted: Sat Feb 17, 2007 10:00 pm
by bingo
8) great ... !

Posted: Sun Feb 18, 2007 1:09 am
by PB
Good to see the IIf macro being used in a real-world app. :)

Posted: Sun Feb 18, 2007 1:31 am
by va!n
@peterb:
great work and very good looking and user friendly GUI...

btw, i think IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX should be defined and declared as constant...?

Code: Select all

#IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX  = 147536

Posted: Sun Feb 18, 2007 1:49 am
by peterb
@va!n: yes, you're right :D

Posted: Sun Feb 18, 2007 3:47 am
by Tranquil
Wow!

This is realy great. One hint:

You should change the displaytype of the Disc-Size using StrQ instead of Str like this way:

Code: Select all

 SetGadgetText ( #Disk_Size, StrQ( dg\DiskSize ) + " Bytes" )
So that DVD sizes above 2 Gigs are correctly shown and not as a negative value.

Posted: Sun Feb 18, 2007 12:25 pm
by peterb
Tranquil: thanks for suggestion :)

Posted: Sun Feb 18, 2007 10:37 pm
by SFSxOI
peterb;

is that the latest version of the code posted? with the bug fixes?

Good job, thank you :)

Posted: Sun Feb 18, 2007 11:01 pm
by Num3
Another Nominee for best PB code :D

Posted: Tue Feb 20, 2007 11:28 am
by techjunkie
Very impressive! and all within 375 LOC... Great work! :D

Posted: Tue Feb 20, 2007 3:12 pm
by JCV
very nice piece of code! Thanks!

Posted: Tue Feb 20, 2007 3:28 pm
by Derek
Very good, thanks for sharing. :)

Posted: Sat Mar 03, 2007 10:21 pm
by johnfermor
Excellent job. This'll be great for non-Nero Burning ROM users to create ISO files for use with DaeMon Tools!

Thanks for sharing!

Posted: Sat Mar 03, 2007 10:37 pm
by Edwin Knoppert
Great!
But.. can you make iso's from a folder instead?

PS, i'm using cdburnerxp (3.x) for iso's

http://www.cdburnerxp.se/