Что нового

Как подавить вывод стандартного звука при выводе окна?

gora

Знающий
Сообщения
315
Репутация
19
Запускаю ехе файл в скрытом режиме, окно его невидимо, но из-за наличия в нем стандартной иконки (например, восклицательный знак в желтом треугольнике) раздается "предательский" стандартный звук. Это раздражает пользователя и порождает у него вопросы (А что это там "блямкает"?).
Есть ли возможность подавлять вывод этих звуков при выводе скрытых окон, но чтобы при выводе остальных окон звуки функционировали нормально?
Спасибо.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
Есть ли возможность подавлять вывод этих звуков при выводе скрытых окон
Можно например приглушить звук в течений нескольких секунд после запуска программы, а потом восстановить его.
 

Arei

Скриптер
Сообщения
938
Репутация
115
вот пример идея как у CreatoR
Код:
Send("{VOLUME_DOWN 100}")
Sleep (1000)
Send("{VOLUME_UP 100}")


время сам выставь на сколько надо.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Arei [?]
вот пример идея как у CreatoR
Я немного подругому себе это представлял:

Код:
$iOld_Vol = _SoundGetWaveVolume()

SoundSetWaveVolume(0)
Run("Prog.exe")
Sleep(2000)
SoundSetWaveVolume($iOld_Vol)

Func _SoundGetWaveVolume()
    Local $WaveVol = -1, $stVol, $ret
	Local Const $MMSYSERR_NOERROR = 0
	
    $stVol = DllStructCreate("dword")
	
    If @error Then
        Return SetError(2, 0, -2)
    EndIf
	
    $ret = DllCall("winmm.dll", "long", "waveOutGetVolume", "hwnd", -1, "ptr", DllStructGetPtr($stVol))
	
    If ($ret[0] == $MMSYSERR_NOERROR) Then
        $WaveVol = Round(Dec(StringRight(Hex(DllStructGetData ($stVol, 1), 8), 4)) / 0xFFFF * 100)
    Else
        SetError(1)
    EndIf
	
    $stVol = ""
	
    Return $WaveVol
EndFunc
 

Arei

Скриптер
Сообщения
938
Репутация
115
да уж, но я ведь по простому :smile:, но в каком то смысле то же работает.
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
Вариант от Arei не устроил по двум причинам:
1 Слишком большая длительность выполнения самой команды Send (мне желательно минимальное время выполнения)
2 Звук после выхода максимальный, а не тот что был установлен в системе (это плохо)
Вариант от CreatoR и работает быстрей и уровень звука сохраняет, но... Он у меня отработал прекрасно на win XP, а вот на win 7 (x64) не сработал - звук не гасится.
Он не универсален для разных систем?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
на win 7 (x64) не сработал
Да, на Vista и выше функция SoundSetWaveVolume применяется только к самому скрипту, и об этом написано в справке.
Нужно искать альтернативы...
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Нужно искать альтернативы...
Почти нашел.
Код:
Send("{VOLUME_MUTE}")
Run("Prog.exe")
Send("{VOLUME_MUTE}")
Но появляется другой непонятный баг.
Этих окон у меня выводится несколько (до восьми) в цикле, а после цикла выводится свое окно в котором курсор устанавливается на кнопку по умолчанию. Так вот с этим Send, курсор не устанавливается, а без него или с Вашим вариантом курсор встает куда указано. Какая тут связь с Send, не понимаю... :(
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
после цикла выводится свое окно в котором курсор устанавливается на кнопку по умолчанию
Пример этого окна можно?
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
AZJIO [?]
А что если сделать функцию дочернего окна?
Не понял. 8 окон, что выводятся в цикле, создаются сторонним приложением, а последнее создается скриптом. О каком дочернем окне идет речь?AZJIO [?]
Или воспользоваться UDF ExtMsgBox.
Можно подробнее?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR сказал(а):
Да, на Vista и выше функция SoundSetWaveVolume применяется только к самому скрипту, и об этом написано в справке.

Если запустить скрипт в режиме совместимости XP, то должно работать как в XP.

:smile:

А вообще, все системные звуки прописаны в реестре, можно необходимые отключить на время...
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Пример этого окна можно?
Можно, только не уверен, что дело в нем. Хотя в окне и есть возможность принудительно устанавливать курсор мыши на кнопку по умолчанию, но в случае, про который идет речь выше, это фича не используется. Курсор мыши устанавливается на кнопку по умолчанию силами самой системы (отмечен соответствующий чекбокс в свойствах мыши).
Код:
; Универсальное окно
#Include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <Misc.au3>
#include <StaticConstants.au3>

$presskey = BitOR(_IsPressed('10'), 2 * _IsPressed('11'), 4 * _IsPressed('12'))

$codeKey = 0
$criptArchive = 0
$criptHdr = 1
$PassWord = "PassWord"
$inputPass = ""

$allWinSFX = 8
$v56 = 'Это не окно вашего архива'
$v57 = 'Закрыть все окна архива'
$v58 = 'сразу'
$v64 = "c"
$v82 = "Шифрование"
$v83 = "Шифровать архив"
$v84 = "Шифровать заголовки файлов"
$v85 = "Введите пароль"

_Window("!!! " & $v56 & " !!!", $v57 & " (" & $allWinSFX & ") " & $v58 & "? ", "OK", 1, 1, 0, @DesktopWidth - 280, @DesktopHeight - 145, 10)

;$Title="Архивирование папок/файлов"
;$Text="Размер выделенных папок/файлов" & @TAB & "20 123 456 789" & @LF & "Выбранный размер словаря (МБ)" & @TAB & "32" & @LF & "Выбранный метод сжатия" & @TAB & "LZMA" & @LF & @LF & "1. Создать solid архив с максимальным сжатием" & @LF & "2. Создать non-solid архив" & @LF & "3. Создать архив без сжатия" & @LF & "4. Создать solid архив с максимальным сжатием" & @LF & "    консольным архиватором"

;$TextButton="1 вариант" & @TAB & "2 вариант" & @TAB & "3 вариант" & @TAB & "4 вариант" & @TAB & "Отмена"
;_Window($Title,$Text,$TextButton,1,5,1,-1,-1,10)

;$TextButton="1 вариант" & @TAB & "2 вариант" & @TAB & "3 вариант"
;_Window($Title,$Text,$TextButton,4)
;_Window($Title,$Text,$TextButton,3)
;_Window($Title,$Text,$TextButton,2)

Exit

;----------------------------------------------------------------------
Func _Window($Title,$Text,$TextButton,$Icon=2,$Focus=1,$Pass=0,$pozX=-1,$pozY=-1,$timer=0)
;	универсальное окно
	Opt('MouseCoordMode', 2)
	$nDefButton = ''
;	число строк
	$array = StringSplit($Text, @LF)
;	расчет ширины окна по самой длинной строке
	$widthWind = 0
	For $i = 1 To $array[0]
		$space = StringSplit($array[$i], @TAB, 1)
		$width = StringLen($array[$i])*5.65 + 60 + $space[0]*10; - ($space[0]*0.65)
		If $widthWind < $width Then $widthWind = $width
	Next
;	расчет ширины окна по числу кнопок
	$buttons = StringSplit($TextButton, @TAB)
	$widthButton = 65
	$step = 5
	If $step*($buttons[0]+1)+$widthButton*$buttons[0] > $widthWind Then
		$widthWind = $step*($buttons[0]+1)+$widthButton*$buttons[0]
		$leftotstup = 0
	Else
		$leftotstup = ($widthWind-$widthButton*$buttons[0]-$step*($buttons[0]-1))/2
	EndIf
;	расчет высоты окна
	$textHeight = $array[0]*16+15
	$heightWind = $textHeight+40
	If $Pass Then $heightWind+=85
;	создание окна
	$hGui = GUICreate($Title, $widthWind+6, $heightWind + 30, $pozX, $pozY, $WS_SYSMENU)
;	задание иконки и шрифта для окна
	GUISetFont(8.5, 400, 0, "Tahoma")
;	GUISetIcon("Button.exe")  

;	Вывод кнопок с центрированием
	For $i = 1 To $buttons[0]
		$button=GUICtrlCreateButton($buttons[$i], $leftotstup+$step*$i+$widthButton*($i-1), $heightWind-35, $widthButton, 25)
		If $i = $Focus Then
			GUICtrlSetState(-1, BitOR($GUI_FOCUS, $GUI_DEFBUTTON))
			$focButW = $leftotstup+$step*$i+$widthButton*($i-1)+$widthButton/2
			$focButH = $heightWind-35+25/2
			$nDefButton = $button
			$sDefButtonText = $buttons[$i]
		EndIf
	Next

;	Вывод Текста
	For $i = 1 To $array[0]
		$subline = StringSplit($array[$i], @TAB)
		GUICtrlCreateLabel($subline[1], 50, 10+16*($i-1), $widthWind-60)
		If $subline[0] > 1 Then
			$widthNumber = StringLen($subline[2])*5.65 + 5
			GUICtrlCreateLabel($subline[2], 50 + $widthWind-60 - $widthNumber, 10+16*($i-1), $widthNumber, -1, $SS_RIGHT)
		EndIf
	Next

;	Вывод поля Шифрование
	If $Pass Then
		GUICtrlCreateGroup($v82, 5, $textHeight, $widthWind-10, 85)
		; CHECKBOX
		$check1 = GuiCtrlCreateCheckbox($v83, 15, $textHeight+20, $widthWind-25, 14)
		$nextfield=$GUI_DISABLE
		If $criptArchive = 1 Then
			$nextfield=$GUI_ENABLE
			GUICtrlSetState(-1, $GUI_CHECKED)
		EndIf
		; CHECKBOX
		$check2 = GuiCtrlCreateCheckbox($v84, 15, $textHeight+40, $widthWind-25, 14)
		If $criptHdr = 1 Then GUICtrlSetState(-1, $GUI_CHECKED)
		GUICtrlSetState(-1, $nextfield)
		; INPUT
		$input1 = GUICtrlCreateLabel($v85 & ":", 15, $textHeight+60)
		GUICtrlSetState(-1, $nextfield)
		$input2 = GuiCtrlCreateInput($PassWord, 105, $textHeight+60-3, $widthWind-120, 20)
		GUICtrlSetState(-1, $nextfield)
		GUICtrlCreateGroup("", -99, -99, 1, 1)  ;close group
	EndIf
;	Вывод иконки: 1 - !, 2 - ?, 3 - X, 4 - i
	GUICtrlCreateIcon("user32.dll", $Icon + 100, 10, 10)
	GUISetState()  ; display the GUI
;	Вывод звука иконки
	If $Icon = 1 Then $iMessageBeep = 0x00000030
	If $Icon = 2 Then $iMessageBeep = -1
	If $Icon = 3 Then $iMessageBeep = 0x00000010
	If $Icon = 4 Then $iMessageBeep = 0x00000040
	DllCall("user32.dll", "int", "MessageBeep", "int", $iMessageBeep)
;	перевод мышки на кнопку в фокусе
	If $presskey >0 Then
		WinSetOnTop($hGui, "", 1)
		If RegRead("HKCU\Control Panel\Mouse", "SnapToDefaultButton") = 1 Then MouseMove($focButW, $focButH, 0)
	EndIf
;	таймер
	If $timer > 0 Then
		$iCounter = $timer
		$timer = TimerInit()
		GUICtrlSetData($nDefButton, $sDefButtonText & ' (' & $iCounter & ' ' & $v64 & ')')
	EndIf
	Do
	$codeKey = GUIGetMsg()
		If $timer > 0 Then
			If TimerDiff($timer) >= 1000 Then
				$timer = TimerInit()
				$iCounter -= 1
				If $iCounter <= 0 Then $codeKey = $GUI_EVENT_CLOSE
				GUICtrlSetData($nDefButton, $sDefButtonText & ' (' & $iCounter & ' ' & $v64 & ')')
			EndIf
			If _IsPressed('25') + _IsPressed('27') > 0 Then
				GUICtrlSetData($nDefButton, $sDefButtonText)
				$timer = 0
			EndIf
		EndIf
		If $Pass AND $codeKey = $check1 Then
			$nextfield=$GUI_DISABLE
			If GUICtrlRead($check1) = $GUI_CHECKED Then $nextfield=$GUI_ENABLE
			GUICtrlSetState($check2, $nextfield)
			GUICtrlSetState($input1, $nextfield)
			GUICtrlSetState($input2, $nextfield)
		EndIf
		If $codeKey = $GUI_EVENT_CLOSE Then
			$codeKey = $buttons[0]
		Else
			$codeKey -= 2
		EndIf
	Until $codeKey > 0 AND $codeKey <= $buttons[0]
	
	$criptArchive = 0
	$criptHdr = 0
	$inputPass = ""
	If $Pass Then 
		If GUICtrlRead($check1) = $GUI_CHECKED Then $criptArchive = 1
		If GUICtrlRead($check2) = $GUI_CHECKED Then $criptHdr = 1
		$inputPass = GUICtrlRead($input2)
	EndIf
GUIDelete()
EndFunc	;==> _Window()

PS
Всем спасибо. Проблему решил! :smile:
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
gora
Подумал что скрытая утилита автоитовская. Ну если нет, можно так:

Код:
;запуск сторонней программы
MsgBox(48, 'Message', 'начало, звук присутствует')

;отключение звука восклицания
$SoundName=RegRead("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current",'')
RegWrite("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current",'',"REG_SZ",'')
;~~~~
;выполнение программы и ожидание завершения процесса
MsgBox(48, 'Message', 'звука нет'&@CRLF&$SoundName)
;~~~~
; восстановление звука восклицания
RegWrite("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current","","REG_SZ",$SoundName)
MsgBox(48, 'Message', 'конец, звук возобновлён')


проверил, работает
делал звуковые темы и работали они без всяких обновлений, просто изменив параметр в реестре, и кстати без выключения звука.

Ну вот ещё отключение всей темы:

Код:
;запуск сторонней программы
MsgBox(0, 'Сообщение', 'начало, звук присутствует')

; создаём бэкап темы и отключаем все звуки звуковой темы
Dim $SoundName[1][2]
$i=0
While 1
	$i+=1
	ReDim $SoundName[$i+1][2]
    $SoundName[$i][0] = RegEnumKey('HKCU\AppEvents\Schemes\Apps\.Default', $i)
	If @error Then ExitLoop
	$SoundName[$i][1]=RegRead('HKCU\AppEvents\Schemes\Apps\.Default\'&$SoundName[$i][0]&'\.Current','')
	RegWrite('HKCU\AppEvents\Schemes\Apps\.Default\'&$SoundName[$i][0]&'\.Current','',"REG_SZ",'')
WEnd
ReDim $SoundName[$i-1][2]
$SoundName[0][0]=$i-2
;~~~~
;выполнение программы и ожидание завершения процесса
MsgBox(0, 'Сообщение', 'звука нет'&@CRLF&$SoundName)
;~~~~
; восстановление звуковой темы
For $i = 1 to $SoundName[0][0]
	RegWrite('HKCU\AppEvents\Schemes\Apps\.Default\'&$SoundName[$i][0]&'\.Current','','REG_SZ',$SoundName[$i][1])
Next
MsgBox(0, 'Сообщение', 'конец, звук возобновлён')
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
AZJIO
Решение интересное, но, как мне кажется, не безопасное. Если вдруг произойдет нечто непредвиденное во время выполнения
AZJIO [?]
;выполнение программы и ожидание завершения процесса
и скрипт аварийно закроется, то пользователь может остаться без звуковой темы!? :shok:
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
gora [?]
Если вдруг произойдет нечто непредвиденное во время выполнения
ИМХО, можно зарегистрировать функцию возврата значений в реестр через OnAutoItExitRegister() или, для надежности, при изменении параметров в реестре, запускать автономный скрипт в скрытом режиме (можно сразу с параметрами, которые нужно восстановить), который будет тихо дожидаться, когда закроется основной скрипт и, после этого, проверит и запишет в реестр необходимые сведения. Хотя совсем "от дурака" это не спасет. Или этот дополнительный скрипт пропишет себя, на всякий случай, в автозагрузку, а потом, после отработки удалит себя из нее.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Нет, лучше написать код без всяких непредвиденных ситуаций.

;)
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
OffTopic:
Yashied [?]
Нет, лучше написать код без всяких непредвиденных ситуаций.
А как предусмотреть, например, отключение электроэнергии (как в Московской и не только областях перед Новым годом)? :smile:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если предусматривать все "непредвиденные" ситуации, то главное вовремя остановиться, иначе получится очередной Service Pack.

А вообще, автозагрузка является хорошим решением. Можно даже обойтись без дополнительного скрипта. Добавить запись в реестр можно с помощью regedit.exe, а сам вызов добавить в RunOnce...
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
gora

Восстановление после загрузки ещё не проверял, но должно работать. Хотя и тут есть нюансы, лично я иногда стартую батник очистки папки "темп", тогда использовать @StartupDir. Но опять же бывает требуется использовать устройства доступные только для чтения (хотя бы смонтированные ISO или WIM), то тут @StartupDir не сработает, тогда двойная проверка файла эксорта потребуется.

Код:
;запуск сторонней программы
MsgBox(48, 'Сообщение', 'начало, звук присутствует')

; экспорт reg-файла и добавление в разовую автозагрузку на случай выключения питания или убития процесса скрипта для восстановления звуковой схемы.
RunWait('reg export HKCU\AppEvents\Schemes\Apps\.Default "'&@TempDir&'\SoundSchemes9572856.reg"', '', @SW_HIDE)
RegWrite('HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', @ScriptName,"REG_SZ",'reg import HKCU\AppEvents\Schemes\Apps\.Default "'&@TempDir&'\SoundSchemes9572856.reg"')
;отключение звука восклицания
$SoundName=RegRead("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current",'')
RegWrite("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current",'',"REG_SZ",'')
OnAutoItExitRegister('_AutoExit')
;~~~~
;выполнение программы и ожидание завершения процесса
MsgBox(48, 'Сообщение', 'звука нет'&@CRLF&$SoundName)
;~~~~

Func _AutoExit()
	; восстановление звука восклицания
	RegWrite("HKCU\AppEvents\Schemes\Apps\.Default\SystemExclamation\.Current","","REG_SZ",$SoundName)
	MsgBox(48, 'Сообщение', 'конец, звук возобновлён')
	RegDelete('HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', @ScriptName)
EndFunc
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
Применение Send("{VOLUME_MUTE}") казалось решит проблему, но рано я обрадовался. А если у пользователя звук изначально выключен, то эта команда его включит и получится обратный эффект.
Можно ли как-то узнать состояние звука (вкл\откл) в системе?
 
Верх