mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-14 04:38:26 +10:00
Some branding and licensing work (#22)
* Fix stdafx include * Fix basic handling of "Games" folder on Windows10 RS4 (#10) This does the following: - Sets the default state to hidden - Skips the Games folder when searching This does not: - Hide the dead menu entry. I do not currently know how to actively change the user preference setting to forcefully hide it. * Add basic Visual Studio gitignore * Add specific entries to gitignore * Do not set default menu to Win7 on RS4 (#10) * Rename "PC Settings" to "Settings" (#12) * Create distinction between modern and legacy settings in search results * Add more build artifacts to gitignore * Add default paths for toolset and build all languages * Fix several memsize, memtype and nullpointer issues * create trunk branch containing all changes * set fallback and next version to 4.3.2, set resource fallback value to allow loading in IDE * add generated en-US.dll to gitignore * Don't echo script contents, add disabled "git clean -dfx" to build fresh * Initial re-branding work (#21) * Create copy of __MakeFinal to build all languages (Use this file when releasing new versions) * Move the registry key IvoSoft->Passionate-Coder (#21) * Change company/mfg name IvoSoft->Passionate-Coder (#21) * Update some leftover copyright dates (#21) * Fix accidental copy-paste breaking MakeFinal scripts * Fix invalid company name for Wix and change registry keys to match the new string (#21) * Update more copyright and legal text (#21) * Update RTF files format (Wordpad generated those) (#21) * update license text in RTF files (#21) We lost the blue link text in the installer page. Will have to manually re-color all the links later.
This commit is contained in:
@@ -0,0 +1,685 @@
|
||||
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
||||
// Classic Start (c) 2017-2018, The Passionate-Coder Team
|
||||
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "JumpLists.h"
|
||||
#include "ItemManager.h"
|
||||
#include "ResourceHelper.h"
|
||||
#include "Translations.h"
|
||||
#include "FNVHash.h"
|
||||
#include "LogManager.h"
|
||||
#include <propkey.h>
|
||||
#include <StrSafe.h>
|
||||
|
||||
static const CLSID CLSID_AutomaticDestinationList={0xf0ae1542, 0xf497, 0x484b, {0xa1, 0x75, 0xa2, 0x0d, 0xb0, 0x91, 0x44, 0xba}};
|
||||
|
||||
struct APPDESTCATEGORY
|
||||
{
|
||||
int type;
|
||||
union
|
||||
{
|
||||
wchar_t *name;
|
||||
int subType;
|
||||
};
|
||||
int count;
|
||||
int pad[10]; // just in case
|
||||
};
|
||||
|
||||
static const GUID IID_IDestinationList={0x03f1eed2, 0x8676, 0x430b, {0xab, 0xe1, 0x76, 0x5c, 0x1d, 0x8f, 0xe1, 0x47}};
|
||||
static const GUID IID_IDestinationList10a={0xfebd543d, 0x1f7b, 0x4b38, {0x94, 0x0b, 0x59, 0x33, 0xbd, 0x2c, 0xb2, 0x1b}}; // 10240
|
||||
static const GUID IID_IDestinationList10b={0x507101cd, 0xf6ad, 0x46c8, {0x8e, 0x20, 0xee, 0xb9, 0xe6, 0xba, 0xc4, 0x7f}}; // 10547
|
||||
|
||||
interface IDestinationList: public IUnknown
|
||||
{
|
||||
public:
|
||||
STDMETHOD(SetMinItems)();
|
||||
virtual HRESULT STDMETHODCALLTYPE SetApplicationID( LPCWSTR appUserModelId ) = 0;
|
||||
STDMETHOD(GetSlotCount)();
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCategoryCount( UINT *pCount ) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetCategory( UINT index, int getCatFlags, APPDESTCATEGORY *pCategory ) = 0;
|
||||
STDMETHOD(DeleteCategory)();
|
||||
virtual HRESULT STDMETHODCALLTYPE EnumerateCategoryDestinations( UINT index, REFIID riid, void **ppvObject ) = 0;
|
||||
STDMETHOD(RemoveDestination)( IUnknown *pItem );
|
||||
STDMETHOD(ResolveDestination)();
|
||||
};
|
||||
|
||||
static const GUID IID_IAutomaticDestinationList={0xbc10dce3, 0x62f2, 0x4bc6, {0xaf, 0x37, 0xdb, 0x46, 0xed, 0x78, 0x73, 0xc4}};
|
||||
static const GUID IID_IAutomaticDestinationList10b={0xe9c5ef8d, 0xfd41, 0x4f72, {0xba, 0x87, 0xeb, 0x03 ,0xba, 0xd5, 0x81, 0x7c}}; // 10547
|
||||
|
||||
interface IAutomaticDestinationList: public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE Initialize( LPCWSTR appUserModelId, LPCWSTR lnkPath, LPCWSTR ) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE HasList( BOOL *pHasList ) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetList( int listType, unsigned int maxCount, REFIID riid, void **ppvObject ) = 0;
|
||||
STDMETHOD(AddUsagePoint)();
|
||||
virtual HRESULT STDMETHODCALLTYPE PinItem( IUnknown *pItem, int pinIndex ) = 0; // -1 - pin, -2 - unpin
|
||||
STDMETHOD(IsPinned)();
|
||||
virtual HRESULT STDMETHODCALLTYPE RemoveDestination( IUnknown *pItem ) = 0;
|
||||
STDMETHOD(SetUsageData)();
|
||||
STDMETHOD(GetUsageData)();
|
||||
STDMETHOD(ResolveDestination)();
|
||||
virtual HRESULT STDMETHODCALLTYPE ClearList( int listType ) = 0;
|
||||
};
|
||||
|
||||
interface IAutomaticDestinationList10b: public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE Initialize( LPCWSTR appUserModelId, LPCWSTR lnkPath, LPCWSTR ) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE HasList( BOOL *pHasList ) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetList( int listType, unsigned int maxCount, unsigned int flags, REFIID riid, void **ppvObject ) = 0;
|
||||
STDMETHOD(AddUsagePoint)();
|
||||
virtual HRESULT STDMETHODCALLTYPE PinItem( IUnknown *pItem, int pinIndex ) = 0; // -1 - pin, -2 - unpin
|
||||
STDMETHOD(IsPinned)();
|
||||
virtual HRESULT STDMETHODCALLTYPE RemoveDestination( IUnknown *pItem ) = 0;
|
||||
STDMETHOD(SetUsageData)();
|
||||
STDMETHOD(GetUsageData)();
|
||||
STDMETHOD(ResolveDestination)();
|
||||
virtual HRESULT STDMETHODCALLTYPE ClearList( int listType ) = 0;
|
||||
};
|
||||
|
||||
class CAutomaticList
|
||||
{
|
||||
public:
|
||||
CAutomaticList( const wchar_t *appid );
|
||||
bool HasList( void );
|
||||
CComPtr<IObjectCollection> GetList( int listType, unsigned int maxCount );
|
||||
void PinItem( IUnknown *pItem, int pinIndex );
|
||||
bool RemoveDestination( IUnknown *pItem );
|
||||
|
||||
private:
|
||||
CComPtr<IAutomaticDestinationList> m_pAutoList;
|
||||
CComPtr<IAutomaticDestinationList10b> m_pAutoList10b;
|
||||
};
|
||||
|
||||
CAutomaticList::CAutomaticList( const wchar_t *appid )
|
||||
{
|
||||
CComPtr<IUnknown> pAutoListUnk;
|
||||
if (SUCCEEDED(pAutoListUnk.CoCreateInstance(CLSID_AutomaticDestinationList)))
|
||||
{
|
||||
pAutoListUnk->QueryInterface(IID_IAutomaticDestinationList,(void**)&m_pAutoList);
|
||||
if (m_pAutoList)
|
||||
{
|
||||
if (FAILED(m_pAutoList->Initialize(appid,NULL,NULL)))
|
||||
m_pAutoList=NULL;
|
||||
}
|
||||
else if (GetWinVersion()>=WIN_VER_WIN10)
|
||||
{
|
||||
pAutoListUnk->QueryInterface(IID_IAutomaticDestinationList10b,(void**)&m_pAutoList10b);
|
||||
if (m_pAutoList10b)
|
||||
{
|
||||
if (FAILED(m_pAutoList10b->Initialize(appid,NULL,NULL)))
|
||||
m_pAutoList10b=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CAutomaticList::HasList( void )
|
||||
{
|
||||
BOOL hasList;
|
||||
if (m_pAutoList)
|
||||
{
|
||||
if (FAILED(m_pAutoList->HasList(&hasList)) || !hasList)
|
||||
return false;
|
||||
}
|
||||
else if (m_pAutoList10b)
|
||||
{
|
||||
if (FAILED(m_pAutoList10b->HasList(&hasList)) || !hasList)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
CComPtr<IObjectCollection> pCollection;
|
||||
UINT count;
|
||||
pCollection=GetList(1,1);
|
||||
if (pCollection && SUCCEEDED(pCollection->GetCount(&count)) && count>0)
|
||||
return true;
|
||||
pCollection=GetList(0,1);
|
||||
if (pCollection && SUCCEEDED(pCollection->GetCount(&count)) && count>0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
CComPtr<IObjectCollection> CAutomaticList::GetList( int listType, unsigned int maxCount )
|
||||
{
|
||||
CComPtr<IObjectCollection> pCollection;
|
||||
if (m_pAutoList)
|
||||
m_pAutoList->GetList(listType,maxCount,IID_IObjectCollection,(void**)&pCollection);
|
||||
else if (m_pAutoList10b)
|
||||
m_pAutoList10b->GetList(listType,maxCount,1,IID_IObjectCollection,(void**)&pCollection);
|
||||
return pCollection;
|
||||
}
|
||||
|
||||
void CAutomaticList::PinItem( IUnknown *pItem, int pinIndex )
|
||||
{
|
||||
if (m_pAutoList)
|
||||
m_pAutoList->PinItem(pItem,pinIndex);
|
||||
else if (m_pAutoList10b)
|
||||
m_pAutoList10b->PinItem(pItem,pinIndex);
|
||||
}
|
||||
|
||||
bool CAutomaticList::RemoveDestination( IUnknown *pItem )
|
||||
{
|
||||
if (m_pAutoList)
|
||||
return SUCCEEDED(m_pAutoList->RemoveDestination(pItem));
|
||||
else if (m_pAutoList10b)
|
||||
return SUCCEEDED(m_pAutoList10b->RemoveDestination(pItem));
|
||||
return false;
|
||||
}
|
||||
|
||||
static CComPtr<IDestinationList> GetCustomList( const wchar_t *appid )
|
||||
{
|
||||
CComPtr<IUnknown> pCustomListUnk;
|
||||
if (SUCCEEDED(pCustomListUnk.CoCreateInstance(CLSID_DestinationList)))
|
||||
{
|
||||
CComPtr<IDestinationList> pCustomList;
|
||||
if (GetWinVersion()<WIN_VER_WIN10)
|
||||
pCustomListUnk->QueryInterface(IID_IDestinationList,(void**)&pCustomList);
|
||||
else
|
||||
{
|
||||
if (FAILED(pCustomListUnk->QueryInterface(IID_IDestinationList10a,(void**)&pCustomList)))
|
||||
pCustomListUnk->QueryInterface(IID_IDestinationList10b,(void**)&pCustomList);
|
||||
}
|
||||
if (pCustomList && SUCCEEDED(pCustomList->SetApplicationID(appid)))
|
||||
return pCustomList;
|
||||
}
|
||||
return CComPtr<IDestinationList>();
|
||||
}
|
||||
|
||||
// Returns true if the given app has a non-empty jumplist
|
||||
bool HasJumplist( const wchar_t *appid )
|
||||
{
|
||||
Assert(GetWinVersion()>=WIN_VER_WIN7);
|
||||
|
||||
CComPtr<IDestinationList> pCustomList=GetCustomList(appid);
|
||||
if (pCustomList)
|
||||
{
|
||||
UINT count;
|
||||
if (SUCCEEDED(pCustomList->GetCategoryCount(&count)) && count>0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CAutomaticList(appid).HasList())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int CalcLinkHash( IShellLink *pLink )
|
||||
{
|
||||
CAbsolutePidl pidl;
|
||||
if (FAILED(pLink->GetIDList(&pidl)))
|
||||
return 0;
|
||||
|
||||
unsigned int hash=FNV_HASH0;
|
||||
CComString pName;
|
||||
if (SUCCEEDED(SHGetNameFromIDList(pidl,SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
||||
{
|
||||
pName.MakeUpper();
|
||||
hash=CalcFNVHash(pName);
|
||||
}
|
||||
CComQIPtr<IPropertyStore> pStore=pLink;
|
||||
if (pStore)
|
||||
hash=CalcFNVHash(GetPropertyStoreString(pStore,PKEY_Link_Arguments),hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void AddJumpItem( CJumpGroup &group, IUnknown *pUnknown, std::vector<CComPtr<IShellItem>> &ignoreItems, std::vector<unsigned int> &ignoreLinks )
|
||||
{
|
||||
CJumpItem item;
|
||||
item.type=CJumpItem::TYPE_UNKNOWN;
|
||||
item.pItem=pUnknown;
|
||||
item.hash=0;
|
||||
item.bHidden=false;
|
||||
item.bHasArguments=false;
|
||||
CComQIPtr<IShellItem> pItem=pUnknown;
|
||||
if (pItem)
|
||||
{
|
||||
for (std::vector<CComPtr<IShellItem>>::const_iterator it=ignoreItems.begin();it!=ignoreItems.end();++it)
|
||||
{
|
||||
int order;
|
||||
if (SUCCEEDED(pItem->Compare(*it,SICHINT_CANONICAL|SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL,&order)) && order==0)
|
||||
return;
|
||||
}
|
||||
item.type=CJumpItem::TYPE_ITEM;
|
||||
CComString pName;
|
||||
if (FAILED(pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
||||
return;
|
||||
item.name=pName;
|
||||
pName.Clear();
|
||||
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
||||
{
|
||||
LOG_MENU(LOG_OPEN,L"Jumplist Item Path: %s",(const wchar_t*)pName);
|
||||
pName.MakeUpper();
|
||||
item.hash=CalcFNVHash(pName);
|
||||
}
|
||||
LOG_MENU(LOG_OPEN,L"Jumplist Item Name: %s",item.name);
|
||||
group.items.push_back(item);
|
||||
return;
|
||||
}
|
||||
|
||||
CComQIPtr<IShellLink> pLink=pUnknown;
|
||||
if (pLink)
|
||||
{
|
||||
unsigned int hash=CalcLinkHash(pLink);
|
||||
for (std::vector<unsigned int>::const_iterator it=ignoreLinks.begin();it!=ignoreLinks.end();++it)
|
||||
{
|
||||
if (hash==*it)
|
||||
return;
|
||||
}
|
||||
item.type=CJumpItem::TYPE_LINK;
|
||||
CComQIPtr<IPropertyStore> pStore=pLink;
|
||||
if (pStore)
|
||||
{
|
||||
PROPVARIANT val;
|
||||
PropVariantInit(&val);
|
||||
if (group.type==CJumpGroup::TYPE_TASKS && SUCCEEDED(pStore->GetValue(PKEY_AppUserModel_IsDestListSeparator,&val)) && val.vt==VT_BOOL && val.boolVal)
|
||||
{
|
||||
item.type=CJumpItem::TYPE_SEPARATOR;
|
||||
PropVariantClear(&val);
|
||||
}
|
||||
else
|
||||
{
|
||||
CString str=GetPropertyStoreString(pStore,PKEY_Title);
|
||||
if (!str.IsEmpty())
|
||||
{
|
||||
wchar_t name[256];
|
||||
SHLoadIndirectString(str,name,_countof(name),NULL);
|
||||
item.name=name;
|
||||
}
|
||||
}
|
||||
}
|
||||
CAbsolutePidl pidl;
|
||||
if (SUCCEEDED(pLink->GetIDList(&pidl)))
|
||||
{
|
||||
CComString pName;
|
||||
if (item.name.IsEmpty())
|
||||
{
|
||||
if (SUCCEEDED(SHGetNameFromIDList(pidl,SIGDN_NORMALDISPLAY,&pName)))
|
||||
{
|
||||
item.name=pName;
|
||||
}
|
||||
}
|
||||
pName.Clear();
|
||||
if (SUCCEEDED(SHGetNameFromIDList(pidl,SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
||||
{
|
||||
LOG_MENU(LOG_OPEN,L"Jumplist Link Path: %s",(const wchar_t*)pName);
|
||||
pName.MakeUpper();
|
||||
item.hash=CalcFNVHash(pName);
|
||||
}
|
||||
CComQIPtr<IPropertyStore> pStore=pLink;
|
||||
if (pStore)
|
||||
{
|
||||
CString args=GetPropertyStoreString(pStore,PKEY_Link_Arguments);
|
||||
if (!args.IsEmpty())
|
||||
{
|
||||
LOG_MENU(LOG_OPEN,L"Jumplist Link Args: %s",args);
|
||||
item.hash=CalcFNVHash(args,item.hash);
|
||||
item.bHasArguments=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_MENU(LOG_OPEN,L"Jumplist Link Name: %s",item.name);
|
||||
if (!item.name.IsEmpty())
|
||||
group.items.push_back(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void AddJumpCollection( CJumpGroup &group, IObjectCollection *pCollection, std::vector<CComPtr<IShellItem>> &ignoreItems, std::vector<unsigned int> &ignoreLinks )
|
||||
{
|
||||
UINT count;
|
||||
if (SUCCEEDED(pCollection->GetCount(&count)))
|
||||
{
|
||||
for (UINT i=0;i<count;i++)
|
||||
{
|
||||
CComPtr<IUnknown> pUnknown;
|
||||
if (SUCCEEDED(pCollection->GetAt(i,IID_IUnknown,(void**)&pUnknown)) && pUnknown)
|
||||
AddJumpItem(group,pUnknown,ignoreItems,ignoreLinks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the jumplist for the given shortcut
|
||||
bool GetJumplist( const wchar_t *appid, CJumpList &list, int maxCount, int maxHeight, int sepHeight, int itemHeight )
|
||||
{
|
||||
Assert(GetWinVersion()>=WIN_VER_WIN7);
|
||||
list.Clear();
|
||||
|
||||
UINT categoryCount=0;
|
||||
CComPtr<IDestinationList> pCustomList=GetCustomList(appid);
|
||||
if (pCustomList)
|
||||
{
|
||||
if (FAILED(pCustomList->GetCategoryCount(&categoryCount)))
|
||||
categoryCount=0;
|
||||
}
|
||||
|
||||
list.groups.reserve(categoryCount+2);
|
||||
|
||||
std::vector<CComPtr<IShellItem>> ignoreItems;
|
||||
std::vector<unsigned int> ignoreLinks;
|
||||
CAutomaticList autoList(appid);
|
||||
{
|
||||
// add pinned
|
||||
CComPtr<IObjectCollection> pPinnedList=autoList.GetList(0,maxCount);
|
||||
if (pPinnedList)
|
||||
{
|
||||
Assert(list.groups.empty());
|
||||
list.groups.resize(list.groups.size()+1);
|
||||
CJumpGroup &group=*list.groups.rbegin();
|
||||
group.type=CJumpGroup::TYPE_PINNED;
|
||||
group.name=FindTranslation(L"JumpList.Pinned",L"Pinned");
|
||||
AddJumpCollection(group,pPinnedList,ignoreItems,ignoreLinks);
|
||||
for (std::vector<CJumpItem>::const_iterator it=group.items.begin();it!=group.items.end();++it)
|
||||
{
|
||||
CComQIPtr<IShellItem> pShellItem=it->pItem;
|
||||
if (pShellItem)
|
||||
ignoreItems.push_back(pShellItem);
|
||||
else
|
||||
{
|
||||
CComQIPtr<IShellLink> pLink=it->pItem;
|
||||
if (pLink)
|
||||
{
|
||||
unsigned int hash=CalcLinkHash(pLink);
|
||||
if (hash)
|
||||
ignoreLinks.push_back(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int taskIndex=-1;
|
||||
for (UINT catIndex=0;catIndex<categoryCount;catIndex++)
|
||||
{
|
||||
APPDESTCATEGORY category={0};
|
||||
if (SUCCEEDED(pCustomList->GetCategory(catIndex,1,&category)))
|
||||
{
|
||||
if (category.type==0)
|
||||
{
|
||||
// custom group
|
||||
if (category.name)
|
||||
{
|
||||
wchar_t name[256];
|
||||
SHLoadIndirectString(category.name,name,_countof(name),NULL);
|
||||
CoTaskMemFree(category.name);
|
||||
CComPtr<IObjectCollection> pCollection;
|
||||
if (SUCCEEDED(pCustomList->EnumerateCategoryDestinations(catIndex,IID_IObjectCollection,(void**)&pCollection)))
|
||||
{
|
||||
list.groups.resize(list.groups.size()+1);
|
||||
CJumpGroup &group=*list.groups.rbegin();
|
||||
group.name=name;
|
||||
group.type=CJumpGroup::TYPE_CUSTOM;
|
||||
AddJumpCollection(group,pCollection,ignoreItems,ignoreLinks);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (category.type==1)
|
||||
{
|
||||
// standard group
|
||||
if (category.subType==1 || category.subType==2)
|
||||
{
|
||||
CComPtr<IObjectCollection> pCollection=autoList.GetList(3-category.subType,maxCount);
|
||||
if (pCollection)
|
||||
{
|
||||
list.groups.resize(list.groups.size()+1);
|
||||
CJumpGroup &group=*list.groups.rbegin();
|
||||
if (category.subType==1)
|
||||
{
|
||||
group.type=CJumpGroup::TYPE_FREQUENT;
|
||||
group.name=FindTranslation(L"JumpList.Frequent",L"Frequent");
|
||||
}
|
||||
else
|
||||
{
|
||||
group.type=CJumpGroup::TYPE_RECENT;
|
||||
group.name=FindTranslation(L"JumpList.Recent",L"Recent");
|
||||
}
|
||||
AddJumpCollection(group,pCollection,ignoreItems,ignoreLinks);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (category.type==2 && taskIndex==-1)
|
||||
{
|
||||
taskIndex=catIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (taskIndex!=-1)
|
||||
{
|
||||
// add tasks
|
||||
CComPtr<IObjectCollection> pCollection;
|
||||
if (SUCCEEDED(pCustomList->EnumerateCategoryDestinations(taskIndex,IID_IObjectCollection,(void**)&pCollection)))
|
||||
{
|
||||
list.groups.resize(list.groups.size()+1);
|
||||
CJumpGroup &group=*list.groups.rbegin();
|
||||
group.name=FindTranslation(L"JumpList.Tasks",L"Tasks");
|
||||
group.type=CJumpGroup::TYPE_TASKS;
|
||||
AddJumpCollection(group,pCollection,ignoreItems,ignoreLinks);
|
||||
}
|
||||
}
|
||||
|
||||
if (categoryCount==0)
|
||||
{
|
||||
// add recent
|
||||
CComPtr<IObjectCollection> pRecentList=autoList.GetList(1,maxCount);
|
||||
if (pRecentList)
|
||||
{
|
||||
list.groups.resize(list.groups.size()+1);
|
||||
CJumpGroup &group=*list.groups.rbegin();
|
||||
group.type=CJumpGroup::TYPE_RECENT;
|
||||
group.name=FindTranslation(L"JumpList.Recent",L"Recent");
|
||||
AddJumpCollection(group,pRecentList,ignoreItems,ignoreLinks);
|
||||
}
|
||||
}
|
||||
|
||||
// limit the item count (not tasks or pinned)
|
||||
for (std::vector<CJumpGroup>::iterator it=list.groups.begin();it!=list.groups.end();++it)
|
||||
{
|
||||
CJumpGroup &group=*it;
|
||||
if (group.type==CJumpGroup::TYPE_TASKS || group.type==CJumpGroup::TYPE_PINNED)
|
||||
maxHeight-=sepHeight+(int)group.items.size()*itemHeight;
|
||||
}
|
||||
|
||||
|
||||
for (std::vector<CJumpGroup>::iterator it=list.groups.begin();it!=list.groups.end();++it)
|
||||
{
|
||||
CJumpGroup &group=*it;
|
||||
if (group.type!=CJumpGroup::TYPE_TASKS && group.type!=CJumpGroup::TYPE_PINNED)
|
||||
{
|
||||
maxHeight-=sepHeight;
|
||||
for (std::vector<CJumpItem>::iterator it2=group.items.begin();it2!=group.items.end();++it2)
|
||||
if (!it2->bHidden)
|
||||
{
|
||||
it2->bHidden=(maxCount<=0 || maxHeight<itemHeight);
|
||||
maxCount--;
|
||||
maxHeight-=itemHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hide empty groups
|
||||
for (std::vector<CJumpGroup>::iterator it=list.groups.begin();it!=list.groups.end();++it)
|
||||
{
|
||||
CJumpGroup &group=*it;
|
||||
group.bHidden=true;
|
||||
for (std::vector<CJumpItem>::const_iterator it2=group.items.begin();it2!=group.items.end();++it2)
|
||||
if (!it2->bHidden)
|
||||
{
|
||||
group.bHidden=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Executes the given item using the correct application
|
||||
bool ExecuteJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpItem &item, HWND hwnd )
|
||||
{
|
||||
Assert(GetWinVersion()>=WIN_VER_WIN7);
|
||||
if (!item.pItem) return false;
|
||||
if (item.type==CJumpItem::TYPE_ITEM)
|
||||
{
|
||||
/* CString appid;
|
||||
{
|
||||
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
||||
appid=pAppInfo->GetAppid();
|
||||
}
|
||||
LOG_MENU(LOG_OPEN,L"Execute Item: name=%s, appid=%s",item.name,appid);*/
|
||||
CComQIPtr<IShellItem> pItem=item.pItem;
|
||||
if (!pItem)
|
||||
return false;
|
||||
/* CComString pName;
|
||||
if (FAILED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName)))
|
||||
return false;
|
||||
wchar_t ext[_MAX_EXT];
|
||||
Strcpy(ext,_countof(ext),PathFindExtension(pName));
|
||||
|
||||
// find the correct association handler by appid and invoke it on the item
|
||||
CComPtr<IEnumAssocHandlers> pEnumHandlers;
|
||||
if (ext[0] && SUCCEEDED(SHAssocEnumHandlers(ext,ASSOC_FILTER_RECOMMENDED,&pEnumHandlers)))
|
||||
{
|
||||
CComPtr<IAssocHandler> pHandler;
|
||||
ULONG count;
|
||||
while (SUCCEEDED(pEnumHandlers->Next(1,&pHandler,&count)) && count==1)
|
||||
{
|
||||
CComQIPtr<IObjectWithAppUserModelID> pObject=pHandler;
|
||||
if (pObject)
|
||||
{
|
||||
CComString pID;
|
||||
if (SUCCEEDED(pObject->GetAppID(&pID)))
|
||||
{
|
||||
// found explicit appid
|
||||
if (_wcsicmp(appid,pID)==0)
|
||||
{
|
||||
LOG_MENU(LOG_OPEN,L"Found handler appid");
|
||||
CComPtr<IDataObject> pDataObject;
|
||||
if (SUCCEEDED(pItem->BindToHandler(NULL,BHID_DataObject,IID_IDataObject,(void**)&pDataObject)) && SUCCEEDED(pHandler->Invoke(pDataObject)))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pHandler=NULL;
|
||||
}
|
||||
pEnumHandlers=NULL;
|
||||
|
||||
// find the correct association handler by exe name and invoke it on the item
|
||||
wchar_t targetPath[_MAX_PATH];
|
||||
targetPath[0]=0;
|
||||
{
|
||||
CComPtr<IShellItem> pItem;
|
||||
SHCreateItemFromIDList(pAppInfo->GetPidl(),IID_IShellItem,(void**)&pItem);
|
||||
CComPtr<IShellLink> pLink;
|
||||
if (pItem)
|
||||
pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IShellLink,(void**)&pLink);
|
||||
CAbsolutePidl target;
|
||||
if (pLink && SUCCEEDED(pLink->Resolve(NULL,SLR_INVOKE_MSI|SLR_NO_UI|SLR_NOUPDATE)) && SUCCEEDED(pLink->GetIDList(&target)))
|
||||
{
|
||||
if (FAILED(SHGetPathFromIDList(target,targetPath)))
|
||||
targetPath[0]=0;
|
||||
}
|
||||
}
|
||||
if (targetPath[0] && SUCCEEDED(SHAssocEnumHandlers(ext,ASSOC_FILTER_RECOMMENDED,&pEnumHandlers)))
|
||||
{
|
||||
while (SUCCEEDED(pEnumHandlers->Next(1,&pHandler,&count)) && count==1)
|
||||
{
|
||||
CComString pExe;
|
||||
if (SUCCEEDED(pHandler->GetName(&pExe)))
|
||||
{
|
||||
if (_wcsicmp(targetPath,pExe)==0)
|
||||
{
|
||||
LOG_MENU(LOG_OPEN,L"Found handler appexe %s",targetPath);
|
||||
CComPtr<IDataObject> pDataObject;
|
||||
if (SUCCEEDED(pItem->BindToHandler(NULL,BHID_DataObject,IID_IDataObject,(void**)&pDataObject)) && SUCCEEDED(pHandler->Invoke(pDataObject)))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pHandler=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// couldn't find a handler, execute the old way
|
||||
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_IDLIST|SEE_MASK_FLAG_LOG_USAGE};
|
||||
execute.nShow=SW_SHOWNORMAL;
|
||||
CAbsolutePidl pidl;
|
||||
if (SUCCEEDED(SHGetIDListFromObject(pItem,&pidl)))
|
||||
{
|
||||
execute.lpIDList=pidl;
|
||||
ShellExecuteEx(&execute);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.type==CJumpItem::TYPE_LINK)
|
||||
{
|
||||
// invoke the link through its context menu
|
||||
CComQIPtr<IContextMenu> pMenu=item.pItem;
|
||||
if (!pMenu) return false;
|
||||
HRESULT hr;
|
||||
HMENU menu=CreatePopupMenu();
|
||||
hr=pMenu->QueryContextMenu(menu,0,1,1000,CMF_DEFAULTONLY);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DestroyMenu(menu);
|
||||
return false;
|
||||
}
|
||||
int id=GetMenuDefaultItem(menu,FALSE,0);
|
||||
if (id>0)
|
||||
{
|
||||
CMINVOKECOMMANDINFO command={sizeof(command),CMIC_MASK_FLAG_LOG_USAGE};
|
||||
command.lpVerb=MAKEINTRESOURCEA(id-1);
|
||||
wchar_t path[_MAX_PATH];
|
||||
GetModuleFileName(NULL,path,_countof(path));
|
||||
if (_wcsicmp(PathFindFileName(path),L"explorer.exe")==0)
|
||||
command.fMask|=CMIC_MASK_ASYNCOK;
|
||||
command.hwnd=hwnd;
|
||||
command.nShow=SW_SHOWNORMAL;
|
||||
hr=pMenu->InvokeCommand(&command);
|
||||
}
|
||||
DestroyMenu(menu);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes the given item from the jumplist
|
||||
void RemoveJumpItem( const CItemManager::ItemInfo *pAppInfo, CJumpList &list, int groupIdx, int itemIdx )
|
||||
{
|
||||
CString appid;
|
||||
{
|
||||
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
||||
appid=pAppInfo->GetAppid();
|
||||
}
|
||||
CJumpGroup &group=list.groups[groupIdx];
|
||||
if (group.type==CJumpGroup::TYPE_FREQUENT || group.type==CJumpGroup::TYPE_RECENT)
|
||||
{
|
||||
if (CAutomaticList(appid).RemoveDestination(group.items[itemIdx].pItem))
|
||||
group.items.erase(group.items.begin()+itemIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
CComPtr<IDestinationList> pCustomList=GetCustomList(appid);
|
||||
if (pCustomList)
|
||||
{
|
||||
if (SUCCEEDED(pCustomList->RemoveDestination(group.items[itemIdx].pItem)))
|
||||
group.items.erase(group.items.begin()+itemIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pins or unpins the given item from the jumplist
|
||||
void PinJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpList &list, int groupIdx, int itemIdx, bool bPin, int pinIndex )
|
||||
{
|
||||
CString appid;
|
||||
{
|
||||
CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS);
|
||||
appid=pAppInfo->GetAppid();
|
||||
}
|
||||
const CJumpGroup &group=list.groups[groupIdx];
|
||||
CAutomaticList(appid).PinItem(group.items[itemIdx].pItem,bPin?pinIndex:-2);
|
||||
}
|
||||
Reference in New Issue
Block a user