Byłem przekonany, że mając ten kod z pobieraniem wartości dźwięku już sobie poradzisz, gdyż w zasadzie wystarczy zastąpić funkcję
mixerSetControlDetails funkcją
mixerGetControlDetails, cała reszta pozostaje prawie bez zmian:
#include <mmsystem.h>
//---------------------------------------------------------------------------
DWORD GetVolume(DWORD cType)
{
MMRESULT result;
HMIXER hMixer;
result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0);
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = cType; // typ sterownika, któremu regulujemy dźwięk
result = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
return mcdu.dwValue;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int Volume = GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
Label1->Caption = "Siła dźwięku: " + (String)Volume;
}
//---------------------------------------------------------------------------
Jeżeli chodzi o sprawdzanie siły dźwięku na bieżąco, to można posłużyć się oczywiście Timer'em, ale ja sugeruję raczej zamontować hak systemowy, gdyż to nie obciąża procesora, wiadomo zegar sobie tyka z określoną częstotliwością, a hak systemowy tylko nasłuchuje komunikatów:
Przykład sprawdzanie siły główne głośności z wykorzystaniem haka systemowego:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "mmsystem.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HHOOK g_hLogHook = NULL;
HWND g_hLastFocus = NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
DWORD GetVolume(DWORD cType) // Funkcja sprawdzająca siłę dźwięku
{
MMRESULT result;
HMIXER hMixer;
result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0);
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = cType; // typ sterownika, któremu regulujemy dźwięk
result = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
return mcdu.dwValue;
}
//---------------------------------------------------------------------------
HOOKPROC ConnectHook(int iCode, WPARAM wParam, LPARAM lParam) // hak systemowy przechwytujący komunikaty
{
if(iCode < 0) return (HOOKPROC)CallNextHookEx(g_hLogHook, iCode, wParam, lParam);
int Volume = GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS); // pobranie siły dźwięku
Form1->Label1->Caption = "Siła dźwięku: " + (String)Volume; // wyświetlenie siły dźwięku - zwracam uwagę na adresowanie Form1->...
return (HOOKPROC)CallNextHookEx (g_hLogHook, iCode, wParam, lParam);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) // Zamontowanie haka systemowego
{
if(g_hLogHook == NULL)
g_hLogHook = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)ConnectHook, HInstance,0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) // od montowanie haka systemowego
{
if(g_hLogHook != NULL)
{
UnhookWindowsHookEx(g_hLogHook);
g_hLogHook = NULL;
}
}
//---------------------------------------------------------------------------
W powyższym przykładzie przechwytywanie komunikatów nie następuje od razu po uruchomieniu programu, gdyż hak nie jest jeszcze zamontowany. Montowanie haka odbywa się w zdarzeniu OnClick przycisku Button1, nie należy jednak w żadnym razie montować haka w zdarzeniu OnShow czy też OnCreate formularza, jeżeli chcemy zamontować hak razem z uruchomieniem programu to należy skorzystać z Timer'a w celu opóźnienia montowania haka, czyli umieszczamy Timer na formularzu, ustawiamy jego właściwość Enabled na false, a Interval na 1000 i w zdarzeniu OnTimer umieszczamy taki kod:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
static int x = 0;
x++;
if(x >= 2)
{
if(g_hLogHook == NULL)
g_hLogHook = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)ConnectHook, HInstance,0);
Timer1->Enabled = false;
}
}
a w zdarzeniu OnShow formularza umieszczamy taki kod:
void __fastcall TForm1::FormShow(TObject *Sender)
{
Timer1->Enabled = true;
Volume = GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
Label1->Caption = "Siła dźwięku: " + (String)Volume;
}
Testowanie tak montowanego haka powinno odbywać się poza IDE środowiska BCB, gdyż program uruchomiony z poziomu BCB może spowodować zawieszenie systemu.
Trzeba też pamiętać o od montowaniu haka przy zamknięciu programu, można to zrobić w zdarzeniu OnClose dla formularza:
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if(g_hLogHook != NULL)
{
UnhookWindowsHookEx(g_hLogHook);
g_hLogHook = NULL;
}
}
Sprawdzanie siły głosu odbywa się wewnątrz funkcji haka, dlatego każde odwołanie do elementu formularza musi odbywać się poprzez adresowanie na formularz, czyli odwołanie do obiektu lub zmiennej powinno zawsze byc poprzedzone nazwą formularza, np. Form1->Label1->Caption = ...
Zmienne, które chcemy wykorzystać wewnątrz haka i jednocześnie programu powinny być deklarowane w pliku nagłówkowym w sekcji
public jako zmienne globalne tak by funkcja haka miała do nich dostęp:
Plik nagłówkowy (np. Unit1.h)
public: // User declarations
int Volume;
__fastcall TForm1(TComponent* Owner);
Plik źródłowy (np. Unit1.cpp)
HOOKPROC ConnectHook(int iCode, WPARAM wParam, LPARAM lParam)
{
if(iCode < 0) return (HOOKPROC)CallNextHookEx(g_hLogHook, iCode, wParam, lParam);
Form1->Volume = GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
Form1->Label1->Caption = "Siła dźwięku: " + (String)Form1->Volume;
return (HOOKPROC)CallNextHookEx (g_hLogHook, iCode, wParam, lParam);
}
W załączniku znajdziesz przykładowy program testowy i pliki Unit1.cpp i Unit1.h. Nie zamieszczam całego projektu, gdyż tworzę w BDS 2006, więc pewnie i tak byś go nie uruchomił.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.