Skip to content

Commit

Permalink
FIle Explorer: Fix Pin to Start/Unpin from Start from Explorer and fi…
Browse files Browse the repository at this point in the history
…x command bar option not being applied to non-primary Explorer instances
  • Loading branch information
Amrsatrio committed Oct 5, 2023
1 parent fbaad56 commit 001e8d8
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 40 deletions.
16 changes: 12 additions & 4 deletions ExplorerPatcher/ExplorerPatcher.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,26 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>

This comment has been minimized.

Copy link
@valinet

valinet Oct 6, 2023

Owner

@Amrsatrio I see this has been reverted as well, what has gone wrong, what doesn't work with the new toolset?

This comment has been minimized.

Copy link
@Amrsatrio

Amrsatrio Oct 6, 2023

Author Collaborator

Nothing is wrong. I only have 22000's toolset (v143) and I don't want to install the v142 one. But Rider decided to move them to the main changelist after I've installed the WIL nuget package 🤷

This comment has been minimized.

Copy link
@valinet

valinet Oct 6, 2023

Owner

Yeah, I was just commenting that 3b38b94 you seem to have gone back to v142, so I thought something might not compile with the newer toolset. So you still plan to do it, only later, yeah, that's fine. Who's Rider?

This comment has been minimized.

Copy link
@Amrsatrio

Amrsatrio Oct 6, 2023

Author Collaborator

https://www.jetbrains.com/rider

I'm used to Jetbrains' IDEs for more than 7 years, but I'm not used to Visual Studio so I used Rider to be able to work efficiently.

This comment has been minimized.

Copy link
@valinet

valinet Oct 6, 2023

Owner

Okay, now I get it, cool. Thanks. Every day I learn something new, that's great!

Expand Down Expand Up @@ -343,10 +343,18 @@
<ResourceCompile Include="ExplorerPatcher.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="settings.reg" />
<None Include="settings10.reg" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230824.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230824.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230824.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.230824.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>
3 changes: 2 additions & 1 deletion ExplorerPatcher/ExplorerPatcher.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,6 @@
<None Include="settings10.reg">
<Filter>Settings</Filter>
</None>
<None Include="packages.config" />
</ItemGroup>
</Project>
</Project>
220 changes: 219 additions & 1 deletion ExplorerPatcher/StartMenuSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,24 @@
#include <windows.system.h>
#include <winrt/windows.foundation.collections.h>
#include <winrt/windows.system.h>
#include <roapi.h>
#include <wil/winrt.h>

extern "C" extern DWORD dwStartShowClassicMode;

static void EPWilLogCallback(wil::FailureInfo const &failure) noexcept
{
wchar_t message[2048];
HRESULT hr = GetFailureLogString(message, ARRAYSIZE(message), failure);
if (SUCCEEDED(hr))
{
wprintf(L"%s", message); // message includes newline
}
}

extern "C" void InitializeWilLogCallback()
{
SetResultLoggingCallback(EPWilLogCallback);
}

static std::vector<winrt::guid> GlobalStartData_GetPlacesFromRegistry()
{
Expand Down Expand Up @@ -137,3 +154,204 @@ extern "C" BOOL NeedsRo_SyncSettingsFromRegToCDS()

return TRUE;
}

namespace ABI::WindowsInternal::Shell::UnifiedTile
{
MIDL_INTERFACE("d3653510-4fff-4bfa-905b-ea038b142fa5")
IUnifiedTileIdentifier : public IInspectable
{
};

MIDL_INTERFACE("0e7735be-a965-44a6-a75f-54b8bcd67bec")
IWin32UnifiedTileIdentifierFactory : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE Create(HSTRING, IUnifiedTileIdentifier**) = 0;
};
}

namespace ABI::WindowsInternal::Shell::UnifiedTile::Private
{
MIDL_INTERFACE("0083831c-82d6-4e8f-bcc2-a8ac2691be49")
IUnifiedTileUserPinHelperStatics : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE CreateUserPinnedShortcutTile(IUnifiedTileIdentifier*) = 0;
};
}

namespace ABI::WindowsInternal::Shell::UnifiedTile::CuratedTileCollections
{
enum class CollectionAttributes {};
enum class PackageStatusChangeType {};
enum class StartCollectionCustomizationRestrictionType {};
enum class TilePinSize {};

namespace DataStoreCache::CuratedTileCollectionTransformer
{
class CuratedTile;
}

MIDL_INTERFACE("ffffffff-ffff-ffff-ffff-ffffffffffff")
ICuratedTileGroup : public IInspectable
{
};

MIDL_INTERFACE("ffffffff-ffff-ffff-ffff-ffffffffffff")
ICuratedTile : public IInspectable
{
};

MIDL_INTERFACE("51a07090-3a1f-49ef-9932-a971b8154790")
ICuratedTileCollection : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE get_CollectionName(HSTRING*) = 0;
virtual HRESULT STDMETHODCALLTYPE get_Attributes(CollectionAttributes*) = 0;
virtual HRESULT STDMETHODCALLTYPE put_Attributes(CollectionAttributes) = 0;
virtual HRESULT STDMETHODCALLTYPE get_Version(unsigned int*) = 0;
virtual HRESULT STDMETHODCALLTYPE put_Version(unsigned int) = 0;
virtual HRESULT STDMETHODCALLTYPE GetGroups(Windows::Foundation::Collections::IMapView<GUID, ICuratedTileGroup*>**) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTiles(Windows::Foundation::Collections::IMapView<GUID, ICuratedTile*>**) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAllTilesInCollection(Windows::Foundation::Collections::IMapView<GUID, ICuratedTile*>**) = 0;
virtual HRESULT STDMETHODCALLTYPE DoesCollectionContainTile(IUnifiedTileIdentifier*, ICuratedTile**, unsigned char*) = 0;
virtual HRESULT STDMETHODCALLTYPE FindTileAndParentGroup(IUnifiedTileIdentifier*, ICuratedTile**, ICuratedTileGroup**, unsigned char*) = 0;
virtual HRESULT STDMETHODCALLTYPE MoveExistingGroupToNewParent(ICuratedTileGroup*, ICuratedTileGroup*) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateNewGroup(ICuratedTileGroup**) = 0;
virtual HRESULT STDMETHODCALLTYPE GetGroup(GUID, ICuratedTileGroup**) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteGroup(GUID) = 0;
virtual HRESULT STDMETHODCALLTYPE RemoveGroup(GUID) = 0;
virtual HRESULT STDMETHODCALLTYPE MoveExistingTileToNewParent(ICuratedTile*, ICuratedTileGroup*) = 0;
virtual HRESULT STDMETHODCALLTYPE AddTile(IUnifiedTileIdentifier*, ICuratedTile**) = 0;
virtual HRESULT STDMETHODCALLTYPE AddTileWithId(IUnifiedTileIdentifier*, GUID, ICuratedTile**) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTile(GUID, ICuratedTile**) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteTile(GUID) = 0;
virtual HRESULT STDMETHODCALLTYPE RemoveTile(GUID) = 0;
virtual HRESULT STDMETHODCALLTYPE Commit() = 0;
virtual HRESULT STDMETHODCALLTYPE CommitAsync(Windows::Foundation::IAsyncAction**) = 0;
virtual HRESULT STDMETHODCALLTYPE CommitAsyncWithTimerBypass(Windows::Foundation::IAsyncAction**) = 0;
virtual HRESULT STDMETHODCALLTYPE ResetToDefault() = 0;
virtual HRESULT STDMETHODCALLTYPE ResetToDefaultAsync(Windows::Foundation::IAsyncAction**) = 0;
virtual HRESULT STDMETHODCALLTYPE CheckForUpdate() = 0;
virtual HRESULT STDMETHODCALLTYPE GetCustomProperty(const HSTRING, HSTRING*) = 0;
virtual HRESULT STDMETHODCALLTYPE HasCustomProperty(const HSTRING, unsigned char*) = 0;
virtual HRESULT STDMETHODCALLTYPE RemoveCustomProperty(const HSTRING) = 0;
virtual HRESULT STDMETHODCALLTYPE SetCustomProperty(const HSTRING, HSTRING) = 0;
virtual HRESULT STDMETHODCALLTYPE EnsureTileRegistration() = 0;
virtual HRESULT STDMETHODCALLTYPE ResurrectTile(std::shared_ptr<DataStoreCache::CuratedTileCollectionTransformer::CuratedTile>, const GUID&) = 0;
virtual HRESULT STDMETHODCALLTYPE OnTileAddedWithinCollection(IUnifiedTileIdentifier*) = 0;
virtual HRESULT STDMETHODCALLTYPE OnTileRemovedWithinCollection(IUnifiedTileIdentifier*) = 0;
};

MIDL_INTERFACE("adbf8965-6056-4126-ab26-6660af4661ce")
IStartTileCollection : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE PinToStart(IUnifiedTileIdentifier*, TilePinSize);
virtual HRESULT STDMETHODCALLTYPE PinToStartAtLocation(IUnifiedTileIdentifier*, ICuratedTileGroup*, Windows::Foundation::Point, Windows::Foundation::Size);
virtual HRESULT STDMETHODCALLTYPE UnpinFromStart(IUnifiedTileIdentifier*);
virtual HRESULT STDMETHODCALLTYPE ReplaceTinyOrMediumTile(IUnifiedTileIdentifier*, IUnifiedTileIdentifier*);
virtual HRESULT STDMETHODCALLTYPE get_LastGroupId(GUID*);
virtual HRESULT STDMETHODCALLTYPE put_LastGroupId(GUID);
virtual HRESULT STDMETHODCALLTYPE get_CustomizationRestriction(StartCollectionCustomizationRestrictionType*);
virtual HRESULT STDMETHODCALLTYPE put_CustomizationRestriction(StartCollectionCustomizationRestrictionType);
virtual HRESULT STDMETHODCALLTYPE get_GroupCellWidth(unsigned int*);
virtual HRESULT STDMETHODCALLTYPE put_GroupCellWidth(unsigned int);
virtual HRESULT STDMETHODCALLTYPE get_PreferredColumnCount(unsigned int*);
virtual HRESULT STDMETHODCALLTYPE put_PreferredColumnCount(unsigned int);
virtual HRESULT STDMETHODCALLTYPE get_CurrentColumnCount(unsigned int*);
virtual HRESULT STDMETHODCALLTYPE put_CurrentColumnCount(unsigned int);
};

MIDL_INTERFACE("ffffffff-ffff-ffff-ffff-ffffffffffff")
ICuratedTileCollectionOptions : public IInspectable
{
};

MIDL_INTERFACE("ffffffff-ffff-ffff-ffff-ffffffffffff")
ICuratedTileCollectionManager : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE NotifyPackageStatusChanged(HSTRING, PackageStatusChangeType) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCollection(HSTRING, ICuratedTileCollection**) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCollectionWithOptions(HSTRING, ICuratedTileCollectionOptions*, ICuratedTileCollection**) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteCollection(HSTRING) = 0;
virtual HRESULT STDMETHODCALLTYPE CollectionExists(HSTRING, unsigned char*) = 0;
virtual HRESULT STDMETHODCALLTYPE InitializeCollection(HSTRING) = 0;
};

MIDL_INTERFACE("15f254ac-49b3-4e6e-9c62-806ffaf554f9")
ICuratedTileCollectionManagerStatics : public IInspectable
{
virtual HRESULT STDMETHODCALLTYPE CreateWithUser(Windows::System::IUser*, ICuratedTileCollectionManager**) = 0;
};
}

struct CCacheShortcut
{
public:
const wchar_t* GetAppID(const void* a2) const
{
DWORD dwOffset = *((DWORD*)this + 11); // Same offset in Windows 10 and 11
return dwOffset != -1 ? (wchar_t*)((char*)a2 + dwOffset) : nullptr;
}
};

extern "C"
{
HRESULT(*AppResolver_CAppResolverCacheBuilder__AddUserPinnedShortcutToStartFunc)(const CCacheShortcut* a2, const void* a3);
HRESULT AppResolver_CAppResolverCacheBuilder__AddUserPinnedShortcutToStart(const CCacheShortcut* a2, const void* a3)
{

This comment has been minimized.

Copy link
@valinet

valinet Oct 6, 2023

Owner

@Amrsatrio So basically on Windows 11, the OS-shipped implementation doesn't contain code for working with the tile database used by the Windows 10 Start menu, so what this does is reimplement that connection (the tile database still exists), based on disassembly from previous versions?

This comment has been minimized.

Copy link
@Amrsatrio

Amrsatrio Oct 6, 2023

Author Collaborator

Yeah. Win11's CAppResolverCacheBuilder::_AddUserPinnedShortcutToStart() doesn't contain the old code. It's what you expect from Microsoft, when other functions have the old code. I disassembled the one from Win10 1904x so that I can reimplement it. I don't want to patch or hook or such because the code structure on 22000 and 22621 differs drastically.

using namespace ABI::WindowsInternal::Shell::UnifiedTile;
using namespace ABI::WindowsInternal::Shell::UnifiedTile::Private;
using namespace ABI::WindowsInternal::Shell::UnifiedTile::CuratedTileCollections;

if (dwStartShowClassicMode)

This comment has been minimized.

Copy link
@valinet

valinet Oct 6, 2023

Owner

@Amrsatrio This is wrong, it should be if (!dwStartShowClassicMode) I see you addressed it in a subsequent commit, 👍

{
return AppResolver_CAppResolverCacheBuilder__AddUserPinnedShortcutToStartFunc(a2, a3);
}

Microsoft::WRL::ComPtr<IWin32UnifiedTileIdentifierFactory> pTileIdentifierFactory;
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
Microsoft::WRL::Wrappers::HStringReference(L"WindowsInternal.Shell.UnifiedTile.UnifiedTileIdentifier").Get(),
pTileIdentifierFactory.GetAddressOf()
));

Microsoft::WRL::ComPtr<IUnifiedTileIdentifier> pTileIdentifier;
const wchar_t* pwszAppId = a2->GetAppID(a3);
RETURN_IF_FAILED(pTileIdentifierFactory->Create(
Microsoft::WRL::Wrappers::HStringReference(pwszAppId).Get(),
pTileIdentifier.GetAddressOf()
));

Microsoft::WRL::ComPtr<IUnifiedTileUserPinHelperStatics> pTileUserPinHelper;
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
Microsoft::WRL::Wrappers::HStringReference(L"WindowsInternal.Shell.UnifiedTile.Private.UnifiedTileUserPinHelper").Get(),
pTileUserPinHelper.GetAddressOf()
));

RETURN_IF_FAILED(pTileUserPinHelper->CreateUserPinnedShortcutTile(
pTileIdentifier.Get()
));

// At this point, on Windows 11 the Windows 10 code doesn't exist anymore, so we'll add them here
Microsoft::WRL::ComPtr<ICuratedTileCollectionManager> pTileCollectionManager;
RETURN_IF_FAILED(RoActivateInstance(
Microsoft::WRL::Wrappers::HStringReference(L"WindowsInternal.Shell.UnifiedTile.CuratedTileCollections.CuratedTileCollectionManager").Get(),
(IInspectable**)pTileCollectionManager.GetAddressOf()
));

Microsoft::WRL::ComPtr<ICuratedTileCollection> pTileCollection;
RETURN_IF_FAILED(pTileCollectionManager->GetCollection(
Microsoft::WRL::Wrappers::HStringReference(L"Start.TileGrid").Get(),
pTileCollection.GetAddressOf()
));

Microsoft::WRL::ComPtr<IStartTileCollection> pStartTileCollection;
RETURN_IF_FAILED(pTileCollection.As(&pStartTileCollection));

RETURN_IF_FAILED(pStartTileCollection->PinToStart(
pTileIdentifier.Get(),
static_cast<TilePinSize>(0)
));

RETURN_IF_FAILED(pTileCollection->Commit());

return S_OK;
}
}
Loading

0 comments on commit 001e8d8

Please sign in to comment.