mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-17 13:23:04 +10:00
Support for modern app jump-list tasks
Task jump-list items for modern apps require special handling. First of all they don't provide icon directly. Icon location is stored in `PKEY_AppUserModel_DestListLogoUri` property. And then has to be resolved for given application package. Next, context menu of provided `IShellLink` item doesn't seem to be able to start actual link target. Thus we need to obtain context menu of target item. Fixes #375.
This commit is contained in:
@@ -55,8 +55,8 @@ GUID IID_IApplicationResolver8={0xde25675a,0x72de,0x44b4,{0x93,0x73,0x05,0x17,0x
|
|||||||
|
|
||||||
interface IResourceContext;
|
interface IResourceContext;
|
||||||
|
|
||||||
const GUID IID_IResourceMap={0x6e21e72b, 0xb9b0, 0x42ae, {0xa6, 0x86, 0x98, 0x3c, 0xf7, 0x84, 0xed, 0xcd}};
|
MIDL_INTERFACE("6e21e72b-b9b0-42ae-a686-983cf784edcd")
|
||||||
interface IResourceMap : public IUnknown
|
IResourceMap : public IUnknown
|
||||||
{
|
{
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetUri(const wchar_t **pUri ) = 0;
|
virtual HRESULT STDMETHODCALLTYPE GetUri(const wchar_t **pUri ) = 0;
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetSubtree(const wchar_t *propName, IResourceMap **pSubTree ) = 0;
|
virtual HRESULT STDMETHODCALLTYPE GetSubtree(const wchar_t *propName, IResourceMap **pSubTree ) = 0;
|
||||||
@@ -76,8 +76,8 @@ enum RESOURCE_SCALE
|
|||||||
RES_SCALE_80 =3,
|
RES_SCALE_80 =3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const GUID IID_ResourceContext={0xe3c22b30, 0x8502, 0x4b2f, {0x91, 0x33, 0x55, 0x96, 0x74, 0x58, 0x7e, 0x51}};
|
MIDL_INTERFACE("e3c22b30-8502-4b2f-9133-559674587e51")
|
||||||
interface IResourceContext : public IUnknown
|
IResourceContext : public IUnknown
|
||||||
{
|
{
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetLanguage( void ) = 0;
|
virtual HRESULT STDMETHODCALLTYPE GetLanguage( void ) = 0;
|
||||||
virtual HRESULT STDMETHODCALLTYPE GetHomeRegion( wchar_t *pRegion ) = 0;
|
virtual HRESULT STDMETHODCALLTYPE GetHomeRegion( wchar_t *pRegion ) = 0;
|
||||||
@@ -299,7 +299,7 @@ static HBITMAP BitmapFromMetroBitmap( HBITMAP hBitmap, int bitmapSize, DWORD met
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static HBITMAP LoadMetroBitmap0( const wchar_t *path, int bitmapSize, DWORD metroColor )
|
static HBITMAP LoadMetroBitmap0(const wchar_t *path, int bitmapSize, DWORD metroColor = 0xFFFFFFFF)
|
||||||
{
|
{
|
||||||
SIZE size={-bitmapSize,bitmapSize};
|
SIZE size={-bitmapSize,bitmapSize};
|
||||||
HBITMAP hBitmap=LoadImageFile(path,&size,true,true,NULL);
|
HBITMAP hBitmap=LoadImageFile(path,&size,true,true,NULL);
|
||||||
@@ -1104,6 +1104,49 @@ const CItemManager::ItemInfo *CItemManager::GetCustomIcon( const wchar_t *path,
|
|||||||
return GetCustomIcon(text,index,iconSizeType,false);
|
return GetCustomIcon(text,index,iconSizeType,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CItemManager::ItemInfo* CItemManager::GetLinkIcon(IShellLink* link, TIconSizeType iconSizeType)
|
||||||
|
{
|
||||||
|
wchar_t location[_MAX_PATH];
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (link->GetIconLocation(location, _countof(location), &index) == S_OK && location[0])
|
||||||
|
return GetCustomIcon(location, index, iconSizeType, (index == 0)); // assuming that if index!=0 the icon comes from a permanent location like a dll or exe
|
||||||
|
|
||||||
|
CComQIPtr<IPropertyStore> store(link);
|
||||||
|
if (store)
|
||||||
|
{
|
||||||
|
// Name: System.AppUserModel.DestListLogoUri -- PKEY_AppUserModel_DestListLogoUri
|
||||||
|
// Type: String -- VT_LPWSTR
|
||||||
|
// FormatID: {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 29
|
||||||
|
static const PROPERTYKEY PKEY_AppUserModel_DestListLogoUri = { {0x9F4C2855, 0x9F79, 0x4B39, {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}}, 29 };
|
||||||
|
|
||||||
|
auto logoUri = GetPropertyStoreString(store, PKEY_AppUserModel_DestListLogoUri);
|
||||||
|
if (!logoUri.IsEmpty())
|
||||||
|
{
|
||||||
|
auto appId = GetPropertyStoreString(store, PKEY_AppUserModel_ID);
|
||||||
|
if (!appId.IsEmpty())
|
||||||
|
{
|
||||||
|
CComPtr<IResourceManager> resManager;
|
||||||
|
if (SUCCEEDED(resManager.CoCreateInstance(CLSID_ResourceManager)))
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(resManager->InitializeForPackage(GetPackageFullName(appId))))
|
||||||
|
{
|
||||||
|
CComPtr<IResourceMap> resMap;
|
||||||
|
if (SUCCEEDED(resManager->GetMainResourceMap(IID_PPV_ARGS(&resMap))))
|
||||||
|
{
|
||||||
|
CComString location;
|
||||||
|
if (SUCCEEDED(resMap->GetFilePath(logoUri, &location)))
|
||||||
|
return GetCustomIcon(location, -65536, iconSizeType, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const CItemManager::ItemInfo *CItemManager::GetMetroAppInfo10( const wchar_t *appid )
|
const CItemManager::ItemInfo *CItemManager::GetMetroAppInfo10( const wchar_t *appid )
|
||||||
{
|
{
|
||||||
wchar_t APPID[256];
|
wchar_t APPID[256];
|
||||||
@@ -2424,10 +2467,10 @@ void CItemManager::LoadMetroIcon( IShellItem *pItem, int &refreshFlags, const Ic
|
|||||||
if (FAILED(pResManager->InitializeForPackage(packageName)))
|
if (FAILED(pResManager->InitializeForPackage(packageName)))
|
||||||
return;
|
return;
|
||||||
CComPtr<IResourceMap> pResMap;
|
CComPtr<IResourceMap> pResMap;
|
||||||
if (FAILED(pResManager->GetMainResourceMap(IID_IResourceMap,(void**)&pResMap)))
|
if (FAILED(pResManager->GetMainResourceMap(IID_PPV_ARGS(&pResMap))))
|
||||||
return;
|
return;
|
||||||
CComPtr<IResourceContext> pResContext;
|
CComPtr<IResourceContext> pResContext;
|
||||||
if (FAILED(pResManager->GetDefaultContext(IID_ResourceContext,(void**)&pResContext)))
|
if (FAILED(pResManager->GetDefaultContext(IID_PPV_ARGS(&pResContext))))
|
||||||
return;
|
return;
|
||||||
int iconFlags=0;
|
int iconFlags=0;
|
||||||
if ((refreshFlags&INFO_SMALL_ICON) && SetResContextTargetSize(pResContext,SMALL_ICON_SIZE))
|
if ((refreshFlags&INFO_SMALL_ICON) && SetResContextTargetSize(pResContext,SMALL_ICON_SIZE))
|
||||||
@@ -2604,6 +2647,10 @@ void CItemManager::LoadCustomIcon(const wchar_t *iconPath, int iconIndex, int re
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto ExtractIconAsBitmap = [&](int iconSize) -> HBITMAP {
|
auto ExtractIconAsBitmap = [&](int iconSize) -> HBITMAP {
|
||||||
|
|
||||||
|
if (iconIndex == -65536)
|
||||||
|
return LoadMetroBitmap0(iconPath, iconSize);
|
||||||
|
|
||||||
HICON hIcon;
|
HICON hIcon;
|
||||||
|
|
||||||
if (!*iconPath)
|
if (!*iconPath)
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ public:
|
|||||||
const ItemInfo *GetItemInfo( CString path, int refreshFlags, TLocation location=LOCATION_UNKNOWN );
|
const ItemInfo *GetItemInfo( CString path, int refreshFlags, TLocation location=LOCATION_UNKNOWN );
|
||||||
const ItemInfo *GetCustomIcon( const wchar_t *location, int index, TIconSizeType iconSizeType, bool bTemp );
|
const ItemInfo *GetCustomIcon( const wchar_t *location, int index, TIconSizeType iconSizeType, bool bTemp );
|
||||||
const ItemInfo *GetCustomIcon( const wchar_t *path, TIconSizeType iconSizeType );
|
const ItemInfo *GetCustomIcon( const wchar_t *path, TIconSizeType iconSizeType );
|
||||||
|
const ItemInfo* GetLinkIcon(IShellLink* link, TIconSizeType iconSizeType);
|
||||||
const ItemInfo *GetMetroAppInfo10( const wchar_t *appid );
|
const ItemInfo *GetMetroAppInfo10( const wchar_t *appid );
|
||||||
void UpdateItemInfo( const ItemInfo *pInfo, int refreshFlags, bool bHasWriteLock=false );
|
void UpdateItemInfo( const ItemInfo *pInfo, int refreshFlags, bool bHasWriteLock=false );
|
||||||
void WaitForShortcuts( const POINT &balloonPos );
|
void WaitForShortcuts( const POINT &balloonPos );
|
||||||
|
|||||||
@@ -322,6 +322,9 @@ static void AddJumpItem( CJumpGroup &group, IUnknown *pUnknown, std::vector<CCom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_MENU(LOG_OPEN,L"Jumplist Link Name: %s",item.name);
|
LOG_MENU(LOG_OPEN,L"Jumplist Link Name: %s",item.name);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
LogPropertyStore(LOG_OPEN, pStore);
|
||||||
|
#endif
|
||||||
if (!item.name.IsEmpty())
|
if (!item.name.IsEmpty())
|
||||||
group.items.push_back(item);
|
group.items.push_back(item);
|
||||||
return;
|
return;
|
||||||
@@ -519,91 +522,15 @@ bool GetJumplist( const wchar_t *appid, CJumpList &list, int maxCount, int maxHe
|
|||||||
bool ExecuteJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpItem &item, HWND hwnd )
|
bool ExecuteJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpItem &item, HWND hwnd )
|
||||||
{
|
{
|
||||||
Assert(GetWinVersion()>=WIN_VER_WIN7);
|
Assert(GetWinVersion()>=WIN_VER_WIN7);
|
||||||
if (!item.pItem) return false;
|
if (!item.pItem)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (item.type==CJumpItem::TYPE_ITEM)
|
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);
|
CComQIPtr<IShellItem> pItem(item.pItem);
|
||||||
if (!pItem)
|
if (!pItem)
|
||||||
return false;
|
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};
|
SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_IDLIST|SEE_MASK_FLAG_LOG_USAGE};
|
||||||
execute.nShow=SW_SHOWNORMAL;
|
execute.nShow=SW_SHOWNORMAL;
|
||||||
CAbsolutePidl pidl;
|
CAbsolutePidl pidl;
|
||||||
@@ -617,9 +544,50 @@ bool ExecuteJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpItem &i
|
|||||||
|
|
||||||
if (item.type==CJumpItem::TYPE_LINK)
|
if (item.type==CJumpItem::TYPE_LINK)
|
||||||
{
|
{
|
||||||
// invoke the link through its context menu
|
// Name: System.AppUserModel.HostEnvironment -- PKEY_AppUserModel_HostEnvironment
|
||||||
|
// Type: UInt32 -- VT_UI4
|
||||||
|
// FormatID: {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 14
|
||||||
|
static const PROPERTYKEY PKEY_AppUserModel_HostEnvironment = { {0x9F4C2855, 0x9F79, 0x4B39, {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}}, 14 };
|
||||||
|
|
||||||
|
// Name: System.AppUserModel.ActivationContext -- PKEY_AppUserModel_ActivationContext
|
||||||
|
// Type: String -- VT_LPWSTR
|
||||||
|
// FormatID: {9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}, 20
|
||||||
|
static const PROPERTYKEY PKEY_AppUserModel_ActivationContext = { {0x9F4C2855, 0x9F79, 0x4B39, {0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3}}, 20 };
|
||||||
|
|
||||||
CComQIPtr<IContextMenu> pMenu(item.pItem);
|
CComQIPtr<IContextMenu> pMenu(item.pItem);
|
||||||
if (!pMenu) return false;
|
CStringA params;
|
||||||
|
|
||||||
|
CComQIPtr<IShellLink> pLink(item.pItem);
|
||||||
|
if (pLink)
|
||||||
|
{
|
||||||
|
CComQIPtr<IPropertyStore> store(pLink);
|
||||||
|
if (store)
|
||||||
|
{
|
||||||
|
auto appId = GetPropertyStoreString(store, PKEY_AppUserModel_ID);
|
||||||
|
if (!appId.IsEmpty())
|
||||||
|
{
|
||||||
|
CComPtr<IShellItem2> target;
|
||||||
|
if (SUCCEEDED(SHCreateItemInKnownFolder(FOLDERID_AppsFolder, 0, appId, IID_PPV_ARGS(&target))))
|
||||||
|
{
|
||||||
|
ULONG modern = 0;
|
||||||
|
if (SUCCEEDED(target->GetUInt32(PKEY_AppUserModel_HostEnvironment, &modern)) && modern)
|
||||||
|
{
|
||||||
|
CComQIPtr<IContextMenu> targetMenu;
|
||||||
|
if (SUCCEEDED(target->BindToHandler(nullptr, BHID_SFUIObject, IID_PPV_ARGS(&targetMenu))))
|
||||||
|
{
|
||||||
|
pMenu = targetMenu;
|
||||||
|
params = CT2CA(GetPropertyStoreString(store, PKEY_AppUserModel_ActivationContext));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke the link through its context menu
|
||||||
|
if (!pMenu)
|
||||||
|
return false;
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
HMENU menu=CreatePopupMenu();
|
HMENU menu=CreatePopupMenu();
|
||||||
hr=pMenu->QueryContextMenu(menu,0,1,1000,CMF_DEFAULTONLY);
|
hr=pMenu->QueryContextMenu(menu,0,1,1000,CMF_DEFAULTONLY);
|
||||||
@@ -633,6 +601,8 @@ bool ExecuteJumpItem( const CItemManager::ItemInfo *pAppInfo, const CJumpItem &i
|
|||||||
{
|
{
|
||||||
CMINVOKECOMMANDINFO command={sizeof(command),CMIC_MASK_FLAG_LOG_USAGE};
|
CMINVOKECOMMANDINFO command={sizeof(command),CMIC_MASK_FLAG_LOG_USAGE};
|
||||||
command.lpVerb=MAKEINTRESOURCEA(id-1);
|
command.lpVerb=MAKEINTRESOURCEA(id-1);
|
||||||
|
if (!params.IsEmpty())
|
||||||
|
command.lpParameters = params;
|
||||||
wchar_t path[_MAX_PATH];
|
wchar_t path[_MAX_PATH];
|
||||||
GetModuleFileName(NULL,path,_countof(path));
|
GetModuleFileName(NULL,path,_countof(path));
|
||||||
if (_wcsicmp(PathFindFileName(path),L"explorer.exe")==0)
|
if (_wcsicmp(PathFindFileName(path),L"explorer.exe")==0)
|
||||||
|
|||||||
@@ -2203,10 +2203,7 @@ void CMenuContainer::AddJumpListItems( std::vector<MenuItem> &items )
|
|||||||
if (pLink)
|
if (pLink)
|
||||||
{
|
{
|
||||||
pLink->GetIDList(&item.pItem1);
|
pLink->GetIDList(&item.pItem1);
|
||||||
wchar_t location[_MAX_PATH];
|
item.pItemInfo = g_ItemManager.GetLinkIcon(pLink, CItemManager::ICON_SIZE_TYPE_SMALL);
|
||||||
int index;
|
|
||||||
if (pLink->GetIconLocation(location,_countof(location),&index)==S_OK && location[0])
|
|
||||||
item.pItemInfo=g_ItemManager.GetCustomIcon(location,index,CItemManager::ICON_SIZE_TYPE_SMALL,(index==0)); // assuming that if index!=0 the icon comes from a permanent location like a dll or exe
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (jumpItem.type==CJumpItem::TYPE_ITEM)
|
else if (jumpItem.type==CJumpItem::TYPE_ITEM)
|
||||||
@@ -6668,8 +6665,7 @@ bool CMenuContainer::GetDescription( int index, wchar_t *text, int size )
|
|||||||
{
|
{
|
||||||
if (SUCCEEDED(pLink->GetDescription(text,size)) && text[0])
|
if (SUCCEEDED(pLink->GetDescription(text,size)) && text[0])
|
||||||
return true;
|
return true;
|
||||||
wchar_t args[256];
|
if (jumpItem.bHasArguments)
|
||||||
if (SUCCEEDED(pLink->GetArguments(args,_countof(args))) && args[0])
|
|
||||||
{
|
{
|
||||||
// don't use default tip for items with arguments
|
// don't use default tip for items with arguments
|
||||||
Strcpy(text,size,item.name);
|
Strcpy(text,size,item.name);
|
||||||
|
|||||||
Reference in New Issue
Block a user