diff --git a/reactos/base/applications/sndvol32/dialog.c b/reactos/base/applications/sndvol32/dialog.c new file mode 100644 index 00000000000..3cddcd043e2 --- /dev/null +++ b/reactos/base/applications/sndvol32/dialog.c @@ -0,0 +1,384 @@ +/* $Id: misc.c 43790 2009-10-27 10:34:16Z dgorbachev $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Sound Volume Control + * FILE: subsys/system/sndvol32/dialog.c + * PROGRAMMERS: Johannes Anderwald + */ +#include "sndvol32.h" + + +#define XLEFT (30) +#define XTOP (20) +#define DIALOG_VOLUME_SIZE (150) + +LPVOID +LoadDialogResource( + IN HMODULE hModule, + IN LPCWSTR ResourceName, + OUT LPDWORD ResourceLength) +{ + HRSRC hSrc; + HGLOBAL hRes; + PVOID Result; + + /* find resource */ + hSrc = FindResourceW(hModule, ResourceName, (LPCWSTR)RT_DIALOG); + + if (!hSrc) + { + /* failed to find resource */ + return NULL; + } + + /* now load the resource */ + hRes = LoadResource(hAppInstance, hSrc); + if (!hRes) + { + /* failed to load resource */ + return NULL; + } + + /* now lock the resource */ + Result = LockResource(hRes); + + if (!Result) + { + /* failed to lock resource */ + return NULL; + } + + if (ResourceLength) + { + /* store output length */ + *ResourceLength = SizeofResource(hAppInstance, hSrc); + } + + /* done */ + return Result; +} + +LPWORD +AddDialogControl( + IN HWND hwndDialog, + IN HWND * OutWnd, + IN LPRECT DialogOffset, + IN PDLGITEMTEMPLATE DialogItem, + IN DWORD DialogIdMultiplier, + IN HFONT hFont) +{ + RECT rect; + LPWORD Offset; + LPWSTR ClassName, WindowName = NULL; + HWND hwnd; + DWORD wID; + + /* initialize client rectangle */ + rect.left = DialogItem->x + DialogOffset->left; + rect.top = DialogItem->y + DialogOffset->top; + rect.right = DialogItem->cx; + rect.bottom = DialogItem->cy; + + //MapDialogRect(hwndDialog, &rect); + + /* move offset after dialog item */ + Offset = (LPWORD)(DialogItem + 1); + + if (*Offset == 0xFFFF) + { + /* class is encoded as type */ + Offset++; + + /* get control type */ + switch(*Offset) + { + case 0x80: + ClassName = L"button"; + WindowName = (LPWSTR)(Offset + 1); + break ; + case 0x82: + ClassName = L"static"; + WindowName = (LPWSTR)(Offset + 1); + break; + default: + /* FIXME */ + assert(0); + ClassName = 0; + } + } + else + { + /* class name is encoded as string */ + ClassName = (LPWSTR)Offset; + + /* adjust offset */ + Offset += wcslen(ClassName) + 1; + + /* get offset */ + WindowName = (LPWSTR)(Offset + 1); + } + + if (DialogItem->id == MAXWORD) + { + /* id is not important */ + wID = DialogItem->id; + } + else + { + /* calculate id */ + wID = DialogItem->id * (DialogIdMultiplier + 1); + + } + /* now create the window */ + hwnd = CreateWindowExW(DialogItem->dwExtendedStyle, + ClassName, + WindowName, + DialogItem->style, + rect.left, + rect.top, + rect.right, + rect.bottom, + hwndDialog, + (HMENU)(wID), + hAppInstance, + NULL); + + /* sanity check */ + assert(hwnd); + + /* store window */ + *OutWnd = hwnd; + + /* check if this the track bar */ + if (!wcsicmp(ClassName, L"msctls_trackbar32")) + { + /* set up range */ + SendMessage(hwnd, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG(0, 5)); + + /* set up page size */ + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM) 1); + + /* set available range */ + SendMessage(hwnd, TBM_SETSEL, (WPARAM) FALSE, (LPARAM) MAKELONG(0, 5)); + } + else if (!wcsicmp(ClassName, L"static") || !wcsicmp(ClassName, L"button")) + { + /* set font */ + SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE); + } + + //ShowWindow(hwnd, SW_SHOWNORMAL); + + if (WindowName != NULL) + { + /* position offset to start of name */ + Offset++; + + /* move offset past name */ + Offset += wcslen((LPWSTR)Offset) + 1; + } + else + { + /* no name so just adjust offset */ + Offset++; + } + + /* check if there is additional data */ + if (*Offset == 0) + { + /* no additional data */ + Offset++; + } + else + { + /* add data offset */ + Offset += *Offset; + } + + /* make sure next template is word-aligned */ + Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3); + + /* done */ + return Offset; +} + +VOID +LoadDialogControls( + IN PMIXER_WINDOW MixerWindow, + LPRECT DialogOffset, + LPVOID DlgResource, + DWORD DialogIdMultiplier) +{ + LPDLGTEMPLATE DialogHeader; + PDLGITEMTEMPLATE DialogItem; + LPWORD Offset; + WORD FontSize; + WCHAR FontName[100]; + WORD Length, Index; + HFONT Font; + + /* get dialog header */ + DialogHeader = (LPDLGTEMPLATE)DlgResource; + + /* sanity check */ + assert(DialogHeader->cdit); + + if (MixerWindow->Window) + MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + DialogHeader->cdit) * sizeof(HWND)); + else + MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DialogHeader->cdit * sizeof(HWND)); + if (!MixerWindow->Window) + { + /* no memory */ + return; + } + + /* now walk past the dialog header */ + Offset = (LPWORD)(DialogHeader + 1); + + /* FIXME: support menu */ + assert(*Offset == 0); + Offset++; + + /* FIXME: support classes */ + assert(*Offset == 0); + Offset++; + + /* FIXME: support titles */ + assert(*Offset == 0); + Offset++; + + /* get font size */ + FontSize = *Offset; + Offset++; + + /* calculate font length */ + Length = wcslen((LPWSTR)Offset) + 1; + assert(Length < (sizeof(FontName) / sizeof(WCHAR))); + + /* copy font */ + wcscpy(FontName, (LPWSTR)Offset); + + Font = CreateFontW(FontSize+8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, FontName); + assert(Font); + + /* move offset after font name */ + Offset += Length; + + /* offset is now at first dialog item control */ + DialogItem = (PDLGITEMTEMPLATE)Offset; + + /* enumerate now all controls */ + for(Index = 0; Index < DialogHeader->cdit; Index++) + { + /* add controls */ + Offset = AddDialogControl(MixerWindow->hWnd, &MixerWindow->Window[MixerWindow->WindowCount], DialogOffset, DialogItem, DialogIdMultiplier, Font); + + /* sanity check */ + assert(Offset); + + /* move dialog item to new offset */ + DialogItem =(PDLGITEMTEMPLATE)Offset; + + /* increment window count */ + MixerWindow->WindowCount++; + } +} + +VOID +LoadDialog( + IN HMODULE hModule, + IN PMIXER_WINDOW MixerWindow, + IN LPCWSTR DialogResId, + IN DWORD Index) +{ + LPVOID DlgResource; + RECT rect; + + /* first load the dialog resource */ + DlgResource = LoadDialogResource(hModule, DialogResId, NULL); + + if (!DlgResource) + { + /* failed to load resource */ + return; + } + + /* get window size */ + GetClientRect(MixerWindow->hWnd, &rect); + + /* adjust client position */ + rect.left += (Index * DIALOG_VOLUME_SIZE); + + + /* now add the controls */ + LoadDialogControls(MixerWindow, &rect, DlgResource, Index); + +} + +BOOL +CALLBACK +EnumConnectionsCallback( + PSND_MIXER Mixer, + DWORD LineID, + LPMIXERLINE Line, + PVOID Context) +{ + WCHAR LineName[MIXER_LONG_NAME_CHARS]; + DWORD Flags; + DWORD wID; + RECT rect; + PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context; + + if (Line->cControls != 0) + { + /* get line name */ + if (SndMixerGetLineName(PrefContext->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, FALSE) == -1) + { + /* failed to get line name */ + LineName[0] = L'\0'; + } + + /* check if line is found in registry settings */ + if (ReadLineConfig(PrefContext->DeviceName, + LineName, + Line->szName, + &Flags)) + { + /* is it selected */ + if (Flags != 0x4) + { + /* load dialog resource */ + LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(IDD_VOLUME_CTRL), PrefContext->Count); + + /* get id */ + wID = (PrefContext->Count + 1) * IDC_LINE_NAME; + + /* set line name */ + SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName); + + /* increment dialog count */ + PrefContext->Count++; + + /* get application rectangle */ + GetWindowRect(PrefContext->MixerWindow->hWnd, &rect); + + /* now move the window */ + MoveWindow(PrefContext->MixerWindow->hWnd, rect.left, rect.top, (PrefContext->Count * DIALOG_VOLUME_SIZE), rect.bottom, TRUE); + + } + } + } + return TRUE; +} + +VOID +LoadDialogCtrls( + PPREFERENCES_CONTEXT PrefContext) +{ + /* set dialog count to one */ + PrefContext->Count = 0; + + /* enumerate controls */ + SndMixerEnumConnections(PrefContext->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext); +} diff --git a/reactos/base/applications/sndvol32/misc.c b/reactos/base/applications/sndvol32/misc.c index 2935a85e193..169e6114339 100644 --- a/reactos/base/applications/sndvol32/misc.c +++ b/reactos/base/applications/sndvol32/misc.c @@ -23,7 +23,8 @@ * FILE: subsys/system/sndvol32/misc.c * PROGRAMMERS: Thomas Weidenmueller */ -#include +#include "sndvol32.h" + static INT LengthOfStrResource(IN HINSTANCE hInst, diff --git a/reactos/base/applications/sndvol32/mixer.c b/reactos/base/applications/sndvol32/mixer.c index f01496c7ed3..d4e883ba2a9 100644 --- a/reactos/base/applications/sndvol32/mixer.c +++ b/reactos/base/applications/sndvol32/mixer.c @@ -23,7 +23,7 @@ * FILE: subsys/system/sndvol32/mixer.c * PROGRAMMERS: Thomas Weidenmueller */ -#include +#include "sndvol32.h" #define NO_MIXER_SELECTED ((UINT)(~0)) diff --git a/reactos/base/applications/sndvol32/resources.h b/reactos/base/applications/sndvol32/resources.h index 0272ffecd1c..2fa18a50a66 100644 --- a/reactos/base/applications/sndvol32/resources.h +++ b/reactos/base/applications/sndvol32/resources.h @@ -10,7 +10,7 @@ #define IDC_HELP_TOPICS 1101 #define IDC_ABOUT 1102 -#define IDD_PREFERENCES 101 + #define IDC_MIXERDEVICE 1001 #define IDC_PLAYBACK 1002 #define IDC_RECORDING 1003 @@ -18,6 +18,11 @@ #define IDC_LINE 1005 #define IDC_LABELCONTROLS 1006 #define IDC_CONTROLS 1007 +#define IDC_LINE_NAME 1008 #define IDS_SNDVOL32 100 #define IDS_NOMIXERDEVICES 101 + + +#define IDD_VOLUME_CTRL 200 +#define IDD_PREFERENCES 201 diff --git a/reactos/base/applications/sndvol32/sndvol32.c b/reactos/base/applications/sndvol32/sndvol32.c index 3816d353a63..6c8ad7c55c1 100644 --- a/reactos/base/applications/sndvol32/sndvol32.c +++ b/reactos/base/applications/sndvol32/sndvol32.c @@ -23,13 +23,14 @@ * FILE: subsys/system/sndvol32/sndvol32.c * PROGRAMMERS: Thomas Weidenmueller */ -#include +#include "sndvol32.h" HINSTANCE hAppInstance; ATOM MainWindowClass; HWND hMainWnd; HANDLE hAppHeap; LPTSTR lpAppTitle; +PREFERENCES_CONTEXT Preferences; #define GetDialogData(hwndDlg, type) \ ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER) @@ -38,21 +39,7 @@ LPTSTR lpAppTitle; /******************************************************************************/ -typedef struct _PREFERENCES_CONTEXT -{ - PMIXER_WINDOW MixerWindow; - PSND_MIXER Mixer; - HWND hwndDlg; - UINT Selected; - DWORD SelectedLine; - DWORD PlaybackID; - DWORD RecordingID; - UINT OtherLines; - TCHAR DeviceName[128]; - - DWORD tmp; -} PREFERENCES_CONTEXT, *PPREFERENCES_CONTEXT; typedef struct _PREFERENCES_FILL_DEVICES { @@ -546,18 +533,36 @@ DlgPreferencesProc(HWND hwndDlg, return 0; } + /******************************************************************************/ static VOID DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow) { - UNREFERENCED_PARAMETER(MixerWindow); + DWORD Index; + + for(Index = 0; Index < MixerWindow->WindowCount; Index++) + { + /* destroys the window */ + DestroyWindow(MixerWindow->Window[Index]); + } + + /* free memory */ + HeapFree(GetProcessHeap(), 0, MixerWindow->Window); + + /* set to null */ + MixerWindow->Window = NULL; + MixerWindow->WindowCount = 0; } static BOOL -RebuildMixerWindowControls(PMIXER_WINDOW MixerWindow) +RebuildMixerWindowControls(PPREFERENCES_CONTEXT PrefContext) { - DeleteMixerWindowControls(MixerWindow); + /* delete existing mixer controls */ + DeleteMixerWindowControls(PrefContext->MixerWindow); + + /* load new mixer controls */ + LoadDialogCtrls(PrefContext); return TRUE; } @@ -637,44 +642,56 @@ MainWindowProc(HWND hwnd, GWL_USERDATA, (LONG_PTR)MixerWindow); MixerWindow->hWnd = hwnd; - MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, - NULL, - hwnd, - 0); - if (MixerWindow->hStatusBar != NULL) + MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd); + if (MixerWindow->Mixer != NULL) { - MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd); - if (MixerWindow->Mixer != NULL) + TCHAR szProduct[MAXPNAMELEN]; + + /* get mixer product name */ + if (SndMixerGetProductName(MixerWindow->Mixer, + szProduct, + sizeof(szProduct) / sizeof(szProduct[0])) == -1) { - TCHAR szProduct[MAXPNAMELEN]; - - if (SndMixerGetProductName(MixerWindow->Mixer, - szProduct, - sizeof(szProduct) / sizeof(szProduct[0])) > 0) - { - SendMessage(MixerWindow->hStatusBar, - WM_SETTEXT, - 0, - (LPARAM)szProduct); - } - - if (!RebuildMixerWindowControls(MixerWindow)) - { - DPRINT("Rebuilding mixer window controls failed!\n"); - SndMixerDestroy(MixerWindow->Mixer); - MixerWindow->Mixer = NULL; - Result = -1; - } + /* failed to get name */ + szProduct[0] = L'\0'; } - else + + + /* initialize perferences */ + ZeroMemory(&Preferences, sizeof(Preferences)); + + /* store mixer */ + Preferences.Mixer = MixerWindow->Mixer; + + /* store mixer window */ + Preferences.MixerWindow = MixerWindow; + + /* first destination line id */ + Preferences.SelectedLine = 0xFFFF0000; + + /* copy product */ + wcscpy(Preferences.DeviceName, szProduct); + + if (!RebuildMixerWindowControls(&Preferences)) { + DPRINT("Rebuilding mixer window controls failed!\n"); + SndMixerDestroy(MixerWindow->Mixer); + MixerWindow->Mixer = NULL; Result = -1; } - } - else - { - DPRINT("Failed to create status window!\n"); - Result = -1; + + /* create status window */ + MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS, + NULL, + hwnd, + 0); + if (MixerWindow->hStatusBar) + { + SendMessage(MixerWindow->hStatusBar, + WM_SETTEXT, + 0, + (LPARAM)szProduct); + } } break; } @@ -746,7 +763,7 @@ CreateApplicationWindow(VOID) HWND hWnd; PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap, - 0, + HEAP_ZERO_MEMORY, sizeof(MIXER_WINDOW)); if (MixerWindow == NULL) { @@ -758,8 +775,8 @@ CreateApplicationWindow(VOID) hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT, SZ_APP_CLASS, lpAppTitle, - WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, //WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, 0, 300, 315, NULL, LoadMenu(hAppInstance, MAKEINTRESOURCE(IDM_MAINMENU)), @@ -805,6 +822,7 @@ _tWinMain(HINSTANCE hInstance, { MSG Msg; int Ret = 1; + INITCOMMONCONTROLSEX Controls; UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpszCmdLine); @@ -823,7 +841,10 @@ _tWinMain(HINSTANCE hInstance, lpAppTitle = NULL; } - InitCommonControls(); + Controls.dwSize = sizeof(INITCOMMONCONTROLSEX); + Controls.dwICC = ICC_BAR_CLASSES | ICC_STANDARD_CLASSES; + + InitCommonControlsEx(&Controls); if (RegisterApplicationClasses()) { diff --git a/reactos/base/applications/sndvol32/sndvol32.h b/reactos/base/applications/sndvol32/sndvol32.h index 8ca5669bb4f..9cbae1ccbf8 100644 --- a/reactos/base/applications/sndvol32/sndvol32.h +++ b/reactos/base/applications/sndvol32/sndvol32.h @@ -9,6 +9,7 @@ #include #include #include "resources.h" +#include typedef struct _MIXER_WINDOW { @@ -16,6 +17,10 @@ typedef struct _MIXER_WINDOW HWND hStatusBar; struct _SND_MIXER *Mixer; UINT SelectedLine; + UINT WindowCount; + HWND * Window; + + } MIXER_WINDOW, *PMIXER_WINDOW; extern HINSTANCE hAppInstance; @@ -26,7 +31,8 @@ extern HANDLE hAppHeap; #define SZ_APP_CLASS TEXT("Volume Control") ULONG DbgPrint(PCH , ...); -#define DPRINT DbgPrint("SNDVOL32: %s:%i: ", __FILE__, __LINE__); DbgPrint +#define DPRINT +//DbgPrint("SNDVOL32: %s:%i: ", __FILE__, __LINE__); DbgPrint /* @@ -61,6 +67,24 @@ typedef struct _SND_MIXER PSND_MIXER_DESTINATION Lines; } SND_MIXER, *PSND_MIXER; +typedef struct _PREFERENCES_CONTEXT +{ + PMIXER_WINDOW MixerWindow; + PSND_MIXER Mixer; + HWND hwndDlg; + + UINT Selected; + DWORD SelectedLine; + DWORD PlaybackID; + DWORD RecordingID; + UINT OtherLines; + TCHAR DeviceName[128]; + + DWORD Count; + DWORD tmp; +} PREFERENCES_CONTEXT, *PPREFERENCES_CONTEXT; + + typedef BOOL (CALLBACK *PFNSNDMIXENUMLINES)(PSND_MIXER Mixer, LPMIXERLINE Line, UINT DisplayControls, PVOID Context); typedef BOOL (CALLBACK *PFNSNDMIXENUMCONNECTIONS)(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Context); typedef BOOL (CALLBACK *PFNSNDMIXENUMPRODUCTS)(PSND_MIXER Mixer, UINT Id, LPCTSTR ProductName, PVOID Context); @@ -78,6 +102,12 @@ BOOL SndMixerEnumLines(PSND_MIXER Mixer, PFNSNDMIXENUMLINES EnumProc, PVOID Cont BOOL SndMixerEnumConnections(PSND_MIXER Mixer, DWORD LineID, PFNSNDMIXENUMCONNECTIONS EnumProc, PVOID Context); BOOL SndMixerIsDisplayControl(PSND_MIXER Mixer, LPMIXERCONTROL Control); +/* + * dialog.c + */ +VOID +LoadDialogCtrls(PPREFERENCES_CONTEXT PrefContext); + /* * MISC */ diff --git a/reactos/base/applications/sndvol32/sndvol32.rbuild b/reactos/base/applications/sndvol32/sndvol32.rbuild index 97d5a60cc95..38d5d9e0f5a 100644 --- a/reactos/base/applications/sndvol32/sndvol32.rbuild +++ b/reactos/base/applications/sndvol32/sndvol32.rbuild @@ -11,6 +11,7 @@ shell32 winmm sndvol32.h + dialog.c misc.c mixer.c sndvol32.c