Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 181 additions & 1 deletion AppVolume/AppVolume.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
#include "AppVolume.h"
#include "RainmeterAPI.h"
#include "API\RainmeterAPI.h"
#include <stdexcept>

#define INVALID_FILE L"/<>\\"

#pragma pack(push, 2)
typedef struct // 16 bytes
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY, * LPICONDIRENTRY;

typedef struct // 22 bytes
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
} ICONDIR, * LPICONDIR;
#pragma pack(pop)

BOOL ParentMeasure::isCOMInitialized = FALSE;
IMMDeviceEnumerator * ParentMeasure::pEnumerator = nullptr;
Expand Down Expand Up @@ -271,6 +296,9 @@ BOOL ParentMeasure::UpdateList()

for (auto &session : sessionCollection)
{
if (!saveIcons.empty() && !PathFileExists((saveIcons + session.appName + L".png").c_str())) {
GetIcon(session.appPath, saveIcons + session.appName + L".png", iconSize);
}
float maxVol = 0.0;
for (auto &volIter : session.volume)
{
Expand Down Expand Up @@ -458,6 +486,26 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
{
parent->InitializeCOM();
parent->ignoreSystemSound = RmReadInt(rm, L"IgnoreSystemSound", 1) == 1;
std::wstring saveIcons = RmReadPath(rm, L"IconsPath", L"");
if (saveIcons.find_last_of(L'\\') != saveIcons.length()) {
saveIcons += L'\\';
}
parent->saveIcons = saveIcons;
int iconSize = RmReadInt(rm, L"IconSize", 48);
switch (iconSize)
{
case 16:
parent->iconSize = IconSize::IS_SMALL;
break;
case 32:
parent->iconSize = IconSize::IS_MEDIUM;
break;
case 256:
parent->iconSize = IconSize::IS_EXLARGE;
break;
default:
break;
}
LPCWSTR excluding = RmReadString(rm, L"ExcludeApp", L"");
if (*excluding)
{
Expand Down Expand Up @@ -989,3 +1037,135 @@ PLUGIN_EXPORT void Finalize(void* data)

delete child;
}


// copied from file view plugin
void GetIcon(std::wstring filePath, const std::wstring& iconPath, IconSize iconSize)
{
SHFILEINFO shFileInfo;
HICON icon = nullptr;
HIMAGELIST* hImageList = nullptr;
FILE* fp = nullptr;

// Special case for .url files
if (filePath.size() > 3 && _wcsicmp(filePath.substr(filePath.size() - 4).c_str(), L".URL") == 0)
{
WCHAR buffer[MAX_PATH] = L"";
GetPrivateProfileString(L"InternetShortcut", L"IconFile", L"", buffer, sizeof(buffer), filePath.c_str());
if (*buffer)
{
std::wstring file = buffer;
int iconIndex = 0;

GetPrivateProfileString(L"InternetShortcut", L"IconIndex", L"-1", buffer, sizeof(buffer), filePath.c_str());
if (buffer != L"-1")
{
iconIndex = _wtoi(buffer);
}

int size = 48;
switch (iconSize) {
case IconSize::IS_SMALL:
size = 16;
case IconSize::IS_MEDIUM:
size = 32;
case IconSize::IS_EXLARGE:
size = 256;
}

PrivateExtractIcons(file.c_str(), iconIndex, size, size, &icon, nullptr, 1, LR_LOADTRANSPARENT);
}
}

if (icon == nullptr)
{
SHGetFileInfo(filePath.c_str(), 0, &shFileInfo, sizeof(shFileInfo), SHGFI_SYSICONINDEX);
SHGetImageList((int)iconSize, IID_IImageList, (void**)&hImageList);
((IImageList*)hImageList)->GetIcon(shFileInfo.iIcon, ILD_TRANSPARENT, &icon);
}

errno_t error = _wfopen_s(&fp, iconPath.c_str(), L"wb");
if (filePath == INVALID_FILE || icon == nullptr || (error == 0 && !SaveIcon(icon, fp)))
{
fwrite(iconPath.c_str(), 1, 1, fp); // Clears previous icon
fclose(fp);
}

DestroyIcon(icon);
}

bool SaveIcon(HICON hIcon, FILE* fp)
{
ICONINFO iconInfo;
BITMAP bmColor;
BITMAP bmMask;
if (!fp || nullptr == hIcon || !GetIconInfo(hIcon, &iconInfo) ||
!GetObject(iconInfo.hbmColor, sizeof(bmColor), &bmColor) ||
!GetObject(iconInfo.hbmMask, sizeof(bmMask), &bmMask))
return false;

// support only 16/32 bit icon now
if (bmColor.bmBitsPixel != 16 && bmColor.bmBitsPixel != 32)
return false;

HDC dc = GetDC(nullptr);
BYTE bmiBytes[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
BITMAPINFO* bmi = (BITMAPINFO*)bmiBytes;

// color bits
memset(bmi, 0, sizeof(BITMAPINFO));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(dc, iconInfo.hbmColor, 0, bmColor.bmHeight, nullptr, bmi, DIB_RGB_COLORS);
int colorBytesCount = bmi->bmiHeader.biSizeImage;
BYTE* colorBits = new BYTE[colorBytesCount];
GetDIBits(dc, iconInfo.hbmColor, 0, bmColor.bmHeight, colorBits, bmi, DIB_RGB_COLORS);

// mask bits
memset(bmi, 0, sizeof(BITMAPINFO));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(dc, iconInfo.hbmMask, 0, bmMask.bmHeight, nullptr, bmi, DIB_RGB_COLORS);
int maskBytesCount = bmi->bmiHeader.biSizeImage;
BYTE* maskBits = new BYTE[maskBytesCount];
GetDIBits(dc, iconInfo.hbmMask, 0, bmMask.bmHeight, maskBits, bmi, DIB_RGB_COLORS);

ReleaseDC(nullptr, dc);

// icon data
BITMAPINFOHEADER bmihIcon;
memset(&bmihIcon, 0, sizeof(bmihIcon));
bmihIcon.biSize = sizeof(BITMAPINFOHEADER);
bmihIcon.biWidth = bmColor.bmWidth;
bmihIcon.biHeight = bmColor.bmHeight * 2; // icXOR + icAND
bmihIcon.biPlanes = bmColor.bmPlanes;
bmihIcon.biBitCount = bmColor.bmBitsPixel;
bmihIcon.biSizeImage = colorBytesCount + maskBytesCount;

// icon header
ICONDIR dir;
dir.idReserved = 0; // must be 0
dir.idType = 1; // 1 for icons
dir.idCount = 1;
dir.idEntries[0].bWidth = (BYTE)bmColor.bmWidth;
dir.idEntries[0].bHeight = (BYTE)bmColor.bmHeight;
dir.idEntries[0].bColorCount = 0; // 0 if >= 8bpp
dir.idEntries[0].bReserved = 0; // must be 0
dir.idEntries[0].wPlanes = bmColor.bmPlanes;
dir.idEntries[0].wBitCount = bmColor.bmBitsPixel;
dir.idEntries[0].dwBytesInRes = sizeof(bmihIcon) + bmihIcon.biSizeImage;
dir.idEntries[0].dwImageOffset = sizeof(ICONDIR);

fwrite(&dir, sizeof(dir), 1, fp);
fwrite(&bmihIcon, sizeof(bmihIcon), 1, fp);
fwrite(colorBits, colorBytesCount, 1, fp);
fwrite(maskBits, maskBytesCount, 1, fp);

// Clean up
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
delete[] colorBits;
delete[] maskBits;

fclose(fp);

return true;
}
20 changes: 19 additions & 1 deletion AppVolume/AppVolume.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once
#include <windows.h>
#include <commctrl.h>
#include <commoncontrols.h>

#include <Endpointvolume.h>
#include <Audiopolicy.h>
Expand Down Expand Up @@ -42,6 +44,14 @@ enum StringType
ICONPATH
};

enum class IconSize
{
IS_SMALL = 1, // 16x16
IS_MEDIUM = 0, // 32x32
IS_LARGE = 2, // 48x48
IS_EXLARGE = 4 // 256x256
};

class AppSession
{
public:
Expand Down Expand Up @@ -77,13 +87,17 @@ class ParentMeasure
BOOL ignoreSystemSound;
std::vector<AppSession> sessionCollection;
std::vector<std::wstring> excludeList;
std::wstring saveIcons;
IconSize iconSize;

ParentMeasure() :
skin(nullptr),
rm(nullptr),
initError(FALSE),
name(nullptr),
ignoreSystemSound(true)
ignoreSystemSound(true),
saveIcons(),
iconSize(IconSize::IS_LARGE)
{};

~ParentMeasure();
Expand All @@ -107,6 +121,8 @@ class ChildMeasure
std::wstring indexApp;

ChildMeasure() :
parent(),
rm(),
indexType(NOINDEXTYPE),
numtype(NONUMTYPE),
strtype(NOSTRTYPE),
Expand All @@ -128,3 +144,5 @@ class ChildMeasure
void SeparateList(LPCWSTR list, std::vector<std::wstring> &vectorList);
BOOL IsValidParent(ChildMeasure * child, LPCWSTR functionName, LPCWSTR functionArg);
BOOL IsValidIndex(int index, ChildMeasure * child, LPCWSTR functionName, LPCWSTR functionArg);
void GetIcon(std::wstring filePath, const std::wstring& iconPath, IconSize iconSize);
bool SaveIcon(HICON hIcon, FILE* fp);
Binary file modified AppVolume/AppVolume.rc
Binary file not shown.
11 changes: 6 additions & 5 deletions AppVolume/AppVolume.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,32 @@
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{996CDD3C-F8EC-4DB4-BD82-B1F61FB9999A}</ProjectGuid>
<RootNamespace>AppVolume</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
Expand Down Expand Up @@ -130,6 +130,7 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(ProjectDir)\API</AdditionalIncludeDirectories>
<LanguageStandard>Default</LanguageStandard>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
Expand Down