**Windows: volume control** [bll] 2016-12-15 This Tcl stub might be useful to someone. I was using a stand-alone program (and still need to for 32-bit and Windows XP). The 32-bit .dll is not linking properly, don't know what is going on with that. ====== load [file join [pwd] winvolume64[info sharedlibextension]] set vol [winvolume] ; # get the volume incr vol -10 set newvol [winvolume $vol] ; # set the volume, always returns the current volume. ====== '''winmkvol.sh''' ====== #!/bin/bash # # Run within Msys2 case $MSYSTEM in *32) g++ -m32 -shared -static-libgcc -o winvolume32.dll \ -I$HOME/local-32/include -DUSE_TCL_STUBS winvolume.cpp \ -L$HOME/local-32/lib -ltclstub86 -lole32 ;; *64) g++ -m64 -shared -static-libgcc -o winvolume64.dll \ -I$HOME/local-64/include -DUSE_TCL_STUBS winvolume.cpp \ -L$HOME/local-64/lib -ltclstub86 -lole32 ;; esac ====== '''winvolume.cpp''' ====== /* much of the original volume code from: https://gist.github.com/rdp/8363580 */ #include #include #include #include #include #include #include #include /* log */ #define EXIT_ON_ERROR(hr) \ if (FAILED(hr)) { printf ("error %d occurred\n", -hr); goto Exit; } #define SAFE_RELEASE(punk) \ if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; } extern "C" { int winvolumeObjCmd ( ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj * const objv[] ) { IAudioEndpointVolume *g_pEndptVol = NULL; HRESULT hr = S_OK; IMMDeviceEnumerator *pEnumerator = NULL; IMMDevice *pDevice = NULL; OSVERSIONINFO VersionInfo; float currentVal; int vol; int rc; if (objc != 1 && objc != 2) { Tcl_WrongNumArgs (interp, 1, objv, "?volume?"); return TCL_ERROR; } vol = -1; if (objc == 2) { rc = Tcl_GetIntFromObj (interp, objv[1], &vol); if (rc != TCL_OK) { vol = -1; } } ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO)); VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&VersionInfo); if (VersionInfo.dwMajorVersion <= 5) { return TCL_ERROR; } CoInitialize(NULL); // Get enumerator for audio endpoint devices. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); EXIT_ON_ERROR(hr) // Get default audio-rendering device. hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice); EXIT_ON_ERROR(hr) hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&g_pEndptVol); EXIT_ON_ERROR(hr) if (objc == 2) { float got = (float) vol / 100.0; // needs to be within 1.0 to 0.0 hr = g_pEndptVol->SetMasterVolumeLevelScalar (got, NULL); EXIT_ON_ERROR(hr) } hr = g_pEndptVol->GetMasterVolumeLevelScalar (¤tVal); EXIT_ON_ERROR(hr) Tcl_SetObjResult (interp, Tcl_NewIntObj ((int) round(100 * currentVal))); Exit: SAFE_RELEASE(pEnumerator) SAFE_RELEASE(pDevice) SAFE_RELEASE(g_pEndptVol) CoUninitialize(); return TCL_OK; } int Winvolume_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,"winvolume", winvolumeObjCmd, (ClientData) NULL, NULL); Tcl_PkgProvide(interp,"winvolume","0.1"); return TCL_OK; } } /* extern C */ ====== <>Windows