This one had me stuck for too long, so I'm self answering this. Apologies for the sardonic tone!
Trying to use the official API to create .url files has only 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.
Ok, so that should look something like this (my actual code is rust, sorry for the lack of testing):
CoInitializeEx(nullptr, 0);
IUniformResourceLocator* url = nullptr;
CoCreateInstance(
CLSID_InternetShortcut,
nullptr,
CLSCTX_INPROC,
IID_IUniformResourceLocator,
(void**)&url,
);
Oh this fails with E_NOINTERFACE? Well there's not much code yet, so it's not too hard to guess that you have to init with STA, instead of the default MTA:
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
So that's the first step, the second is just something like:
url->SetURL(L"https://stackoverflow.com", 0);
Now for the third step:
IPersistFile* file = nullptr;
url->QueryInterface(IID_IPersistFile, (void**)&file);
file->Save(L"best-site.url", FALSE);
Huh, Save()
is returning E_FAIL? That's strange, I'm using exactly the same code for saving a ShellLink object to a .lnk file?
The answer is actually quite simple: InternetShortcut
for whatever reason, unlike ShellLink
and presumably other shell objects requires that the path for Save()
is absolute. (And only Save()
, Load()
is quite happy with a relative path)
So, the full working code using 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");
}
User contributions licensed under CC BY-SA 3.0