Skip to content

Commit

Permalink
Add app id management and create shortcut
Browse files Browse the repository at this point in the history
  • Loading branch information
MHendricks committed Aug 5, 2022
1 parent ab3e35e commit f539d39
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 10 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

A Python library that provides useful functionality for managing Microsoft Windows systems.

## Features

* App Model Id management for shortcuts and inside python applications to allow for taskbar grouping.
* Finding, creating and moving shortcuts.
* Pinning shortcuts to the taskbar and start menu.
* Flashing a window to get a users attention.

## Shortcut management

Expand Down Expand Up @@ -36,3 +42,9 @@ Pinning/unpinning a shortcut to the taskbar:
C:\blur\dev\casement>casement shortcut pin "C:\Users\Public\Desktop\My Shortcut.lnk" -t
C:\blur\dev\casement>casement shortcut unpin "C:\Users\Public\Desktop\My Shortcut.lnk" -t
```

# Installing

Casement can be installed by the standard pip command `pip install casement`.
There is also an optional extras_require option `pip install casement[pil]` to
allow creating shortcut icons by converting image files to .ico files.
87 changes: 87 additions & 0 deletions casement/app_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import ctypes
import os
import pythoncom
from ctypes import wintypes
from win32com.propsys import propsys
from win32com.shell import shellcon


class AppId(object):
@staticmethod
def for_shortcut(shortcut):
"""Gets the AppUserModel.ID for the given shortcut.
This will allow windows to group windows with the same app id on a shortcut
pinned to the taskbar. Use :py:meth:`AppId.for_application` to set the
app id for a running application.
"""
if os.path.exists(shortcut):
# These imports won't work inside python 2 DCC's
from win32com.propsys import propsys

# Original info from https://stackoverflow.com/a/61714895
key = propsys.PSGetPropertyKeyFromName("System.AppUserModel.ID")
store = propsys.SHGetPropertyStoreFromParsingName(shortcut)
return store.GetValue(key).GetValue()

@staticmethod
def set_for_shortcut(shortcut, app_id):
"""Sets AppUserModel.ID info for a windows shortcut.
Note: This doesn't seem to work on a pinned taskbar shortcut. Set it on
a desktop shortcut then pin that shortcut.
This will allow windows to group windows with the same app id on a shortcut
pinned to the taskbar. Use :py:meth:`AppId.set_for_application` to set
the app id for a running application.
Args:
shortcut (str): The .lnk filename to set the app id on.
app_id (str): The app id to set on the shortcut
"""
if os.path.exists(shortcut):
# Original info from https://stackoverflow.com/a/61714895
key = propsys.PSGetPropertyKeyFromName("System.AppUserModel.ID")
store = propsys.SHGetPropertyStoreFromParsingName(
shortcut, None, shellcon.GPS_READWRITE, propsys.IID_IPropertyStore
)

new_value = propsys.PROPVARIANTType(app_id, pythoncom.VT_BSTR)
store.SetValue(key, new_value)
store.Commit()

@staticmethod
def for_application():
"""Returns the current Windows 7+ app user model id used for taskbar
grouping."""

lp_buffer = wintypes.LPWSTR()
app_user_model_id = (
ctypes.windll.shell32.GetCurrentProcessExplicitAppUserModelID
)
app_user_model_id(ctypes.cast(ctypes.byref(lp_buffer), wintypes.LPWSTR))
appid = lp_buffer.value
ctypes.windll.kernel32.LocalFree(lp_buffer)
return appid

@staticmethod
def set_for_application(appid, prefix=None):
"""Controls Windows taskbar grouping.
Specifies a Explicit App User Model ID that Windows 7+ uses to control
grouping of windows on the taskbar. This must be set before any ui is
displayed. The best place to call it is in the first widget to be displayed
__init__ method.
See :py:meth:`AppId.set_for_shortcut` to set the app id on a windows shortcut.
Args:
appid (str): The id of the application. Should use full camel-case.
http://msdn.microsoft.com/en-us/library/dd378459%28v=vs.85%29.aspx#how
prefix (str, optional): The prefix attached to the id.
"""

# https://stackoverflow.com/a/27872625
if prefix:
appid = u'%s.%s' % (prefix, appid)
return not ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
Loading

0 comments on commit f539d39

Please sign in to comment.