chromium/chrome/installer/tools/shortcut_properties.py

#!/usr/bin/env vpython3
# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Dumps a Windows shortcut's property bag to stdout.

This is required to confirm correctness of properties that aren't readily
available in Windows UI.

If you run into "ImportError: No module named pywintypes":
Run this script with vpython3 instead.
"""

import optparse
from pywintypes import IID
import sys
from win32com.propsys import propsys
from win32com.propsys import pscon


def BuildPKeyToNameMapping():
  """Returns a dict mapping PKey values (a tuple of an IID and an int) to their
  names."""
  # The pscon module contains a number of well-known PKey values. Scan through
  # the module picking out anything that looks plausibly like a PROPERTYKEY (a
  # tuple of a PyIID and an int), and map it to its name in the module.
  return {item: name for (name, item) in pscon.__dict__.items() if (
             isinstance(item, tuple) and
             len(item) == 2 and
             isinstance(item[1], int))}


def PrintShortcutProperties(shortcut_path, dump_all):
  properties = propsys.SHGetPropertyStoreFromParsingName(shortcut_path)

  print('Known properties (--dump-all for more):')

  app_id = properties.GetValue(pscon.PKEY_AppUserModel_ID).GetValue()
  print('\tAppUserModelId => "%s"' % app_id)

  # Hard code PKEY_AppUserModel_IsDualMode as pscon doesn't support it.
  PKEY_AppUserModel_IsDualMode = (IID('{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}'),
                                  11)
  dual_mode = properties.GetValue(PKEY_AppUserModel_IsDualMode).GetValue()
  print('\tDual Mode => "%s"' % dual_mode)

  # Dump all other properties with their raw ID if requested, add them above
  # over time as we explicitly care about more properties, see propkey.h or
  # pscon.py for a reference of existing PKEYs' meaning.
  if dump_all:
    key_to_name = BuildPKeyToNameMapping()
    print('\nOther properties:')
    for i in range(0, properties.GetCount()):
      property_key = properties.GetAt(i)
      # |property_key| is a tuple of an IID identifying the format and an int
      # (a.k.a. a PROPERTYKEY struct). If this key is one of the predefined ones
      # in the pscon module, display the name given to it by the module. If not,
      # show the key's IID and int -- the viewer may be able to find it in
      # propkey.h.
      key_name = key_to_name.get(property_key, str(property_key))
      property_value = properties.GetValue(property_key).GetValue()
      print('\t%s => "%s"' % (key_name, property_value))


def main():
  usage = 'usage: %prog [options] "C:\\Path\\To\\My Shortcut.lnk"'
  parser = optparse.OptionParser(usage,
                                 description="Dumps a shortcut's  properties.")
  parser.add_option('-a', '--dump-all', action='store_true', dest='dump_all',
                    default=False)
  options, args = parser.parse_args()

  if len(args) != 1:
    parser.error('incorrect number of arguments')

  PrintShortcutProperties(args[0], options.dump_all)


if __name__ == '__main__':
  sys.exit(main())