【问题标题】:InternetShortcut object IPersistFile::Save fails with E_FAIL (0x80004005)InternetShortcut 对象 IPersistFile::Save 失败并显示 E_FAIL (0x80004005)
【发布时间】:2020-09-04 22:55:34
【问题描述】:

这个问题让我卡了太久,所以我自己回答这个问题。为讽刺的语气道歉!

尝试使用官方API创建.url文件只有the following documentation:

  • 使用 CoCreateInstance 创建 Internet 快捷方式对象的实例,并使用 CLSID_InternetShortcut 的 CLSID。
  • 使用 IUniformResourceLocator::SetURL 方法设置快捷方式中的 URL。
  • 使用 IPersistFile::Save 方法将快捷方式文件保存到所需位置。

好的,应该看起来像这样(我的实际代码是生锈的,抱歉缺乏测试):

CoInitializeEx(nullptr, 0);

IUniformResourceLocator* url = nullptr;
CoCreateInstance(
  CLSID_InternetShortcut,
  nullptr,
  CLSCTX_INPROC,
  IID_IUniformResourceLocator,
  (void**)&url,
);

哦,E_NOINTERFACE 失败了?好吧,还没有太多代码,所以不难猜到你必须用 STA 来初始化,而不是默认的 MTA:

CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);

这是第一步,第二步是这样的:

url->SetURL(L"https://stackoverflow.com", 0);

现在进行第三步:

IPersistFile* file = nullptr;
url->QueryInterface(IID_IPersistFile, (void**)&file);
file->Save(L"best-site.url", FALSE);

嗯,Save() 正在返回 E_FAIL?这很奇怪,我使用完全相同的代码将 ShellLink 对象保存到 .lnk 文件?

【问题讨论】:

  • “不难猜到你必须用 STA 来初始化,而不是默认的 MTA”——听起来像是 Raymond Chen 写博客解释原因的工作IUniformResourceLocator 在 MTA 中不起作用;-) 不过,this port 总结道:“我的猜测是,InternetShortcut 被标记为单元线程对象,并且 IUniformResourceLocator 接口不可编组。 i>"
  • 我猜测为什么它被标记为单元线程是 IURL 有一个带有 HWND 参数的调用方法,因此可能有时会显示 UI(浏览器选择?)。如果您只想设置 URL,这很烦人,也许您可​​以在 MTA 中获取IPropertySetStore?值得测试。

标签: windows winapi com


【解决方案1】:

答案实际上很简单:InternetShortcut 不管出于何种原因,与ShellLink 不同,可能其他shell 对象要求Save() 的路径是绝对的。 (而且只有Save()、Load() 对相对路径非常满意)

所以,使用WIL 的完整工作代码:

#include <windows.h>
#include <IntShCut.h>
#include <wil/com.h>

void save_link(LPCWSTR url_value, LPCWSTR path) {
    auto url = wil::CoCreateInstance<IUniformResourceLocator>(CLSID_InternetShortcut, CLSCTX_INPROC);
    THROW_IF_FAILED(url->SetURL(url_value, 0));
    auto file = url.query<IPersistFile>();
    WCHAR full_path[MAX_PATH];
    GetFullPathName(path, ARRAYSIZE(full_path), full_path, nullptr);
    THROW_IF_FAILED(file->Save(full_path, FALSE));
}

int main() {
    THROW_IF_FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
    save_link(L"https://stackoverflow.com", L"best-site.url");
}

【讨论】:

  • 公平地说,IPersistFile::Save 的文档确实声明提供的路径应该是绝对的。 IShellLink 是接受它的怪人。
猜你喜欢
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 2014-04-23
相关资源
最近更新 更多