Что нового

[Процессы] Использование WinRAR в скрипте

freed21

Новичок
Сообщения
39
Репутация
1
Здравствуйте, друзья. В своем скрипте мне приходится пользоваться WinRar'ом, есть GUI, в котором выбираем что и куда распаковывать, потом при помощи ShellExecuteWait запускается программа распаковки. Вопрос: как считать коды возвращаемых WinRarом ошибок и можно ли прогресс бар распаковки WinRARа отобразить в GUI скрипта?
В ини-файле должно быть что-то типа
[Destination]
Dest.1 = C:\Temp


Код:
#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <ProgressConstants.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <ListBoxConstants.au3>
#include <GuiListBox.au3>
#include <GuiRichEdit.au3>

#Region ### START Koda GUI section ###
$ImportForm = GUICreate("Импорт файлов", 322, 458, 733, 343)
$ImportProgress = GUICtrlCreateProgress(10, 430, 300, 17, BitOR($PBS_SMOOTH,$WS_BORDER))
$Output = GUICtrlCreateCombo("", 10, 190, 300, 25, $CBS_DROPDOWNLIST)
$ImportInfo = _GUICtrlRichEdit_Create($ImportForm,"", 10, 220, 300, 175, BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL,$ES_READONLY))
$FileInfo= GUICtrlCreateList("", 10, 35, 300, 150, BitOR($ES_AUTOVSCROLL,$ES_WANTRETURN,$WS_VSCROLL,$GUI_SS_DEFAULT_LIST,$LBS_NOINTEGRALHEIGHT), $WS_EX_STATICEDGE)
GUICtrlSetData(-1, "")
$ButtonImport = GUICtrlCreateButton("Импортировать файлы", 10, 400, 300, 25, $WS_GROUP)
$LabelAdd = GUICtrlCreateLabel("Добавьте файл в список импорта", 10, 10, 180, 21)
$ButtonClear = GUICtrlCreateButton("", 275, 0, 35, 35,$BS_ICON)
GUICtrlSetImage($ButtonClear, "imageres.dll", -85)
GUICtrlSetTip($ButtonClear, "Очистить список")
$ButtonMinus = GUICtrlCreateButton("", 235, 0, 35, 35,$BS_ICON)
GUICtrlSetImage($ButtonMinus, "shell32.dll", -235)
GUICtrlSetTip($ButtonMinus, "Удалить файл из списка")
$ButtonPlus = GUICtrlCreateButton("", 195, 0, 35, 35,$BS_ICON)
GUICtrlSetImage($ButtonPlus, "shell32.dll", -280)
GUICtrlSetTip($ButtonPlus, "Добавить файл в список")
GUISetState(@SW_SHOW)

;#########################################  INI  #####################################################

$iniDir = IniReadSection("INI.ini", "Directory")
;_ArrayDisplay($iniDir)
$iniDirDef = IniRead("INI.ini", "LastDestination", "LastDest", "")
If Not $iniDir then
   $iniDirNum = $iniDir[0][0]
   For $i=1 to $iniDirNum
	  GUICtrlSetData($Output, $iniDir[$i][1], $iniDirDef)
   Next
EndIf


$iniList = IniReadSection("INI.ini", "LastImportList")
If Not $iniList then
   $iniListNum = $iniList[0][0]
   For $i=1 to $iniListNum
	  GUICtrlSetData($FileInfo, $iniList[$i][1])
   Next
EndIf

;########################################   INI   ####################################################

#EndRegion ### END Koda GUI section ###

While 1
$nMsg = GUIGetMsg()
Switch $nMsg

   Case $GUI_EVENT_CLOSE
	  IniDelete ("INI.ini", "LastImportList")
	  $sList_String = ""
	  $iCount = _GUICtrlListBox_GetCount($FileInfo)
	  For $i = 0 To $iCount-1
		 $sList_String = _GUICtrlListBox_GetText($FileInfo, $i)
		 IniWrite("INI.ini" ,"LastImportList", "File."&$i, $sList_String)
	  Next
	  IniWrite("INI.ini" ,"LastDestination", "LastDest", GuiCtrlRead($Output))
	  _GUICtrlRichEdit_Destroy($ImportInfo)
	  Exit

   Case $ButtonPlus
	  $FileName = FileOpenDialog("Выберите файл", "C:\Temp", "Файлы (*.dat)", 1 + 2 + 4)
	  $MassFile = StringSplit($FileName,"|")
	  If $MassFile[0]==1 Then
		 If $MassFile[1] <> "" then GUICtrlSetData($FileInfo, $MassFile[1], 1)
	  Else
		 For $i=1 to $MassFile[0]-1
			GUICtrlSetData($FileInfo, $MassFile[1]&"\"&$MassFile[$i+1], 1)
		 Next
	  EndIf

   Case $ButtonMinus
	  $tmp = GUICtrlSendMsg($FileInfo, $LB_GETCURSEL, 0, 0)
	  GUICtrlSendMsg($FileInfo, $LB_DELETESTRING, $tmp, 0)

   Case $ButtonClear
	  GUICtrlSetData($FileInfo, "")

   Case $ButtonImport
	  $ListCount = GUICtrlSendMsg($FileInfo, $LB_GETCOUNT, 0, 0)
	  $PercentFile = 100/$ListCount
	  $sList_String = ""
	  $iCount = _GUICtrlListBox_GetCount($FileInfo)
	  If Not $iCount then
		 MsgBox(0,"Предупреждение", "Список для импортирования пуст")
	  Else
		 If Not GuiCtrlRead($Output) then
			MsgBox(0,"Предупреждение", "Выберите папку для распаковки архива")
		 Else
			GUICtrlSetState($ButtonClear,$GUI_DISABLE)
			GUICtrlSetState($ButtonMinus,$GUI_DISABLE)
			GUICtrlSetState($ButtonPlus,$GUI_DISABLE)
			GUICtrlSetState($Output,$GUI_DISABLE)
			_GUICtrlRichEdit_SetCharAttributes($ImportInfo, "+bo")
			_GUICtrlRichEdit_AppendText($ImportInfo,'Импортирование файлов('&$ListCount&')'&@CR)
			For $i=0 to $ListCount-1
			   $File = _GUICtrlListBox_GetText($FileInfo, $i)
			   $FName = StringRegExp($File, "([^.\\]+)\.", 1)
			   _GUICtrlRichEdit_AppendText($ImportInfo, $FName[0]&'.dat')
			   $Command = "C:\Program Files\WinRAR\WinRAR.exe"
			   $Param = 'x -ad -o- '&$File&' '&GuiCtrlRead($Output)&'\'
			   $iPID = ShellExecuteWait($Command, $Param)
			   GUICtrlSetData($ImportProgress,$PercentFile*($i+1))
			   $ImportWay = GuiCtrlRead($Output)&'\'&$FName[0]&'\ExportData\'
			   _GUICtrlRichEdit_SetCharAttributes($ImportInfo, "+it")
			   _GUICtrlRichEdit_AppendText($ImportInfo,'  -- импортировано'&@CR)
			Next
			_GUICtrlRichEdit_SetCharAttributes($ImportInfo, "+bo")
			_GUICtrlRichEdit_AppendText($ImportInfo,'Импортирование завершено'&@CR)
			_GUICtrlRichEdit_AppendText($ImportInfo,'--------------------------------------------------------------------------------------------'&@CR)
			GUICtrlSetState($ButtonClear,$GUI_ENABLE)
			GUICtrlSetState($ButtonMinus,$GUI_ENABLE)
			GUICtrlSetState($ButtonPlus,$GUI_ENABLE)
			GUICtrlSetState($Output,$GUI_ENABLE)
		 EndIf
	  EndIf
   EndSwitch
WEnd
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Читайте внимательнее справку. ShellExecuteWait() возвращает не PID, а код завершения процесса. Для прогресса вам нужно будет использовать Run() и $STDOUT_CHILD. Если WinRAR в процессе распаковки ничего не выводит в консоль, то все плохо. :smile:
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Хорошо, но мне нужно прочитать код возврата WinRAR (их можно посмотреть в справке винрар/режим командной строки/коды возврата Winrar). Как это можно сделать?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
freed21 сказал(а):
Хорошо, но мне нужно прочитать код возврата WinRAR (их можно посмотреть в справке винрар/режим командной строки/коды возврата Winrar). Как это можно сделать?
Вот ShellExecuteWait() и вернет этот код возврата.
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Тогда тут что-то не сходится. Я запускаю скрипт, выбираю файл для распаковки, открывается окошко процесса разархивации, я его закрываю, но ShellExecuteWait мне возвращает 0, хотя должен согласно справке вернуть 255(Операция прервана пользователем)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
freed21 сказал(а):
Тогда тут что-то не сходится. Я запускаю скрипт, выбираю файл для распаковки, открывается окошко процесса разархивации, я его закрываю, но ShellExecuteWait мне возвращает 0, хотя должен согласно справке вернуть 255(Операция прервана пользователем)
Попробуйте заменить ShellExecuteWait() на RunWait(), и напишите что вернет функция.
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Я пробовал и RunWait уже. В случае успешного завершения и в случае прерванной пользователем операции возвращает 0. Наверно вернее будет узнать в какую системную переменную WinRAR отправляет код возврата и как-то ее считать.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
freed21 сказал(а):
Я пробовал и RunWait уже. В случае успешного завершения и в случае прерванной пользователем операции возвращает 0. Наверно вернее будет узнать в какую системную переменную WinRAR отправляет код возврата и как-то ее считать.
Код возврата - это код завершения процесса. Например, если в скрипте написать "Exit 1", то код возврата будет 1. Для проверки правильности возврата кодов WinRAR, попробуйте распаковать заведомо битый архив (файл нулевой длины), и посмотрите что он вернет. Здается мне, что закрытие окна не воспринимается WinRAR'ом как прерывание пользователем (всякое бывает).
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Попробовал убить архив, открыв текстовым редактором и дописав символов. Через скрипт попробовал распаковать его, сначала выдает MsgBoх "Архивы не найдены", но и RunWait и ShellExecuteWait возвращают 0... :stars:


Добавлено:
Сообщение автоматически объединено:

Хотя нет, извиняюсь, возвращают 1. Но это в случае с битым архивом и согласно справке AutoIt. А как получить коды возврата именно WinRAR, когда в соответствии с каждым событием отправляется свой код возврата.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
OffTopic:
freed21
используй 7Zip. есть UDF для работы с dll
например http://autoit-script.ru/index.php?topic=18264.0
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Ситуация такая, что все это дело должно работать именно с WinRAR, а не с 7-зип. И пишется это не для меня, а для пользователей, которые могут начудить во время использования программы (начать закрывать окно архиватора - одно из этого). Поэтому распознавать битый архив не так важно, как перехватывать код закрытия RAR пользователем.


Добавлено:
Сообщение автоматически объединено:

И ,если возможно, поясните, как можно из консоли при использовании консольной RAR выхватывать проценты распаковки без бегущих строк (распакованных из архива файлов).


Добавлено:
Сообщение автоматически объединено:

Если удастся поместить прогресс бар с распаковкой в GUI скрипта, то проблема со считыванием кода возврата отпадет сама собой, потому что у пользователя не будет возможности закрыть окошко архиватора во время распаковки (все будет происходить в консоли в режиме HIDE). Но в любом случае следить за прогрессом нужно, потому что архивы на вход будут подаваться довольно большие, вплоть до 10 гигабайт.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
freed21 [?]
Ситуация такая, что все это дело должно работать именно с WinRAR, а не с 7-зи
это понятно, но лучше бесплатный 7Z и рабочая библиотека под него, чем платный Winrar и костыли для работы с ним
 

Prog

Продвинутый
Сообщения
537
Репутация
65
Не лучше будет сделать самораспаковывающийся архив? В крайнем случае, прицепить к скрипту DLL самораспаковывающегося архива. Тогда не будет проблем с кодами ошибок, прогрессбаром и окнами WinRARа.
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Архивы делаю не я, они поступают из другой программы
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
freed21,
Попробуйте распаковывать консольным Rar.exe, читать его через StdoutRead() и парсить полученный текст. При запаковке он пишет в консоль процент выполнения, при распаковке - проверьте сами.
 
Автор
F

freed21

Новичок
Сообщения
39
Репутация
1
Возвращаемые значения WinRAR мне наконец-то удалось получить :smile: Не могли бы на моем коде показать, как при помощи StdOut получать данные из консоли, а то я перепробовал разные варианты и всегда пустоту получаю, спасибо большое за советы :smile:
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
freed21 [?]
как при помощи StdOut получать данные из консоли, а то я перепробовал разные варианты и всегда пустоту получаю, спасибо большое за советы


Код:
Global $iPid, $sText

$iPid = Run("program.exe /params", "", @SW_SHOW, 6)
While ProcessExists($iPid)
$sText &= StdoutRead($iPid)
Sleep(100)
WEnd
MsgBox(0, "Прочитанный текст", $sText)



Добавлено:
Сообщение автоматически объединено:

Если программа будет выводить русские символы и будет неверная кодировка, то используя функцию _Encoding_866To1251 () из Encoding UDF можно перевести...
 

Cornet

Знающий
Сообщения
41
Репутация
6
Раз уж тема есть, то пусть будет тут.

Написал для себя небольшую функцию по добавлению в архив RAR.
Может кому пригодится ;)

Функция работает только с русским Rar
Внимание! Функция удаляет архив если он уже существует.
Код:
#include <Constants.au3>
#include <StaticConstants.au3>

#include <Encoding.au3>
#include <Date.au3>

$ArcFileName = "D:\file.rar"
$FileToArc = '"' & "D:\file.ext" & '"'
$FileToArc &= ' "' & "D:\file1.ext" & '"'
$FileToArc &= ' "' & "D:\file2.ext" & '"'
$FileToArc &= ' "' & "D:\file3.ext" & '"'
$FileToArc &= ' "' & "D:\file4.ext" & '"'

RarAdd($ArcFileName, $FileToArc)

Func RarAdd($ArcFileName, $FileToArc, $RarPatch = "")
	If Not FileExists($RarPatch) Then $RarPatch = StringRegExpReplace(RegRead("HKEY_CLASSES_ROOT\Applications\WinRAR.exe\shell\open\command", ""), ".(.+\\).+", "$1") & "Rar.exe"
	If Not FileExists($RarPatch) Then $RarPatch = StringRegExpReplace(RegRead("HKEY_CLASSES_ROOT\WinRAR\shell\open\command", ""), ".(.+\\).+", "$1") & "Rar.exe"
	If Not FileExists($RarPatch) Then Return -1
	Local  $WinRarPatch = StringRegExpReplace($RarPatch, "Rar\.exe", "WinRar.exe")

	Local $hTimer, $Secs, $Mins, $Hour, $Time, $oDiff, $tDiff, $oProc
	Local $eSecs, $eMins, $eHour
	Local $proc[1] = [0]
	Local $i = 0

	If FileExists($ArcFileName) Then FileDelete($ArcFileName) ;!Удаляет архив если он уже существует

	$aFiles = StringSplit(StringReplace(StringTrimRight(StringTrimLeft($FileToArc, 1), 1), '" "', '…'), '…')

	#Region ### START Koda GUI section ### Form=
	$Form1 = GUICreate("Создание архива", 365, 190)
	If FileExists($WinRarPatch) Then GUISetIcon($WinRarPatch)
	$Group1 = GUICtrlCreateGroup("", 16, 16, 330, 78)
	$Label1 = GUICtrlCreateLabel("Архив ", 24, 28, 37, 17)
	$Label2 = GUICtrlCreateLabel("Добавление", 24, 43, 67, 17)
	$lArhName = GUICtrlCreateLabel($ArcFileName, 71, 28, 266, 17)
	$lFileName = GUICtrlCreateLabel("", 24, 58, 250, 17)
	$lProgress = GUICtrlCreateLabel("0%", 308, 58, 30, 17, $SS_RIGHT)
	$pProgress = GUICtrlCreateProgress(24, 72, 314, 12)
	GUICtrlCreateGroup("", -99, -99, 1, 1)
	$Group2 = GUICtrlCreateGroup("", 16, 104, 330, 46)
	$Label4 = GUICtrlCreateLabel("Прошло времени", 24, 116, 91, 17)
	$lTime1 = GUICtrlCreateLabel("00:00:00", 296, 116, 46, 17)
	$Label6 = GUICtrlCreateLabel("Примерно осталось", 24, 131, 106, 17)
	$lTime2 = GUICtrlCreateLabel("00:00:00", 296, 131, 46, 17)
	GUICtrlCreateGroup("", -99, -99, 1, 1)
	$Cancel = GUICtrlCreateButton("Отмена", 271, 155, 75, 25)
	GUISetState(@SW_SHOW)
	#EndRegion ### END Koda GUI section ###

	$hTimer = TimerInit()
	$pidRar = Run($RarPatch & ' a -m5 -ep "' & $ArcFileName & '" ' & $FileToArc, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
	If @error Then Return -2

	While 1
		$tDiff = TimerDiff($hTimer)
		If $tDiff - $oDiff > 999 Then
			$oDiff = $tDiff
			_TicksToTime(Int($tDiff), $Hour, $Mins, $Secs)
			$Time = StringFormat("%02i:%02i:%02i", $Hour, $Mins, $Secs)
			GUICtrlSetData($lTime1, $Time)
			If IsArray($proc) And $proc[0] > 0 Then
				If $oProc <> $proc[0] Then
					$expectedTime = $tDiff * 100 / $proc[0] - $tDiff
					_TicksToTime(Int($expectedTime), $eHour, $eMins, $eSecs)
					$Time = StringFormat("%02i:%02i:%02i", $eHour, $eMins, $eSecs)
					GUICtrlSetData($lTime2, $Time)
					$oProc = $proc[0]
				Else
					If $eSecs > 0 Then
						$eSecs -= 1
					Else
						$eMins -= 1
						$eSecs = 59
					EndIf
					$Time = StringFormat("%02i:%02i:%02i", $eHour, $eMins, $eSecs)
					GUICtrlSetData($lTime2, $Time)
				EndIf
			EndIf
		EndIf

		$nMsg = GUIGetMsg()
		If $nMsg = -3 Or $nMsg = $Cancel Then
			StdioClose($pidRar)
			ProcessClose($pidRar)
			Return 0
		EndIf
		$sOut = StdoutRead($pidRar, False)
		If @error Then Return -3
		$sOut = _Encoding_866To1251($sOut)
		If $sOut Then
			$fstart = StringRegExp($sOut, "(?m)Добавление", 3)
			If Not @error Then
				$i += 1
				GUICtrlSetData($lFileName, $aFiles[$i])
				$fs = FileGetSize($aFiles[$i])
			EndIf
			$proc = StringRegExp($sOut, "\d+(?=%)", 1)
			If Not @error Then
				GUICtrlSetData($pProgress, $proc[0])
				GUICtrlSetData($lProgress, $proc[0] & "%")
			EndIf
			If StringRegExp($sOut, "Готово") Then Return 1
		EndIf
	WEnd
EndFunc   ;==>RarAdd
 
Верх