#include
#include
#include
#include
#include
#include "helpers.h"
extern "C" {
PyObject *
shortcut_create(PyObject *, PyObject *args, PyObject *kwargs)
{
static const char *keywords[] = {
"path", "target", "arguments", "working_directory",
"icon", "icon_index",
NULL
};
wchar_t *path = NULL;
wchar_t *target = NULL;
wchar_t *arguments = NULL;
wchar_t *workingDirectory = NULL;
wchar_t *iconPath = NULL;
int iconIndex = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"O&O&|O&O&O&i:shortcut_create", keywords,
as_utf16, &path, as_utf16, &target, as_utf16, &arguments, as_utf16, &workingDirectory,
as_utf16, &iconPath, &iconIndex)) {
return NULL;
}
PyObject *r = NULL;
IShellLinkW *lnk = NULL;
IPersistFile *persist = NULL;
HRESULT hr;
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLinkW, (void **)&lnk);
if (FAILED(hr)) {
err_SetFromWindowsErrWithMessage(hr, "Creating system shortcut");
goto done;
}
if (FAILED(hr = lnk->SetPath(target))) {
err_SetFromWindowsErrWithMessage(hr, "Setting shortcut target");
goto done;
}
if (arguments && *arguments && FAILED(hr = lnk->SetArguments(arguments))) {
err_SetFromWindowsErrWithMessage(hr, "Setting shortcut arguments");
goto done;
}
if (workingDirectory && *workingDirectory && FAILED(hr = lnk->SetWorkingDirectory(workingDirectory))) {
err_SetFromWindowsErrWithMessage(hr, "Setting shortcut working directory");
goto done;
}
if (iconPath && *iconPath && FAILED(hr = lnk->SetIconLocation(iconPath, iconIndex))) {
err_SetFromWindowsErrWithMessage(hr, "Setting shortcut icon");
goto done;
}
if (FAILED(hr = lnk->QueryInterface(&persist))) {
err_SetFromWindowsErrWithMessage(hr, "Getting persist interface");
goto done;
}
// gh-15: Apparently ERROR_USER_MAPPED_FILE can occur here, which suggests
// contention on the file. We should be able to sleep and retry to handle it
// in most cases.
for (int retries = 5; retries; --retries) {
if (SUCCEEDED(hr = persist->Save(path, 0))) {
break;
}
if (retries == 1 || hr != HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE)) {
err_SetFromWindowsErrWithMessage(hr, "Writing shortcut");
goto done;
}
Sleep(10);
}
r = Py_NewRef(Py_None);
done:
if (persist) {
persist->Release();
}
if (lnk) {
lnk->Release();
}
if (path) PyMem_Free(path);
if (target) PyMem_Free(target);
if (arguments) PyMem_Free(arguments);
if (workingDirectory) PyMem_Free(workingDirectory);
if (iconPath) PyMem_Free(iconPath);
return r;
}
PyObject *
shortcut_get_start_programs(PyObject *, PyObject *, PyObject *)
{
wchar_t *path;
HRESULT hr = SHGetKnownFolderPath(
FOLDERID_Programs,
KF_FLAG_NO_PACKAGE_REDIRECTION | KF_FLAG_CREATE,
NULL,
&path
);
if (FAILED(hr)) {
err_SetFromWindowsErrWithMessage(hr, "Obtaining Start Menu location");
return NULL;
}
PyObject *r = PyUnicode_FromWideChar(path, -1);
CoTaskMemFree(path);
return r;
}
PyObject *
shortcut_default_cwd(PyObject *, PyObject *, PyObject *)
{
static const KNOWNFOLDERID fids[] = { FOLDERID_Documents, FOLDERID_Profile };
for (auto i = std::begin(fids); i != std::end(fids); ++i) {
wchar_t *path;
if (SUCCEEDED(SHGetKnownFolderPath(
*i,
KF_FLAG_NO_PACKAGE_REDIRECTION,
NULL,
&path
))) {
PyObject *r = PyUnicode_FromWideChar(path, -1);
CoTaskMemFree(path);
return r;
}
}
return Py_GetConstant(Py_CONSTANT_NONE);
}
PyObject *
hide_file(PyObject *, PyObject *args, PyObject *kwargs)
{
static const char *keywords[] = {"path", "hidden", NULL};
wchar_t *path;
int hidden = 1;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|b:hide_file", keywords, as_utf16, &path, &hidden)) {
return NULL;
}
PyObject *r = NULL;
DWORD attr = GetFileAttributesW(path);
if (attr == INVALID_FILE_ATTRIBUTES) {
err_SetFromWindowsErrWithMessage(GetLastError(), "Reading file attributes");
goto done;
}
if (hidden) {
attr |= FILE_ATTRIBUTE_HIDDEN;
} else {
attr &= ~FILE_ATTRIBUTE_HIDDEN;
}
if (!SetFileAttributesW(path, attr)) {
err_SetFromWindowsErrWithMessage(GetLastError(), "Setting file attributes");
goto done;
}
r = Py_NewRef(Py_None);
done:
PyMem_Free(path);
return r;
}
}