Skip to content

Commit

Permalink
Add support for Python 3.12 (#164)
Browse files Browse the repository at this point in the history
* update CI matrix

* install conda with --only-deps for now

* state conda deps explicitly instead

* use PyObject + PyUnicode_AsWideCharString

* use str() explicitly

* pass default values?

* allow optional values again

* better cleanup

* these cannot be NULL

* amend docstring

* guard these frees

* more like this part

* add tmate

* remove Py_DECREF calls for now

* remove tmate

* update changelog with 1.4.20 details

* revert to regular conda dep

* revert win32

* add news
  • Loading branch information
jaimergp authored Dec 11, 2023
1 parent a83d5ea commit 0530802
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 20 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ jobs:
fail-fast: false
matrix:
os: [windows, ubuntu, macos]
python-version: ["3.8", "3.9", "3.10"] # "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
exclude:
- os: macos
python-version: "3.11"
- os: macos
python-version: "3.10"
- os: macos
python-version: "3.9"

steps:
- uses: actions/checkout@v3
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
* @dbast made their first contribution in https://github.com/conda/menuinst/pull/116
* @aganders3 made their first contribution in https://github.com/conda/menuinst/pull/119

## 1.4.20 (2023-10-30)

* Add support for Python 3.12 (#165)

## 1.4.19 (2022-08-17)

Expand Down
19 changes: 19 additions & 0 deletions news/164-py312
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### Enhancements

* Update `winshortcut` C extension to support Python 3.12. (#164)

### Bug fixes

* <news item>

### Deprecations

* <news item>

### Docs

* <news item>

### Other

* <news item>
91 changes: 72 additions & 19 deletions src/winshortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@

static PyObject *CreateShortcut(PyObject *self, PyObject *args)
{
Py_UNICODE *path; /* path and filename */
Py_UNICODE *description;
Py_UNICODE *filename;
PyObject *py_path; /* path and filename */
wchar_t *path = NULL;
PyObject *py_description;
wchar_t *description = NULL;
PyObject *py_filename;
wchar_t *filename = NULL;

Py_UNICODE *arguments = NULL;
Py_UNICODE *iconpath = NULL;
PyObject *py_arguments = NULL;
PyObject *py_iconpath = NULL;
int iconindex = 0;
Py_UNICODE *workdir = NULL;
Py_UNICODE *app_id = NULL;
PyObject *py_workdir = NULL;
PyObject *py_app_id = NULL;

IShellLink *pShellLink = NULL;
IPersistFile *pPersistFile = NULL;
Expand All @@ -56,10 +59,23 @@ static PyObject *CreateShortcut(PyObject *self, PyObject *args)
goto error;
}

if (!PyArg_ParseTuple(args, "uuu|uuuiu",
&path, &description, &filename,
&arguments, &workdir, &iconpath, &iconindex, &app_id)) {
return NULL;
if (!PyArg_ParseTuple(args, "UUU|UUUiU",
&py_path, &py_description, &py_filename,
&py_arguments, &py_workdir, &py_iconpath, &iconindex, &py_app_id)) {
goto error;
}

path = PyUnicode_AsWideCharString(py_path, NULL);
if (path == NULL) {
goto error;
}
description = PyUnicode_AsWideCharString(py_description, NULL);
if (description == NULL) {
goto error;
}
filename = PyUnicode_AsWideCharString(py_filename, NULL);
if (filename == NULL) {
goto error;
}

hres = CoCreateInstance(CLSID_ShellLink, NULL,
Expand Down Expand Up @@ -94,34 +110,56 @@ static PyObject *CreateShortcut(PyObject *self, PyObject *args)
goto error;
}

if (arguments) {
if (py_arguments) {
wchar_t *arguments = PyUnicode_AsWideCharString(py_arguments, NULL);
if (arguments == NULL) {
goto error;
}
hres = pShellLink->SetArguments(arguments);
if (FAILED(hres)) {
PyErr_Format(PyExc_OSError,
"SetArguments() error 0x%x", hres);
PyMem_Free(arguments);
goto error;
}
PyMem_Free(arguments);
}

if (iconpath) {
if (py_iconpath) {
wchar_t *iconpath = PyUnicode_AsWideCharString(py_iconpath, NULL);
if (iconpath == NULL) {
goto error;
}
hres = pShellLink->SetIconLocation(iconpath, iconindex);
if (FAILED(hres)) {
PyErr_Format(PyExc_OSError,
"SetIconLocation() error 0x%x", hres);
PyMem_Free(iconpath);
goto error;
}
PyMem_Free(iconpath);
}

if (workdir) {
if (py_workdir) {
wchar_t *workdir = PyUnicode_AsWideCharString(py_workdir, NULL);
if (workdir == NULL) {
goto error;
}
hres = pShellLink->SetWorkingDirectory(workdir);
if (FAILED(hres)) {
PyErr_Format(PyExc_OSError,
"SetWorkingDirectory() error 0x%x", hres);
goto error;
PyErr_Format(PyExc_OSError,
"SetWorkingDirectory() error 0x%x", hres);
PyMem_Free(workdir);
goto error;
}
PyMem_Free(workdir);
}

if (app_id) {
if (py_app_id) {
wchar_t *app_id = PyUnicode_AsWideCharString(py_app_id, NULL);
if (app_id == NULL) {
goto error;
}
hres = pShellLink->QueryInterface(IID_PPV_ARGS(&pPropertyStore));
if (FAILED(hres)) {
PyErr_Format(PyExc_OSError,
Expand All @@ -134,6 +172,7 @@ static PyObject *CreateShortcut(PyObject *self, PyObject *args)
"InitPropVariantFromString() error 0x%x", hres);
goto error;
}
PyMem_Free(app_id);
pPropertyStore->SetValue(PKEY_AppUserModel_ID, pv);
pPropertyStore->Commit();
PropVariantClear(&pv);
Expand All @@ -159,6 +198,10 @@ static PyObject *CreateShortcut(PyObject *self, PyObject *args)
pPersistFile->Release();
pShellLink->Release();

PyMem_Free(path);
PyMem_Free(description);
PyMem_Free(filename);

CoUninitialize();
Py_RETURN_NONE;

Expand All @@ -173,6 +216,16 @@ static PyObject *CreateShortcut(PyObject *self, PyObject *args)
pPropertyStore->Release();
}

if (path) {
PyMem_Free(path);
}
if (description) {
PyMem_Free(description);
}
if (filename) {
PyMem_Free(filename);
}

CoUninitialize();
return NULL;
}
Expand All @@ -181,7 +234,7 @@ PyMethodDef meth[] = {
{"create_shortcut", CreateShortcut, METH_VARARGS,
"winshortcut.create_shortcut(path, description, filename,\n"
" arguments=u\"\", workdir=None, iconpath=None,\n"
" iconindex=0)\n"
" iconindex=0, app_id=None)\n"
"\n"
" Creates a shortcut ``filename`` (a .lnk file), whose\n"
" target path is ``path``. All the input strings must be\n"
Expand Down

0 comments on commit 0530802

Please sign in to comment.