//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "AudioSwitcher.h"
#include <Windows.h>
#include "AudioMain.h"
#include "HandleFinder.h"
#include "UserDefines.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TAudioSwitch *AudioSwitch;
//---------------------------------------------------------------------------
__fastcall TAudioSwitch::TAudioSwitch(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void TAudioSwitch::errorBox(char *errMsg)
{
MessageBox(NULL,errMsg, "Fatal Error", MB_OK);
}
//---------------------------------------------------------------------------
char *TAudioSwitch::GetPropName(int PropIndex)
{
return((Audio->AudioEndPoint+(PropIndex*MAXCHAR)));
}
//---------------------------------------------------------------------------
bool TAudioSwitch::SetDefaultEndpoint(HWND defaultButton,bool Action)
{
// Get 'Set Default' button window style
long lResult=GetWindowLong(defaultButton,GWL_STYLE);
//Check if 'Set Default' button is enabled
if (Action)
{
if (!(lResult & WS_DISABLED))
{// If so, set audio endpoint as default
SendMessage(defaultButton, BM_CLICK, NULL, NULL);
return true;
}
}
else
{
if (lResult & WS_DISABLED)
return true;
else
return false;
}
return false;
}
//-----------------------------------------------------------------------------------
bool TAudioSwitch::ChangeAudioDevice(int cmdSwitch,int Index)
{
HWND okButton,defaultButton;
HWND listView;
// HWND appletWindow;
LVITEM lvi, *_lvi;
TOKEN_PRIVILEGES tokenPriv;
LUID tokenLuid;
HANDLE tokenHandle;
HANDLE lView;
DWORD procID=0;
AnsiString itemText;
int lvsize=sizeof(LVITEM);
char item[MAXCHAR];
char *_item;
bool breakFlag=false;
ZeroMemory(&tokenPriv,sizeof(TOKEN_PRIVILEGES));
ZeroMemory(&tokenLuid,sizeof(LUID));
ZeroMemory(&item,MAXCHAR);
// if it's already running
if (appletWindow == NULL)
appletWindow = FindWindow(NULL,AppletName);
// if not, run it
if (appletWindow == NULL)
appletWindow = findHandle->launchApplet(APPLET,AppletName);
if (appletWindow != NULL)
{
// hide the applet from view
// user interaction with the soundapplet will mess up the pointers
//find the Buttons
okButton = findHandle->findChildWindow(appletWindow,BUTTON,OkButton);
defaultButton = findHandle->findChildWindow(appletWindow,BUTTON,DefButton);
if (okButton && defaultButton) //found buttons so must be the correct Page
// TODO add code to manipulate applet pages
{
//find the listview
listView = findHandle->findChildWindow(appletWindow,LIST_VIEW,NULL);
//get the listview thread
GetWindowThreadProcessId(listView,&procID);
//open the listview process
lView=OpenProcess(PROCESS_ALL_ACCESS,false,procID);
if (lView)
{
// Ensure you have sufficient privileges to the applet
if ( !LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tokenLuid ) )
{
errorBox("Insufficient Privileges");
return true;
}
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = tokenLuid;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tokenHandle=NULL;
if (!OpenProcessToken(lView,TOKEN_ADJUST_PRIVILEGES,&tokenHandle))
{
errorBox("Unable to get privlege level");
return true;
}
// Set access token
if ( !AdjustTokenPrivileges(tokenHandle,FALSE,&tokenPriv,sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
{
errorBox("Unable to set privlege level");
return true;
}
// Allocate virtual memory for ListView
LVITEM *_lvi=(LVITEM*)VirtualAllocEx(lView, NULL, lvsize,MEM_COMMIT, PAGE_READWRITE);
// Allocate virtual memory for ListView Item String
char *_item=(char*)VirtualAllocEx(lView, NULL, MAXCHAR, MEM_COMMIT, PAGE_READWRITE);
if (!_item)
{
errorBox("Unable to allocate process memory");
return true;
}
int itemCount=SendMessage(listView,LVM_GETITEMCOUNT, NULL, NULL);
if (!itemCount)
{
errorBox("Empty List");
return true;
}
ShowWindow( appletWindow, SW_HIDE );
for (int i=0;i<itemCount;i++)
{
ZeroMemory(&lvi,lvsize);
if (!i)
{
// set the first item in the listview as focused
lvi.mask=LVIF_STATE;
lvi.state=LVIS_FOCUSED | LVIS_SELECTED;
lvi.stateMask=LVIS_FOCUSED | LVIS_SELECTED;
WriteProcessMemory(lView, _lvi, &lvi, lvsize,NULL);
SendMessage(listView, LVM_SETITEMSTATE, (WPARAM)lvi.iItem, (LPARAM)_lvi);
// mess with the keys about to activate the Set Default state
// no idea why, but it works
SendMessage(listView, WM_KEYDOWN, VK_DOWN, NULL);
SendMessage(listView, WM_KEYUP, VK_UP, NULL);
SendMessage(listView, WM_KEYDOWN, VK_DOWN, NULL);
SendMessage(listView, WM_KEYUP, VK_UP, NULL);
// reset the first item in the listview as focused
lvi.mask=LVIF_STATE;
lvi.state=LVIS_FOCUSED | LVIS_SELECTED;
lvi.stateMask=LVIS_FOCUSED | LVIS_SELECTED;
WriteProcessMemory(lView, _lvi, &lvi, lvsize,NULL);
SendMessage(listView, LVM_SETITEMSTATE, (WPARAM)lvi.iItem, (LPARAM)_lvi);
}
else
{
// descend the list one by one
SendMessage(listView, WM_KEYDOWN, VK_DOWN, NULL);
SendMessage(listView, WM_KEYUP, VK_DOWN, NULL);
}
// Commandline switches given?
// Get ItemText
ZeroMemory(&lvi,lvsize);
lvi.iItem=i;
lvi.cchTextMax=MAXCHAR;
lvi.pszText=_item;
WriteProcessMemory(lView, _lvi, &lvi,lvsize, NULL);
SendMessage(listView,LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi);
ReadProcessMemory(lView, _item, item, MAXCHAR, NULL);
itemText=item;
TListItem *EndItem;
switch (cmdSwitch)
{
case SELECT_LIST:
// Set Selected endpoint as default
if (i==Index)
{
breakFlag=true;
SendMessage(defaultButton, BM_CLICK, NULL, NULL);
}
break;
case DEFAULT:
// Add ItemText to ListView
EndItem=Audio->lvEndpoint->Items->Add();
EndItem->Caption=itemText;
if (SetDefaultEndpoint(defaultButton,false))
EndItem->SubItems->Add("Active");
else
EndItem->SubItems->Add("Not Active");
break;
case SELECT_CMD:
if (itemText.Pos(Selected)>0)
breakFlag=SetDefaultEndpoint(defaultButton,true);
break;
}
// Check if the loop continues
if (breakFlag) break;
}
}
// Close applet on cmdline conditions
if (cmdSwitch==SELECT_CMD)
{
ShowWindow( appletWindow, SW_RESTORE );
SendMessage(okButton, BM_CLICK, NULL, NULL);
appletWindow=NULL;
}
// Cleanup
VirtualFreeEx(lView, _lvi, 0, MEM_RELEASE);
VirtualFreeEx(lView, _item, 0, MEM_RELEASE);
CloseHandle(tokenHandle);
CloseHandle(lView);
}
else
{ //didn't find buttons
errorBox("Unable to find buttons");
return true;
}
}
else
{ //didn't find applet window
errorBox("Failed to find applet window");
return true;
}
return false;
}