你可以通过调用IShellItem::BindToHandler()
并通过BHID_SFUIObject
为rbhid
参数获得直接从IShellItem
的IShellLink
。然后,请拨打IShellLink::GetIDList()
以获取目前解决方案中已经完成的链接目标。
在我的Windows 10测试中,它独立于IsShortcut
注册表项的存在。
例子:
#include <ShlObj.h> // Shell API
#include <atlcomcli.h> // CComPtr
#include <atlbase.h> // CComHeapPtr
#include <iostream>
#include <system_error>
// Throw a std::system_error if the HRESULT indicates failure.
template< typename T >
void ThrowIfFailed(HRESULT hr, T&& msg)
{
if(FAILED(hr))
throw std::system_error{ hr, std::system_category(), std::forward<T>(msg) };
}
// RAII wrapper to initialize/uninitialize COM
struct CComInit
{
HRESULT hr = ::CoInitialize(nullptr);
CComInit() { ThrowIfFailed(hr, "CoInitialize failed"); }
~CComInit() { ::CoUninitialize(); }
};
int main()
{
try
{
CComInit init;
// Create a shell item from a file for testing purposes.
CComPtr<IShellItem> pItem;
ThrowIfFailed(
SHCreateItemFromParsingName(L"C:\\test.lnk", nullptr, IID_PPV_ARGS(&pItem)),
"Could not create shell item from path");
// Obtain a link object from the shell item.
CComPtr<IShellLink> pLink;
ThrowIfFailed(
pItem->BindToHandler(nullptr, BHID_SFUIObject, IID_PPV_ARGS(&pLink)),
"Could not obtain IShellLink");
// Get the link target as PIDL.
CComHeapPtr<ITEMIDLIST> pidlTarget;
ThrowIfFailed(
pLink->GetIDList(&pidlTarget),
"Could not get link target as PIDL");
// Create a shell item from the link target PIDL...
CComPtr<IShellItem> pItemTarget;
ThrowIfFailed(
SHCreateShellItem(nullptr, nullptr, pidlTarget, &pItemTarget),
"Could not create shell item for link target");
//... to obtain the display name (we may use SIGDN_FILESYSPATH to obtain a
// path only if we know the target is a filesystem item).
CComHeapPtr<wchar_t> pDisplayName;
ThrowIfFailed(
pItemTarget->GetDisplayName(SIGDN_DESKTOPABSOLUTEEDITING, &pDisplayName),
"Could not get display name of link target");
std::wcout << L"Link target (display name): " << pDisplayName.m_pData << '\n';
return 0;
}
catch(std::system_error const& e)
{
std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
return 1;
}
}
注:
- 代码使用ATL COM智能指针异常安全,干净的代码。
CComPtr
用于管理COM对象(当对象超出作用域时,其析构函数自动调用Release()
方法)。 CComHeapPtr
用于管理由shell分配的“原始内存”(其析构函数自动调用::CoTaskMemFree()
)。
继续为用户创建的混乱提供解决方法的路径只会导致黑暗的一面;-)。相反,你应该告诉他们隐藏快捷箭头的正确方法是[用一个透明图标代替它](http://www.theeldergeek.com/windows_7/shortcut_remove_arrow_overlay.htm)。我认为这仍然适用于Win 10。甚至有免费工具可以做到这一点,而无需手动篡改注册表。 – zett42
@ zett42好点,但我不是在寻找“黑客”或解决方法,只是解决问题的另一种方法。也能够直接从* IShellItem *获得* IShellLink *将会很有用。 – IllidanS4
够公平的。 [Raymond Chen通过'IShellFolder :: GetUIObjectOf()')(https://blogs.msdn.microsoft.com/oldnewthing/20100702-00/?p=13523/),在结果中获得一个'IShellLink'。当你从一个'IShellItem'开始时,你可以用'BHID_SFUIObject'来合理地调用'IShellItem :: BindToHandler()'来获得'IShellLink'。我不知道这是否也取决于'IsShortcut'注册表项,但它可能值得一试。 – zett42