You could always just use the mechanisms they give you to replace them. IShellIconOverlayIdentifier
Code: Select all
'' 32-bit
'' -Wl --kill-at -gen gcc -d DLL_DEBUG
'' 64-bit
'' -d DLL_DEBUG
''
'' regsvr32 NoOverlay.dll
'' Then restart explorer
#define _WIN32_WINNT &H0601
#define UNICODE
#define _UNICODE
#include "windows.bi"
#include "win/objbase.bi"
#include "win/shlobj.bi"
#include "win/shlguid.bi"
#include "crt/string.bi"
#include "crt/stdio.bi"
Dim Shared g_dllRefCount As Long
Dim Shared g_pDllPath As PWSTR
Dim Shared g_dllPathLen As size_t
Dim Shared g_interfaceKey As HKEY
Const g_iconRegKey = WStr("SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\NoShortcutIcon")
Const g_clsidRegKey= WStr("CLSID\{AF6C47F3-EB63-4BD4-A0E9-4D71104FB8F2}")
Const g_dllName = Wstr("NoShortcutIcon")
'' {AF6C47F3-EB63-4BD4-A0E9-4D71104FB8F2}
'' NoShortcutIconOverlay
Static Shared g_NullLinkIconCLSID As CLSID = TYPE(&hAF6C47F3, &hEB63, &h4BD4, {&hA0, &hE9, &h4D, &h71, &h10, &h4F, &hB8, &hF2})
Const g_NullLinkCLSIDString = WStr("{AF6C47F3-EB63-4BD4-A0E9-4D71104FB8F2}")
#ifdef DLL_DEBUG
Sub LogMessage cdecl(ByVal fmt As PCWSTR, ...)
Dim buf as WSTRING* 2000
Dim argList as cva_list
cva_start(argList, fmt)
vsnwprintf(@buf, SizeOf(buf) \ 2, fmt, argList)
cva_end(argList)
OutputDebugString(@buf)
end sub
Sub LogIID(ByVal iid As REFIID, ByVal when As PCWSTR)
Dim iidStr As WSTRING * 60
Dim iidName As WSTRING * 128
Dim iidNameSize As DWORD = SizeOf(iidName)
StringFromGUID2(iid, @iidStr, SizeOf(iidStr) \ 2)
Dim regRet As Long = RegGetValue(g_interfaceKey, @iidStr, NULL, RRF_RT_REG_SZ, NULL, @iidName, @iidNameSize)
LogMessage("NoShortcut: %s queried for iid %s", when, Iif(regRet = ERROR_SUCCESS, @iidName, @iidStr))
end sub
#else
#define LogMessage(a, ...)
#define LogIID(a, b)
#endif
Type NoShortcutIconOverlay extends Object
Private:
As Long refCount
Public:
Declare Constructor()
'' IUnknown
Declare Virtual Function QueryInterface (BYVAL riid AS REFIID, BYVAL ppv AS PVOID PTR) AS HRESULT
Declare Virtual Function AddRef () AS ULONG
Declare Virtual Function Release () AS ULONG
''IShellIconOverlayIdentifier
Declare Virtual Function IsMemberOf(ByVal pwszPath As PCWSTR, ByVal dwAttrib As DWORD) As HRESULT
Declare Virtual Function GetOverlayInfo (ByVal pwszIconFile As PWSTR, ByVal cchMax As Long, ByVal pIndex As Long Ptr, ByVal pdwFlags As DWORD Ptr) As HRESULT
Declare Virtual Function GetPriority (ByVal pIPriority As Long Ptr) As HRESULT
end type
Constructor NoShortcutIconOverlay()
InterlockedIncrement(@g_dllRefCount)
refCount = 1
end constructor
Function NoShortcutIconOverlay.QueryInterface(BYVAL riid AS REFIID, BYVAL ppv AS PVOID PTR) AS HRESULT
If ppv = 0 Then Return E_POINTER
Dim hr As HRESULT = E_NOINTERFACE
LogIID(riid, __FUNCTION__)
If IsEqualIID(riid, @IID_IShellIconOverlayIdentifier) OrElse IsEqualIID(riid, @IID_IUnknown) Then
*ppv = @This
AddRef()
hr = S_OK
end if
Return hr
end function
Function NoShortcutIconOverlay.AddRef () AS ULONG
Return InterlockedIncrement(@refCount)
end function
Function NoShortcutIconOverlay.Release () AS ULONG
Dim as Long newCount = InterlockedDecrement(@refCount)
If newCount <= 0 Then
Delete @This
InterlockedDecrement(@g_dllRefCount)
end if
Return newCount
end function
Function NoShortcutIconOverlay.IsMemberOf(ByVal pwszPath As PCWSTR, ByVal dwAttrib As DWORD) As HRESULT
LogMessage("NoShortcut: IsMemberOf called for %s, flags %#x", pwszPath, dwAttrib)
Dim pathLen As size_t = wcslen(pwszPath)
Dim hr As HRESULT = Any
If(dwAttrib And SFGAO_LINK) OrElse ((pathLen > 4) AndAlso (_wcsicmp(pwszPath + (pathLen - 4), @WStr(".lnk")) = 0)) Then
LogMessage("NoShortcut: Active for %s", pwszPath)
hr = S_OK
Else
Dim fileInf as SHFILEINFO
fileInf.dwAttributes = SFGAO_LINK
If SHGetFileInfo(pwszPath, 0, @fileInf, SizeOf(fileInf), SHGFI_ATTR_SPECIFIED Or SHGFI_ATTRIBUTES) Then
hr = IIf(fileInf.dwAttributes And SFGAO_LINK, S_OK, S_FALSE)
Else
hr = E_FAIL
End If
End If
Return hr
end function
Function NoShortcutIconOverlay.GetOverlayInfo (ByVal pwszIconFile As PWSTR, ByVal cchMax As Long, ByVal pIndex As Long Ptr, ByVal pdwFlags As DWORD Ptr) As HRESULT
If pIndex = 0 OrElse pwszIconFile = 0 OrElse pdwFlags = 0 Then Return E_POINTER
If cchMax < g_dllPathLen Then Return E_OUTOFMEMORY
wcscpy(pwszIconFile, g_pDllPath)
*pIndex = 0
*pdwFlags = ISIOI_ICONFILE Or ISIOI_ICONINDEX
LogMessage("NoShortcut: GetOverlayInfo returned %s, index: %d, flags: %#x", pwszIconFile, *pIndex, *pdwFlags)
Return S_OK
end function
Function NoShortcutIconOverlay.GetPriority (ByVal pIPriority As Long Ptr) As HRESULT
Dim hr As HRESULT = S_OK
If pIPriority Then
*pIPriority = 0
Else
hr = E_POINTER
end if
Return hr
end function
Type NoShortcutIconClassFactory extends Object
Private:
As Long refCount
Public:
Declare Constructor()
'' IUnknown
Declare Virtual Function QueryInterface (BYVAL riid AS REFIID, BYVAL ppv AS PVOID PTR) AS HRESULT
Declare Virtual Function AddRef () AS ULONG
Declare Virtual Function Release () AS ULONG
'' IClassFactory
DECLARE Virtual Function CreateInstance (BYVAL punk As LPUNKNOWN, ByVal riid As REFIID, ByVal ppv As PVOID Ptr) AS HRESULT
DECLARE Virtual Function LockServer (BYVAL fLock AS Long) AS HRESULT
End Type
Constructor NoShortcutIconClassFactory()
InterlockedIncrement(@g_dllRefCount)
refCount = 1
end constructor
Function NoShortcutIconClassFactory.QueryInterface(BYVAL riid AS REFIID, BYVAL ppv AS PVOID PTR) AS HRESULT
Dim hr As HRESULT = E_NOINTERFACE
If ppv = 0 Then Return E_POINTER
LogIID(riid, __FUNCTION__)
If IsEqualIID(riid, @IID_IClassFactory) OrElse IsEqualIID(riid, @IID_IUnknown) Then
*ppv = @This
AddRef()
hr = S_OK
end if
Return hr
end function
Function NoShortcutIconClassFactory.AddRef () AS ULONG
Return InterlockedIncrement(@refCount)
end function
Function NoShortcutIconClassFactory.Release () AS ULONG
Dim as Long newCount = InterlockedDecrement(@refCount)
If newCount <= 0 Then
Delete @This
InterlockedDecrement(@g_dllRefCount)
end if
Return newCount
end function
Function NoShortcutIconClassFactory.CreateInstance (BYVAL punk As LPUNKNOWN, ByVal riid As REFIID, ByVal ppv As PVOID Ptr) AS HRESULT
If pUnk Then Return CLASS_E_NOAGGREGATION
Dim pOverlay As NoShortcutIconOverlay Ptr = New NoShortcutIconOverlay()
Dim hr As HRESULT = pOverlay->QueryInterface(riid, ppv)
pOverlay->Release()
Return hr
end function
Function NoShortcutIconClassFactory.LockServer (BYVAL fLock AS Long) AS HRESULT
If fLock Then
AddRef()
Else
Release()
end if
return S_OK
end function
Extern "Windows-MS"
Public Function DllGetClassObject (ByVal clsid As REFCLSID, ByVal iid As REFIID, ByVal ppv As PVOID Ptr) As HRESULT Export
Dim ret As HRESULT
LogIID(clsid, __FUNCTION__)
If IsEqualCLSID(clsid, @g_NullLinkIconCLSID) Then
Dim pClassFact As NoShortcutIconClassFactory Ptr = New NoShortcutIconClassFactory()
ret = pClassFact->QueryInterface(iid, ppv)
pClassFact->Release()
Else
ret = CLASS_E_CLASSNOTAVAILABLE
end if
Return ret
end function
Function DllCanUnloadNow () As HRESULT Export
Return IIf(g_dllRefCount = 0, S_OK, S_FALSE)
end function
Function RegisterShortcutIcon() As BOOL
Dim ret As BOOL
Dim hKey As HKEY
If RegCreateKeyEx(HKEY_LOCAL_MACHINE, g_iconRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, @hKey, NULL) = ERROR_SUCCESS Then
LogMessage("NoShortcut: Created key %s", g_iconRegKey)
Dim stringBytes As DWORD = wcslen(@g_NullLinkCLSIDString) * 2
ret = IIf(RegSetValueEx(hKey, NULL, 0, REG_SZ, Cast(PBYTE, @g_NullLinkCLSIDString), stringBytes) = ERROR_SUCCESS, TRUE, FALSE)
RegCloseKey(hKey)
end if
Return ret
end function
Function RegisterCLSID() As BOOL
Dim ret As Long = 3
Dim hClsidKey As HKEY
If RegCreateKeyEx(HKEY_CLASSES_ROOT, g_clsidRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, @hClsidKey, NULL) = ERROR_SUCCESS Then
ret -= 1
LogMessage("NoShuortcut: Opened CLSID key %s", g_clsidRegKey)
Dim stringBytes As DWORD = wcslen(@g_dllName) * 2
'' Don't really care if this fails
RegSetValueEx(hClsidKey, NULL, 0, REG_SZ, Cast(PBYTE, @g_dllName), stringBytes)
Dim hInProcKey As HKEY
If RegCreateKeyEx(hClsidKey, @WStr("InProcServer32"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, @hInProcKey, NULL) = ERROR_SUCCESS Then
LogMessage("NoShortcut: Opened InProcServer key")
ret -= 1
Dim threadModel As PCWSTR = @WStr("Apartment")
Dim stat As LSTATUS = RegSetValueEx(hInProcKey, NULL, 0, REG_SZ, Cast(PBYTE, g_pDllPath), g_dllPathLen * 2)
stat += RegSetValueEx(hInProcKey, @WStr("ThreadingModel"), 0, REG_SZ, Cast(PBYTE, threadModel), wcslen(threadModel) * 2)
ret -= Iif(stat = ERROR_SUCCESS, 1, 0)
RegCloseKey(hInProcKey)
end if
RegCloseKey(hClsidKey)
end if
Return ret = 0
end function
Sub UnregisterShortcutIcon()
RegDeleteKey(HKEY_LOCAL_MACHINE, g_iconRegKey)
end sub
Sub UnregisterCLSID()
RegDeleteTree(HKEY_CLASSES_ROOT, g_clsidRegKey)
end sub
Function DllRegisterServer() As HRESULT Export
Dim wowProc As BOOL
If IsWow64Process(GetCurrentProcess(), @wowProc) AndAlso wowProc Then
MessageBox(NULL, "NoOverlay: Must use 64-bit dll on 64-bit Windows", "NoOverlay Dll Registration", MB_OK)
Return E_FAIL
end if
Dim ret As BOOL = RegisterShortcutIcon()
If ret Then
ret = RegisterCLSID()
If ret = FALSE Then
UnregisterShortcutIcon()
end if
end if
Return IIf(ret, S_OK, E_FAIL)
end function
Function DllUnregisterServer() As HRESULT Export
UnregisterShortcutIcon()
UnregisterCLSID()
Return S_OK
end function
End Extern
Sub CaptureDllName(ByVal hMod As HMODULE)
Dim pathChars As DWORD = MAX_PATH
Dim pDllPath As PWSTR = Allocate(pathChars * 2)
Do
Dim written As DWORD = GetModuleFileName(hMod, pDllPath, pathChars)
If written = pathChars Then
pathChars *= 2
Dim pTemp As PWSTR = ReAllocate(pDllPath, pathChars * 2)
If pTemp Then
pDllPath = pTemp
Else
DeAllocate(pDllPath)
Exit Do
end if
Else
g_dllPathLen = written + 1
g_pDllPath = pDllPath
Exit Do
end if
loop
LogMessage("NoShortcut: Dll Name is %s", g_pDllPath)
end sub
Sub FreeDllName()
DeAllocate(g_pDllPath)
end sub
Sub ModConstructor() constructor
Dim hMod As HMODULE = Any
GetModuleHandleEx(_
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS Or GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, _
Cast(PWSTR, @ModConstructor), _
@hMod _
)
LogMessage("NoShortcut: Dll loaded at %p", hMod)
DisableThreadLibraryCalls(hMod)
CaptureDllName(hMod)
#ifdef DLL_DEBUG
RegOpenKeyEx(HKEY_CLASSES_ROOT, "Interface", 0, KEY_READ, @g_interfaceKey)
#endif
end sub
Sub ModDestructor() destructor
LogMessage("NoShortcut: Dll unloading")
FreeDllName()
#ifdef DLL_DEBUG
RegCloseKey(g_interfaceKey)
#endif
end sub
It looks a lot, but most of it is just COM boilerplate, the actual custom bit is less than 80 lines.
And then a transparent icon.
.
It works on Win7 and the version of Win11 I have. But that's from last year as it's a VM so who knows if it continues to work. I can't be bothered installing the new Win11 to find out.
it should turn off all the things that show little overlay icons (things like the offline files marker, etc), but I don't guarantee it. It might also slow things down a little bit since explorer will then paint the overlays on every file icon it sees, even if it is transparent.
If you install it and then want to change it, you have to kill explorer, overwrite the dll and then restart explorer to see the changes as it doesn't ever get unloaded. This applies to unregistering it too, unregister, restart explorer, delete dll.