Учебно-тренировочная работа

Код:
; PureBasic Visual Designer v3.95 build 1485 (PB4Code)

Import "Kernel32.lib"
    SetFilePointerEx.i(*hFile,liDistanceToMove.q,*lpNewFilePointer,dwMoveMethod.l)
EndImport

;- Window Constants
;
Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants
;
Enumeration
	#Text_0
	#Text_1
	#Text_Size
	#Text_2
	#Text_Count
	#Text_Msg
	#Text_Help
	#String_0
	#String_1
  #Button_Select
  #Button_Start
  #Button_Stop
  #Button_Help
  #ProgressBar_0
EndEnumeration

Global lWorkThreadStarted.b ; рабочий поток запущен
Global lWorkThreadStop.b ; команда на останов потока
Global nWorkThread.l
Global iSectorSize.i ;размер сектора в байтах - нужен для режима #FILE_FLAG_NO_BUFFERING
Define Filename$

Procedure.s GetSysErrorText(ErrCode)
	Define result.s=""
	*Memory = AllocateMemory (255)
	length = FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #Null, ErrCode, 0, *Memory, 255, #Null)
	result=PeekS (*Memory, length - 2)
	FreeMemory (*Memory)
	ProcedureReturn result
EndProcedure

Procedure FatalError() 
   Protected Result$, Line 
   
   Result$="FatalError(): " 
   Line = ErrorLine() 
   If Line>=0 
     Result$+" в строке "+Str(Line)+", файла: "+ErrorFile() 
   EndIf 
   
   Result$+" Ошибка типа: "+Chr(34)+ErrorMessage()+Chr(34) 
   
   MessageRequester("Фатальная ошибка выполнения", Result$, #PB_MessageRequester_Ok )
   End 
EndProcedure

Procedure SaveParams(IniFileName.s) ; сохранить параметры текущей сессии
; сохранить параметры программы
	If CreatePreferences(IniFileName)
    PreferenceGroup("Values")
    WritePreferenceString("File", GetGadgetText(#String_0) )
    ClosePreferences()
	EndIf	
EndProcedure

Procedure.s IntToTrain(In.q, FieldLen.i, delimiter.s) ; Входное число, длина поля ("триады"), разделитель триад
	tmp$=Str(In)
	tmpLen=Len(tmp$)
	dlmLen=Len(delimiter)
	NewLen=0
	; количество "триад" и новая длина
	FieldQty=Int(tmpLen/FieldLen)
	NewLen=FieldQty*FieldLen
	n=tmpLen % FieldLen
	If n>0
    FieldQty+1
    NewLen+n
	EndIf
	NewLen+(FieldQty-1)*dlmLen

	*Result=AllocateMemory(NewLen+1)
	FillMemory(*Result, NewLen+1)
	pr=0 ;pointer of result
	If n>0 ; перенос первой неполной триады
    CopyMemory(@tmp$, *Result, n)
    pr+n
    If FieldQty>1
    	CopyMemory(@delimiter, *Result+pr, dlmLen)
    	pr+dlmLen
    EndIf
	EndIf
	
	p=n+1 
	While p<tmpLen ; перенос полных триад
    CopyMemory(@tmp$+p-1, *Result+pr, FieldLen)
    pr+FieldLen
    If pr<NewLen
    	CopyMemory(@delimiter, *Result+pr, dlmLen)
    	pr+dlmLen    	
    EndIf
    p+FieldLen
	Wend
	ProcedureReturn PeekS(*Result , NewLen )

EndProcedure

Procedure getMyFile()
	Filename$ = OpenFileRequester("Выбрать файл для проверки", "", "Все файлы|*.*", 0)
	If Len(Filename$)>0
    SetGadgetText(#String_0,Filename$)
	EndIf
EndProcedure

Procedure showFileSize()
	Protected Filename$=GetGadgetText(#String_0)

	If Mid(Filename$,2,2)=":\" ;есть буква диска
    Protected SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters
    If GetDiskFreeSpace_( Mid(Filename$,1,3), @SectorsPerCluster, @BytesPerSector, @NumberOfFreeClusters, @TotalNumberOfClusters)
    	iSectorSize=BytesPerSector
    EndIf
	Else
    SetGadgetText(#Text_Msg, "Не могу опознать букву диска")
    ProcedureReturn 
	EndIf

	Protected Result.q = FileSize(GetGadgetText(#String_0))
	If Result<0
    SetGadgetText(#Text_Msg, "Файл не найден")
    SetGadgetText(#Text_Size, "")
	Else
    SetGadgetText(#Text_Size, IntToTrain(Result, 3, " "))
    SetGadgetText(#Text_Msg, "")
    DisableGadget(#Button_Start,0)
	EndIf
	SetGadgetText(#Text_Count, "")
	SetGadgetState(#ProgressBar_0, 100)
EndProcedure

Procedure Start(*Value)
	lWorkThreadStarted=#True
	SetGadgetText(#Text_Msg, "")
	;открыть файл
	File$=GetGadgetText(#String_0)
	Handle=CreateFile_(@File$,#GENERIC_READ,#FILE_SHARE_READ,0,#OPEN_EXISTING,#FILE_FLAG_NO_BUFFERING,0) 
	If Handle=#INVALID_HANDLE_VALUE 
    ErrCode=GetLastError_()
    SetGadgetText(#Text_Msg, "Ошибка открытия файла ErrCode="+Str(ErrCode)+":"+GetSysErrorText(ErrCode))
    CloseHandle_(Handle)
	Else
    DisableGadget(#Button_Start,1)
    DisableGadget(#Button_Stop,0)
    
    ;qFileSize.q=GetFileSize_(Handle, #NUL) ;длина файла
    qFileSize.q=0
    GetFileSizeEx_(Handle,@qFileSize)
    SetGadgetText(#Text_Size, IntToTrain(qFileSize, 3, " ")) ;Str(qFileSize))

    KSize=iSectorSize*256 ;размер буфера
    *Buffer1=AllocateMemory(KSize)
    If *Buffer1
    	nReaded.l=0 ;для возврата количества реально прочитаных байт
    	qCount.q=0 ;прочитано байт от начала файла
    	iOk.i=1 ;флаг успешного завершения операции
        While qCount<qFileSize
        	
        	If SetFilePointerEx(Handle, qCount, #NUL, #FILE_BEGIN) = 0
            ErrCode=GetLastError_()
            SetGadgetText(#Text_Msg, "Ошибка установки позиции чтения файла Err."+Str(ErrCode)+":"+GetSysErrorText(ErrCode))
        	EndIf
        	
        	If ReadFile_(Handle,*Buffer1,KSize,@nReaded,0) = 0
            ErrCode=GetLastError_()
            SetGadgetText(#Text_Msg, "Ошибка чтения файла. ErrCode="+Str(ErrCode)+":"+GetSysErrorText(ErrCode))
            iOk=0
            Break
        	EndIf
        	
 	          	qCount+nReaded
 	          	
 	          	SetGadgetState(#ProgressBar_0, Int(qCount/qFileSize*100))
        SetGadgetText(#Text_Count, Str(Int(qCount/qFileSize*100))+"% "+IntToTrain(qCount, 3, " ")) ;Str(qCount))
        
        If lWorkThreadStop ;прервать проверку
        	SetGadgetText(#Text_Msg, "Чтение файла прервано по требованию пользователя")
        	iOk=0
        	Break
        EndIf
        
    	Wend    
	
         FreeMemory(*Buffer1)
         If iOk
         	SetGadgetText(#Text_Msg, "Читабельность файла - Ok")
         EndIf

    Else
    	SetGadgetText(#Text_Msg, "Ошибка при выделении памяти под буфер. ErrCode="+Str(ErrCode)+":"+GetSysErrorText(ErrCode))
    EndIf
    CloseHandle_(Handle)
    
    DisableGadget(#Button_Start,0)
    DisableGadget(#Button_Stop,1)
    DisableGadget(#ProgressBar_0,1)
	EndIf
	lWorkThreadStarted=#False
EndProcedure

Procedure Open_Window_0()
  Protected Result.b= #False
  If OpenWindow(#Window_0, 281, 107, 570, 99, "Проверка читабельности файла (r) SadStar",  #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)

      TextGadget(#Text_0, 10, 10, 50, 20, "Файл : ", #PB_Text_Right)
      StringGadget(#String_0, 60, 10, 440, 20, "")
      TextGadget(#Text_1, 10, 40, 50, 20, "Размер : ", #PB_Text_Right)
      TextGadget(#Text_Size, 60, 40, 110, 20, "0", #PB_Text_Right)
      TextGadget(#Text_2, 10, 60, 50, 20, "Считано : ", #PB_Text_Right)
      TextGadget(#Text_Count, 60, 60, 110, 20, "0", #PB_Text_Right)
      TextGadget(#Text_Msg, 180, 40, 320, 35, "0")
      SetGadgetColor(#Text_Msg, #PB_Gadget_FrontColor, #Red)

      
      ButtonGadget(#Button_Select, 510, 10, 50, 20, ". . .")
      ButtonGadget(#Button_Start, 510, 43, 50, 20, "Start")
      DisableGadget(#Button_Start,1)
      ButtonGadget(#Button_Stop, 510, 75, 50, 20, "Stop")
      DisableGadget(#Button_Stop,1)
      ProgressBarGadget(#ProgressBar_0, 60, 80, 440, 10, 0, 10, #PB_ProgressBar_Smooth )
      SetGadgetAttribute(#ProgressBar_0, #PB_ProgressBar_Minimum, 0)
      SetGadgetAttribute(#ProgressBar_0, #PB_ProgressBar_Maximum, 100)
      SetGadgetState(#ProgressBar_0, 100)
      DisableGadget(#ProgressBar_0,1)
      ButtonGadget(#Button_Help, 5, 75, 50, 20, "???" , #PB_Button_Toggle)
      
      TextGadget(#Text_Help, 60, 100, 440, 140, "TextGadget Border", #PB_Text_Border)
      Text$="Эта утилита проверяет читабельность файла с носителя."+#CRLF$
      Text$+"Просто читает файл от начала и до конца."+#CRLF$
      Text$+"Если попадется 'битый' участок файла - остановится по ошибке."+#CRLF$
      Text$+"Обычно я проверял читабельность файлов (например - киношки на CD/DVD) методом копирования."+#CRLF$
      Text$+"Но для больших файлов нужно большое место для приема файлов."+#CRLF$
      Text$+"Да еще антивирус кидается его проверять..."+#CRLF$
      Text$+"Т.ч. с этой утилитой будет проще жить."+#CRLF$
      Text$+"20/06/2012"+#CRLF$
      Text$+"SadStar"+#CRLF$
      SetGadgetText(#Text_Help, Text$)
      
	Result=#True
  EndIf
  ProcedureReturn Result
EndProcedure

OnErrorCall(@FatalError())
 
ProgName$ = ProgramFilename() ;полное имя файла самой исполняемой программы
IniFileName$ = Left(ProgName$, Len(ProgName$)-3)+"ini" ;полное имя ini-файла

If Not Open_Window_0(): End: EndIf
;{ Восстановление параметров
If OpenPreferences(IniFileName$)
	If PreferenceGroup("Values")
    ; восстанавливаем параметры последнего сеанса работы с программой
    SetGadgetText(#String_0, ReadPreferenceString("File", ""))
	EndIf
	ClosePreferences()
EndIf
;}

showFileSize()

;{- Event loop
Repeat
	Event = WaitWindowEvent() ; ждать события
	EventWindow = EventWindow() ; какое окно поимело событие
	Select Event
    	; ------------------------------
    Case #PB_Event_Gadget
    	EventGadget = EventGadget()
    	EventType = EventType()
    	If EventGadget = #Button_Select
        getMyFile()
        showFileSize()
    	ElseIf EventGadget = #Button_Start
        	; запустить поток обработки
        	lWorkThreadStarted=#False
        	lWorkThreadStop=#False
        	nWorkThread = CreateThread(@Start(), 0)
        	If Not nWorkThread
            SetGadgetText(#Text_Msg, "Поток обработки не создан. ErrCode="+Str(ErrCode)+":"+GetSysErrorText(ErrCode))
        	EndIf
    	ElseIf EventGadget = #Button_Stop
        	; остановить поток обработки
        	lWorkThreadStop=#True
    	ElseIf EventGadget = #Button_Help
        If GetGadgetState(#Button_Help) 
        	ResizeWindow(#Window_0, #PB_Ignore, #PB_Ignore, #PB_Ignore, WindowHeight(#Window_0) +150) 
        Else
        	ResizeWindow(#Window_0, #PB_Ignore, #PB_Ignore, #PB_Ignore, WindowHeight(#Window_0) -150)
        EndIf

    	EndIf
    	; ----------------------------

    Case #PB_Event_CloseWindow
    	If EventWindow = #Window_0
        SaveParams(IniFileName$)
        If lWorkThreadStarted And IsThread(nWorkThread)
        	KillThread(nWorkThread)
        EndIf
        CloseWindow(#Window_0)
        Break
    	EndIf
	EndSelect
ForEver
;}

End