Windows XP: volume control edit
2018-5-18 : Now available on SourceForge:
https://sourceforge.net/projects/volume-controls-cmdline/files/bll 2016-12-19 Finding the code to handle Windows XP volume was a bit difficult. Builds a stand-alone executable or loadable Tcl stub.
load [file join [pwd] winxpvolume[info sharedlibextension]]
set vol [winxpvolume] ; # get the volume
incr vol -10
set newvol [winxpvolume $vol] ; # set the volume, always returns the current volume.
winxpmkvol.sh#!/bin/bash
gcc -m32 -static-libgcc -UWINXP_TCL_INTERFACE -o winxpvolume.exe \
-I$HOME/local-32/include -DUSE_TCL_STUBS winxpvolume.c \
-L$HOME/local-32/lib -lwinmm
gcc -m32 -shared -static-libgcc -DWINXP_TCL_INTERFACE -o winxpvolume.dll \
-I$HOME/local-32/include -DUSE_TCL_STUBS winxpvolume.c \
-L$HOME/local-32/lib -ltclstub86 -lwinmm
winxpvolume.c/*
* Copyright 2016 Brad Lanam Walnut Creek CA US
* MIT License
*
* Reference:
* https://www.codeproject.com/kb/audio-video/mixersetcontroldetails.aspx?display=printall&fid=16481&df=90&mpp=25&noise=3&sort=position&view=quick&select=2765918
*/
#ifdef WINXP_TCL_INTERFACE
# include <tcl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
int
process (int set, int vol)
{
MMRESULT result;
HMIXER hMixer;
result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0);
MIXERLINE ml = {0};
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
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);
if (set) {
vol = round ((double) vol / 100.0 * 65535.0);
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
mcdu.dwValue = vol;
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
result = mixerSetControlDetails((HMIXEROBJ) hMixer,
&mcd, MIXER_SETCONTROLDETAILSF_VALUE);
}
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;
result = mixerGetControlDetails((HMIXEROBJ) hMixer,
&mcd, MIXER_SETCONTROLDETAILSF_VALUE);
vol = (int) round ((double) mcdu.dwValue / 65535.0 * 100.0);
return vol;
}
#ifndef WINXP_TCL_INTERFACE
int
main (int argc, char *argv[])
{
int set;
int vol;
set = 0;
if (argc > 1) {
set = 1;
vol = atoi(argv[1]);
}
vol = process (set, vol);
printf ("%d\n", vol);
fflush (stdout);
return 0;
}
#endif
#ifdef WINXP_TCL_INTERFACE
int winxpvolumeObjCmd (
ClientData cd,
Tcl_Interp* interp,
int objc,
Tcl_Obj * const objv[]
)
{
int set;
int vol;
int rc;
if (objc != 1 && objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?vol?");
return TCL_ERROR;
}
set = 0;
if (objc == 2) {
rc = Tcl_GetIntFromObj(interp, objv[1], &vol);
if (rc != TCL_OK) {
return TCL_ERROR;
}
set = 1;
}
vol = process (set, vol);
Tcl_SetObjResult (interp, Tcl_NewIntObj (vol));
return TCL_OK;
}
int
Winxpvolume_Init (Tcl_Interp *interp)
{
Tcl_Encoding utf;
#ifdef USE_TCL_STUBS
if (!Tcl_InitStubs(interp,"8.3",0)) {
return TCL_ERROR;
}
#else
if (!Tcl_PkgRequire(interp,"Tcl","8.3",0)) {
return TCL_ERROR;
}
#endif
Tcl_CreateObjCommand(interp,"winxpvolume", winxpvolumeObjCmd, (ClientData) NULL, NULL);
Tcl_PkgProvide(interp,"winxpvolume","0.1");
return TCL_OK;
}
#endif /* WINXP_TCL_INTERFACE */