Невозможно создать ярлык из dll в c ++ (ссылка на оболочку)

Я использую расширение пространства имен оболочки для создания виртуальной папки в разделе «Мой компьютер».

Теперь мне нужно создать ярлык для него программно в C ++.
На основании ответа от Создание ярлыка для нефайлового объекта и из Как создать ярлык для виртуальной папки в C ++ на Windows 7?, Я создаю отдельный проект EXE для создания ярлыка для моей виртуальной папки, и он работает.

Однако, когда я копирую тот же код в свою DLL и вызываю эту функцию DLL из другого проекта MFC, созданный «ярлык» не является настоящим ярлыком.

Пожалуйста, смотрите следующий код и фотографии:

В индивидуальном проекте EXE:

HRESULT CreateComputerChildShortCut(LPWSTR childDisplayName, LPWSTR path)
{
// get My Computer folder's ShellItem
CComPtr<IShellItem> folder;
HRESULT hr = SHCreateItemInKnownFolder(FOLDERID_ComputerFolder, 0, NULL, IID_PPV_ARGS(&folder));
if (FAILED(hr)) return hr;

// enumerate children
CComPtr<IEnumShellItems> items;
hr = folder->BindToHandler(NULL, BHID_EnumItems, IID_PPV_ARGS(&items));
if (FAILED(hr)) return hr;

for (CComPtr<IShellItem> item; items->Next(1, &item, NULL) == S_OK; item.Release())
{
// get display name
CComHeapPtr<wchar_t> displayName;
item->GetDisplayName(SIGDN_NORMALDISPLAY, &displayName);

if (!lstrcmpi(childDisplayName, displayName))
{
HRESULT hres;
IShellLink* psl;

// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
CComHeapPtr<ITEMIDLIST> pidl;
hr = SHGetIDListFromObject(item, &pidl);
if (FAILED(hr)) return hr;

IPersistFile* ppf;

psl->SetIDList(pidl);

// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);

if (SUCCEEDED(hres))
{
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(path, FALSE);
ppf->Release();
}
psl->Release();

break;
}
}
}
return S_OK;
}

int main()
{
CoInitialize(NULL);
// I've used my Apple's iCloud as an example
// it's a virtual folder, a shell namespace extension
LPWSTR szFolderPath = new TCHAR[MAX_PATH];

SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PROFILE, FALSE);

std::wstring temp(szFolderPath);

std::wstring links = L"\\Links\\MyShortcut-fromExe";

temp += links;

LPWSTR path = (LPWSTR)temp.c_str();

HRESULT hr = CreateComputerChildShortCut(L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{5B952D69-65F5-42cf-ABF3-0AF269C5EC5F}", path);
//the first GUID means "My Computer", the second is my virtual folder's GUID

//SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN);

printf("hr:0x%08X\n", hr);
CoUninitialize();
return 0;
}

После того, как я его запустил, он отлично создает ярлык:

образ

Как видите, ярлык, созданный из EXE-файла, также может отображаться слева от папки, и его свойства открываются нормально:

образ

Однако, когда я запускаю тот же код из DLL, вызванной из моего проекта MFC, созданный код не является обычным ярлыком.

образ

Он не отображается слева автоматически, как в EXE, и его свойства выглядят странно. Когда я дважды щелкаю «ярлык», то он добавляется слева.

Ниже приведен код в DLL:

CoInitialize(NULL);

LPWSTR szFolderPath = new TCHAR[MAX_PATH];

SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PROFILE, FALSE);

std::wstring temp(szFolderPath);

std::wstring links = L"\\Links\\MyShortcut-fromDll";

temp += links;

LPWSTR path = (LPWSTR)temp.c_str();
// the value of VirtualFolderTitle is "VirtualFolder"HRESULT hr = CreateShortCut((LPWSTR)VirtualFolderTitle.c_str(), path);

if (hr != S_OK)
{
LOG_ERROR(L"cannot create short cut for Thermo Fisher Cloud", 0);
}

CoUninitialize();

а также

HRESULT CreateShortCut(LPWSTR childDisplayName, LPWSTR path)
{
// get My Computer folder's ShellItem
CComPtr<IShellItem> folder;
HRESULT hr = SHCreateItemInKnownFolder(FOLDERID_ComputerFolder, 0, NULL, IID_PPV_ARGS(&folder));
if (FAILED(hr)) return hr;

// enumerate children
CComPtr<IEnumShellItems> items;
hr = folder->BindToHandler(NULL, BHID_EnumItems, IID_PPV_ARGS(&items));
if (FAILED(hr)) return hr;

for (CComPtr<IShellItem> item; items->Next(1, &item, NULL) == S_OK; item.Release())
{
// get display name
CComHeapPtr<wchar_t> displayName;
item->GetDisplayName(SIGDN_NORMALDISPLAY, &displayName);

if (!lstrcmpi(childDisplayName, displayName))
{
HRESULT hres;
IShellLink* psl;

// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
CComHeapPtr<ITEMIDLIST> pidl;
hr = SHGetIDListFromObject(item, &pidl);
if (FAILED(hr)) return hr;

IPersistFile* ppf;

psl->SetIDList(pidl);

// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);

if (SUCCEEDED(hres))
{
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(path, FALSE);
ppf->Release();
}
psl->Release();

break;
}
}
}
return S_OK;
}

Я пытался отладить его самостоятельно, но единственное различие, которое я обнаружил между ними, это когда они item->GetDisplayName(SIGDN_NORMALDISPLAY, &displayName);, проект EXE получит строку ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{5B952D69-65F5-42cf-ABF3-0AF269C5EC5F}, но DLL получит строку VirtualFolder вместо.

Это действительно странно. Таким образом, единственное различие между кодом EXE и DLL в том, что в коде EXE мне нужно передать GUID, но для DLL мне нужно передать имя виртуальной папки.

Я также пытался использовать точно такой же код из Как создать ярлык для виртуальной папки в C ++ на Windows 7?, но проект DLL по-прежнему создает другой «ярлык», чем EXE.

Кто-нибудь знает, как это исправить? Как я могу создать нормальный ярлык из DLL и вызываться проектом MFC?

Примечание. Оба «ярлыка» могут направить пользователя в нужную виртуальную папку.

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]