InternetShortcut 对象 IPersistFile::Save 失败 E_FAIL (0x80004005)
InternetShortcut object IPersistFile::Save fails with E_FAIL (0x80004005)
这个让我卡了太久,所以我自己回答这个问题。为讽刺的语气道歉!
尝试使用官方 API 创建 .url 文件只有 the following documentation:
- Create an instance of the Internet shortcut object with CoCreateInstance, using a CLSID of CLSID_InternetShortcut.
- Use the IUniformResourceLocator::SetURL method to set the URL in the shortcut.
- Use the IPersistFile::Save method to save the shortcut file to a desired location.
好的,看起来应该是这样的(我的实际代码是生锈的,抱歉缺乏测试):
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://whosebug.com", 0);
现在进行第三步:
IPersistFile* file = nullptr;
url->QueryInterface(IID_IPersistFile, (void**)&file);
file->Save(L"best-site.url", FALSE);
咦,Save()
回来了 E_FAIL?真奇怪,我使用完全相同的代码将 ShellLink 对象保存到 .lnk 文件?
答案实际上很简单: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://whosebug.com", L"best-site.url");
}
这个让我卡了太久,所以我自己回答这个问题。为讽刺的语气道歉!
尝试使用官方 API 创建 .url 文件只有 the following documentation:
- Create an instance of the Internet shortcut object with CoCreateInstance, using a CLSID of CLSID_InternetShortcut.
- Use the IUniformResourceLocator::SetURL method to set the URL in the shortcut.
- Use the IPersistFile::Save method to save the shortcut file to a desired location.
好的,看起来应该是这样的(我的实际代码是生锈的,抱歉缺乏测试):
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://whosebug.com", 0);
现在进行第三步:
IPersistFile* file = nullptr;
url->QueryInterface(IID_IPersistFile, (void**)&file);
file->Save(L"best-site.url", FALSE);
咦,Save()
回来了 E_FAIL?真奇怪,我使用完全相同的代码将 ShellLink 对象保存到 .lnk 文件?
答案实际上很简单: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://whosebug.com", L"best-site.url");
}