| Вы замечали как в некоторых программах при открытии какого-либо диалога начинала играть музыка из звуковой схемы Windows, а при закрытии останавливалась? В данной статье будет рассмотрено, как это можно правильно реализовать в Delphi без излишнего пожирания ресурсов компьютера и без увеличения размеров программы.
Как-то в одной из программ я обнаружил очень интересный эффект - при открытии диалогового окна "О программе…" начинала играть мелодия из звуковой схемы, которая обычно проигрывается при запуске Windows. Мне стало интересно, и я по самую голову закапался в файле справки Delphi, чтобы найти, как это можно реализовать. Единственное, что мне удалось найти, так это функцию MessageBeep. К сожалению, с ее помощью можно воспроизвести только несколько звуков из схемы.
Так как практически всё Windows хранит в реестре, я решил не останавливаться на достигнутом, а интенсивно покопаться в последнем. Через некоторое время мне все же удалось обнаружить мелодии звуковой схемы. Они скрывались в ключе:
|
HKEY_USERS\.DEFAULT\AppEvents\Schemes\Apps\.Default |

Рис.1. Ключ реестра, скрывающий звуковые схемы.
Если обратить внимание на подкаталоги данного ключа, то можно прочитать названия: Maximize, Minimize, SystemQuestion, SystemStart и другие. Как вы уже успели заметить по названиям, это и есть различные события из звуковой схемы. Каждый такой подкаталог содержит еще две папочки -.Current (текущая звуковая схема), и.Default (звуковая схема по умолчанию). Обе они в качестве параметров по умолчанию имеют путь к звуковому файлу. Это хорошо видно на рисунке 1.
Я нашел, то, что искал, но что делать дальше? Как связать реестр и воспроизведение звуков? Немного подумав, я решил сделать это следующим образом: нужно прочитать значение, то есть путь к звуковому файлу, а потом воспроизвести его. Для этого была написана вот такая процедура:
//Проигрывание стандартного звука
function PlaySystemSound(KeyName: String): BOOL;
var
Key : HKEY;
Size : DWORD;
WaveFile: String;
begin
if RegOpenKeyEx(HKEY_USERS, PChar('.DEFAULT\AppEvents\Schemes\Apps\.Default\' +
KeyName), 0, KEY_QUERY_VALUE,Key) = ERROR_SUCCESS then
begin
if RegQueryValueEx(Key, nil, nil, nil, nil, @Size) = ERROR_SUCCESS then
begin
if Size > 1 then
begin
SetLength(WaveFile, Size);
if RegQueryValueEx(Key, nil, nil, nil,
PByte(PChar(WaveFile)), @Size) = ERROR_SUCCESS then
SetLength(WaveFile, Size-1)
else WaveFile := '';
end;
end;
RegCloseKey(Key);
end;
if IsWin9x //Определяем платформу
then Result := sndPlaySound(PChar(WaveFile), SND_ASYNC)
else Result := sndPlaySound(PChar(ExpandEnvironment(WaveFile)), SND_ASYNC);
end; |
Заметьте, что я не использовал визуальный модуль для работы с реестром Registry, а создал всё с помощью API для облегчения веса программы в килобайтах. Зачем нам лишний вес, если процедура будет выполнять такую, на мой взляд, глупую операцию как воспроизведение звуков из схемы Windows? Я не считаю, что украшательства требуют жертв.
В качестве параметра KeyName процедуры могут выступать такие значения:
SystemStart\.current - Запуск Windows;
.Default\.current - Стандартный звук;
SystemExit\.current - Выход из Windows;
SystemHand\.current - Критическая ошибка;
SystemQuestion\.current - Вопрос;
SystemExclamation\.current - Восклицание;
SystemAsterisk\.current - Звездочка;
Close\.current - Закрытие программы;
Open\.current - Открытие программы;
Maximize\.current - Развертывание;
Minimize\.current - Свертывание;
RestoreDown\.current - Восстановление окна с полного экрана;
RestoreUp\.current - В окно из значка;
AppGPFault\.current - Ошибка программы;
MenuCommand\.current - Команда меню;
MenuPopup\.current - Всплывающее меню;
MailBeep\.current - Уведомление о приходе почты;
CCSelect\.current - Выделить;
ShowBand\.current - Отображение панели инструментов. |
Например, воспроизведение мелодии "Запуск Windows" будет выглядеть так:
|
PlaySystemSound('ShowBand\.current');
|
Чтобы остановить воспроизведение мелодии, достаточно запустить функцию sndPlaySound с параметром nil:
|
sndPlaySound(nil, SND_ASYNC);
|
Единственно, что вам нужно сделать для нормальной работы процедуры, так это подключить модуль MMsystem (в разделе Uses), в котором прописана функция sndPlaySound. Но можно пойти и другим путем, что я незамедлительно и сделал. Для этого я создал специальный модуль, в котором прописал функцию sndPlaySound, просто изъяв её из модуля MMsystem. Ниже приводиться полный исходник моего модуля. Заметьте, что он использует всего лишь один модуль Windows.
unit Lenin_Playsnd;
(***************************************)
(* LENIN INC *)
(* Online: http://www.lenininc.com/ *)
(* Free for non commercial use. *)
(***************************************)
interface
uses
Windows;
//Проигрывание мелодии. Пример: PlaySystemSound(pwStandart);
function PlaySystemSound(KeyName: String): BOOL;
//Остановка проигрывания мелодии
function StopSystemSound: BOOL;
{ Функции проигрывания Wave-файлов (из MMsystem) }
function sndPlaySoundA(lpszSoundName: PAnsiChar; uFlags: UINT): BOOL; stdcall;
function sndPlaySoundW(lpszSoundName: PWideChar; uFlags: UINT): BOOL; stdcall;
function sndPlaySound(lpszSoundName: PChar; uFlags: UINT): BOOL; stdcall;
const
pwStartWindows = 'SystemStart\.current'; //Запуск Windows
pwStandart = '.Default\.current'; //Стандартный звук
pwExitWindows = 'SystemExit\.current'; //Выход из Windows
pwError = 'SystemHand\.current'; //Критическа& ошибка
pwQuestion = 'SystemQuestion\.current'; //Вопрос
pwExclamation = 'SystemExclamation\.current'; //Восклицание
pwAsterisk = 'SystemAsterisk\.current'; //Звездочка
pwCloseApp = 'Close\.current'; //Закрытие программы
pwOpenApp = 'Open\.current'; //Открытие программы
pwMaximize = 'Maximize\.current'; //Развертывание
pwMinimize = 'Minimize\.current'; //Свертывание
pwRestoreDown = 'RestoreDown\.current'; //Восстановление окна с полного экрана
pwRestoreUp = 'RestoreUp\.current'; //В окно из значка
pwFaultApp = 'AppGPFault\.current'; //Ошибка программы
pwMenuCommand = 'MenuCommand\.current'; //Команда меню
pwMenuPopup = 'MenuPopup\.current'; //Всплывающее меню
pwMail = 'MailBeep\.current'; //Уведомление о приходе почты
pwSelect = 'CCSelect\.current'; //Выделить
pwToolBar = 'ShowBand\.current'; //Отображение панели инструментов
const
SND_ASYNC = $0001; { play asynchronously }
implementation
const
mmsyst = 'winmm.dll';
function sndPlaySoundA; external mmsyst name 'sndPlaySoundA';
function sndPlaySoundW; external mmsyst name 'sndPlaySoundW';
function sndPlaySound; external mmsyst name 'sndPlaySoundA';
//Определяем платформу
function IsWin9x: Bool; {True = Win9x} { False = NT}
asm
xor eax, eax
mov ecx, cs
xor cl, cl
jecxz @@quit
inc eax
@@quit:
end;
//Пример: ExpandEnvironment('%SystemRoot%');
function ExpandEnvironment(const sDir: String): String;
var
buf: array [0..1023] of Char;
begin
ExpandEnvironmentStrings(PChar(sDir), buf, SizeOf(buf));
Result := buf;
// if (Result<>'') and (Result[Length(Result)]<>'\') then Result:=Result+'\';
end;
//Проигрывание стандартного звука
function PlaySystemSound(KeyName: String): BOOL;
var
Key : HKEY;
Size : DWORD;
WaveFile: String;
begin
if RegOpenKeyEx(HKEY_USERS, PChar('.DEFAULT\AppEvents\Schemes\Apps\.Default\' +
KeyName), 0, KEY_QUERY_VALUE,Key) = ERROR_SUCCESS then
begin
if RegQueryValueEx(Key, nil, nil, nil, nil, @Size) = ERROR_SUCCESS then
begin
if Size > 1 then
begin
SetLength(WaveFile, Size);
if RegQueryValueEx(Key, nil, nil, nil,
PByte(PChar(WaveFile)), @Size) = ERROR_SUCCESS then
SetLength(WaveFile, Size-1)
else WaveFile := '';
end;
end;
RegCloseKey(Key);
end;
if IsWin9x //Определяем платформу
then Result := sndPlaySound(PChar(WaveFile), SND_ASYNC)
else Result := sndPlaySound(PChar(ExpandEnvironment(WaveFile)), SND_ASYNC);
end;
//Остановка проигрывания звука
function StopSystemSound: BOOL;
begin
Result := sndPlaySound(nil, SND_ASYNC);
end;
end. |
Данный модуль не занимает много места в программе, а функции и процедуры нормально работаю во всех операционных средах Windows.
Теперь вы можете озвучить в своем приложении появление диалогового окна "О программе…". При этом если у пользователя не установлена звуковая схема, он не увидит никаких ошибок по этому поводу и даже не будет знать, что при открытии какого-то диалога воспроизводиться звук. Зачем пугать и путать пользователя лишними сообщениями об ошибках? Кстати, в Windows XP даже при выключенной звуковой схеме мелодия будет проигрыватся.
Полностью уже написанный модуль, а также и массу других не менее интересных модулей вы можете найти на моем сайте в разделе WIN32API. Все они распространяются совершенно бесплатно и предназначены для написания программ на чистом WIN32API, то есть шустрых, маленьких размером приложений без использования визуальных компонентов. |