Giter VIP home page Giter VIP logo

pylnk's Introduction

PyLnk 3

PyPI version shields.io PyPI pyversions PyPI download month

Python library for reading and writing Windows shortcut files (.lnk).
Converted to support python 3.

This library can parse .lnk files and extract all relevant information from them. Parsing a .lnk file yields a LNK object which can be altered and saved again. Moreover, .lnk file can be created from scratch be creating a LNK object, populating it with data and then saving it to a file. As that process requires some knowledge about the internals of .lnk files, some convenience functions are provided.

Limitation: Windows knows lots of different types of shortcuts which all have different formats. This library currently only supports shortcuts to files and folders on the local machine.

CLI

Mainly tool has two basic commands.

Parse existed lnk file

pylnk3 parse [-h] filename [props [props ...]]

positional arguments:
  filename    lnk filename to read
  props       props path to read

optional arguments:
  -h, --help  show this help message and exit

Create new lnk file

usage: pylnk3 create [-h] [--arguments [ARGUMENTS]] [--description [DESCRIPTION]] [--icon [ICON]]
                     [--icon-index [ICON_INDEX]] [--workdir [WORKDIR]] [--mode [{Maximized,Normal,Minimized}]]
                     target name

positional arguments:
  target                target path
  name                  lnk filename to create

optional arguments:
  -h, --help            show this help message and exit
  --arguments [ARGUMENTS], -a [ARGUMENTS]
                        additional arguments
  --description [DESCRIPTION], -d [DESCRIPTION]
                        description
  --icon [ICON], -i [ICON]
                        icon filename
  --icon-index [ICON_INDEX], -ii [ICON_INDEX]
                        icon index
  --workdir [WORKDIR], -w [WORKDIR]
                        working directory
  --mode [{Maximized,Normal,Minimized}], -m [{Maximized,Normal,Minimized}]
                        window mode

Examples

pylnk3 p filename.lnk
pylnk3 c c:\prog.exe shortcut.lnk
pylnk3 c \\192.168.1.1\share\file.doc doc.lnk
pylnk3 create c:\1.txt text.lnk -m Minimized -d "Description"

Changes

0.4.2
changed logic for Lnk.path choose (in case of different paths presents at different structures)
read links with root as GUID of KNOWN_FOLDER
[FIX] disabled padding for writing LinkInfo.local_base_path

0.4.0
added support for network links
reworked CLI (added more options for creating links)
added entry point for call tool just like pylnk3
[FIX] allow build links for non-existed (from this machine) paths
[FIX] correct building links on Linux (now expect Windows-like path)
[FIX] fixed path priority at parsing with both local & remote presents

0.3.0
added support links to UWP apps

0.2.1
released to PyPI

0.2.0
converted to python 3

pylnk's People

Contributors

oxygen-dioxide avatar strayge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pylnk's Issues

Created Links that are Invalid on Windows 10

Trying to create LNK files on Linux (Ubuntu 20.04) with commands like:

pylnk3 c 'C:\windows\notepad.exe' notepad.lnk
pylnk3 c 'C:\windows\system32\cmd.exe' command2.lnk

When I transfer them to a Windows 10 (21H2) host however, they appear to be invalid, and no information is shown in properties:
image

When I don't have any subdirectories it's fine:

pylnk3 c c:\prog.exe shortcut.lnk

The shortcut made with this is valid and shows in properties:
Screenshot from 2022-12-06 15-02-06

How to change path?

I need to change the path of a desktop link, because to the program has been moved. How can I do that? I tried to set the path attribute, but it gives me an error:

link = pylnk3.Lnk(link_path)
link.path = new_path
# AttributeError: can't set attribute 'path'

Pass an arguments if it begins with "--"

Hello,

We can't pass "--" args, like test.lnk --arguments --incognito

Example :

pylnk3.py c "C:\Program Files\Google\Chrome\Application\chrome.exe --incognito" test.lnk --arguments --incognito
usage: pylnk3.py [--help] {p, c, d} ...
pylnk3.py: error: unrecognized arguments: --incognito

Even if we put ""

pylnk3.py c "C:\Program Files\Google\Chrome\Application\chrome.exe" test.lnk -a "--incognito"
usage: pylnk3.py [--help] {p, c, d} ...
pylnk3.py: error: unrecognized arguments: --incognito

Thank you

Generated LNK not working on Windows when using script API

Hello,

I'm using pylnk3 to create a test LNK file that opens cmd.exe to spawn notepad.exe for security research. I'm using it in a script that I'm running on Linux, if that makes a difference.

My code in the script is the following:

from pylnk3 import parse, for_file

...

def make_lnk():
    lnk = for_file(
        target_file = "C:\\Windows\\System32\\cmd.exe",
        lnk_name='tmp.lnk',
        arguments="/c C:\Windows\System32\\notepad.exe",
        description="test",
        work_dir="C:\Windows\System32",
        window_mode="Minimized",
        icon_file="C:\Windows\System32\\notepad.exe",
        icon_index=0,
    )
    print("\n" + str(lnk))

    lnk.save("tmp.lnk")

    # For troubleshooting...
    parse_out = parse("tmp.lnk")

    print('\n' + str(parse_out))

The lnk that this produces does not run on Windows. It looks like the Target attribute is not set in the lnk:

image

Though what's interesting to note is that other properties, like the Comment, Start In, and Window fields look good.

Am I missing something?

For reference, here's the output of the print statements:

Target file:
{ 'archive': False,
  'compressed': False,
  'directory': False,
  'encrypted': False,
  'hidden': False,
  'normal': False,
  'not_content_indexed': False,
  'offline': False,
  'read_only': False,
  'reparse_point': False,
  'reserved1': False,
  'reserved2': False,
  'sparse_file': False,
  'system_file': False,
  'temporary': False}
Creation Time: 2022-08-24 10:55:18.671077
Modification Time: 2022-08-24 10:55:18.671080
Access Time: 2022-08-24 10:55:18.671079
File size: 0
Window mode: Minimized
Hotkey: None
None
<LinkTargetIDList>:
  <RootEntry: MY_COMPUTER>
  <DriveEntry: b'C:'>
  <PathSegmentEntry: Windows>
  <PathSegmentEntry: System32>
  <PathSegmentEntry: cmd.exe>
Description: test
Working Directory: C:\Windows\System32
Commandline Arguments: /c C:\Windows\System32\notepad.exe
Icon: C:\Windows\System32\notepad.exe
Target file:
{ 'archive': False,
  'compressed': False,
  'directory': False,
  'encrypted': False,
  'hidden': False,
  'normal': False,
  'not_content_indexed': False,
  'offline': False,
  'read_only': False,
  'reparse_point': False,
  'reserved1': False,
  'reserved2': False,
  'sparse_file': False,
  'system_file': False,
  'temporary': False}
Creation Time: 2022-08-24 10:55:18
Modification Time: 2022-08-24 10:55:18
Access Time: 2022-08-24 10:55:18
File size: 0
Window mode: Minimized
Hotkey: 
File Location Info: <not specified>
<LinkTargetIDList>:
  <RootEntry: MY_COMPUTER>
  <DriveEntry: b'C:'>
  <PathSegmentEntry: Windows>
  <PathSegmentEntry: System32>
  <PathSegmentEntry: cmd.exe>
Description: test
Working Directory: C:\Windows\System32
Commandline Arguments: /c C:\Windows\System32\notepad.exe
Icon: C:\Windows\System32\notepad.exe
Used Path: C:\Windows\System32\cmd.exe

diacritic characters does truncated

As noted here: https://stackoverflow.com/questions/39365489/how-do-you-keep-diacritics-in-shortcut-paths

The WScript.Shell implementation does not support diacritic characters in an Unicode string in case of TargetPath shortcut property. But this module has the same issue:

c:\1.txt.lnk -> c:\ööö\1.txt

>pylnk p c:\1.txt.lnk _link_info._path
c:\ooo\1.txt

But WorkingDirectory property is not affected:

>pylnk p c:\1.txt.lnk _work_dir
c:\ööö

I've compared with https://github.com/Matmaus/LnkParse3 implementation and it returns more reliable results:

>lnkparse c:\1.txt.lnk
...

   LINK INFO:
      Link info flags: 1
      Local base path: C:\ooo\1.txt
      Common path suffix:
      Local base unicode: C:\ööö\1.txt
      Common path suffix unicode: .\ööö\1.txt6C:\ööödz
...

   DATA
      Relative path: .\ööö\1.txt
      Working directory: C:\ööö

When pylnk3 is not:

>pylnk3 p c:\1.txt.lnk _link_info.local_base_path
C:\ooo\1.txt

I've tried to change the code:

#DEFAULT_CHARSET = 'cp1251'
DEFAULT_CHARSET = 'utf-8'

But it still returns a truncated variant. Seems the app does read only one property field (Ansi) instead of 2 (Ansi+Unicode) as LnkParse3 does.

Support subdirectories

Currently it's possible to make a LNK pointed at C:\program.exe but if I try to point it at C:\temp\program.exe the LNK no longer functions.

issue with Fax Recipient.lnk

One of LNK file under SendTo folder does not contain path in expected location.
I have found it only in Extra Data segment.

>>> lnk4 = pylnk3.Lnk(r'c:\Users\heznik\AppData\Roaming\Microsoft\Windows\SendTo\Fax Recipient.lnk')
>>> lnk4.path
>>> lnk4.link_info.path
>>> lnk4.relative_path
'..\\..\\..\\..\\..\\..\\..\\Windows\\System32\\WFS.exe'
>>> print(lnk4)
Target file:
{ 'archive': True,
  'compressed': False,
  'directory': False,
  'encrypted': False,
  'hidden': False,
  'normal': False,
  'not_content_indexed': False,
  'offline': False,
  'read_only': False,
  'reparse_point': False,
  'reserved1': False,
  'reserved2': False,
  'sparse_file': False,
  'system_file': False,
  'temporary': False}
Creation Time: 2009-07-14 02:36:26.369370
Modification Time: 2009-07-14 03:39:52.134001
Access Time: 2009-07-14 02:36:26.369370
File size: 974336
Window mode: Normal
Hotkey:
File Location Info: <not specified>
Description: @%windir%\system32\FXSRESM.dll,-121
Relative Path: ..\..\..\..\..\..\..\Windows\System32\WFS.exe
Commandline Arguments: /SendTo
Icon: %windir%\system32\WFSR.dll
Used Path: None
PropertyStoreDataBlock
 PropertyStore
  FormatID: {46588AE2-4CBC-4338-BBFC-139326986DCE}
EnvironmentVariableDataBlock
 TargetAnsi: %windir%\system32\WFS.exe
 TargetUnicode: %windir%\system32\WFS.exe
ExtraDataBlock
 signature 0xa0000003
 data: b'X\x00\x00\x00\x00\x00\x00\x00win-tj9qcsjkags\x00\xda\xcbLI\xe8\x98\xc8E\xb8\xca\xf6MFCf\xc7\xac\xe3n\x849p\xde\x11\x9d \x00\x1d\t\xfaZ\x1c\xda\xcbLI\xe8\x98\xc8E\xb8\xca\xf6MFCf\xc7\xac\xe3n\x849p\xde\x11\x9d \x00\x1d\t\xfaZ\x1c'

I was able to bypass it with following code:

            if not lnk.path:
                for bloc in lnk.extra_data.blocks:
                    if type(bloc) is pylnk3.ExtraData_EnvironmentVariableDataBlock:
                        # in my case it contains env var %windir%
                        fo.lnk_target = os.path.expandvars (bloc.target_unicode.replace ('\x00', ''))
            else:
                fo.lnk_target = os.path.expandvars (lnk.path)

Network location Support Missing

Hi

I was trying to output a .lnk file for network locations but could not get it to work. I eventually came across the code comment that said this functionality was still to implement and the reference to ask for it if needed. Any chance of adding it please?

issue with Desktop.lnk

I have found this new issue for homedir/Links/Desktop.lnk, that was created by Windows.

>>> lnk4 = pylnk3.Lnk(r'c:\Users\heznik\Links\Desktop.lnk')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1501, in __init__
    self._parse_lnk_file(f)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1548, in _parse_lnk_file
    self.shell_item_id_list = LinkTargetIDList(lnk.read(shell_item_id_list_size))
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 904, in __init__
    self._interpret(raw)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 907, in _interpret
    if raw[0][0] == 0x1F:
IndexError: list index out of range

I attach file for inspection.
Desktop.lnk.zip

PyLnk3 is incompatible with Python 3.5 (and, as a result, Ubuntu 16.04 LTS)

Currently, I have to keep some code on systems running Ubuntu 16.04 LTS on Python 2, because Ubuntu 16.04 comes with Python 3.5.2, but PyLnk3 uses type annotations that the parser doesn't understand until a more recent version of Python. (3.7, I think, but don't quote me on that)

The result is this:

$ python3
Python 3.5.2 (default, Oct  8 2019, 13:06:37) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pylnk3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.5/dist-packages/pylnk3.py", line 378
    self._flags: Dict[str, bool] = dict([(name, False) for name in flag_names])
               ^
SyntaxError: invalid syntax

The solution is to change to a type comment in those situations

self._flags = dict([(name, False) for name in flag_names])  # type: Dict[str, bool]

rename properly

Hi, there are 2 issues with the current release.
The first one, pypi package (https://files.pythonhosted.org/packages/d0/44/ed8fe42645e44b12f4a1771927c661965a606eb71f4fbc57bdcbd3d7e867/pylnk3-0.2.1.tar.gz) is broken due to missing README.md.

The second one is with the package name. setup.py installs all files into ..../site-packages/pylnk3-0.2.1-py3.6.egg-info, however the main python file is still called "pylnk.py".
Either rename egg file back to pylnk or the main file to "pylnk3.py".

Thank you

Missing tags on github

The repo on github doesn't have any git tags corresponding to pypi releases. Could you consider adding them please? Thanks!

local path issues

Hello,

I have found 2 minor issues. Note that I have found bypasses for them, so they don't block me, but they may be bugs.

  1. I create a LNK to folder on Desktop, by RMB-drag. Then I copied LNK somewhere else, to make sure it will still point to right place. When I read it I get:
lnk = pylnk3.Lnk('c:\\Users\\user\\test_lnk.lnk')			
>>> lnk.path
'New folder'
>>> lnk.relative_path
'.\\New folder'
>>> lnk.link_info.path
'C:\\Users\\user\\Desktop\\New folder'

I would expect lnk.path to be correct, but I had to use lnk.link_info.path instead. After peeking into code, seems related to _shell_item_id_list.

  1. One of my shortcuts on Desktop contains '%MY_COMPUTER%' prefix, I had to remove it manually so the path makes sense. I don't have such env var in my environment.
>>> lnk3.path
'%MY_COMPUTER%\\C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\Resolve.exe'
>>> lnk3.relative_path
'..\\..\\..\\Program Files\\Blackmagic Design\\DaVinci Resolve\\Resolve.exe'
>>> lnk3.link_info.path
>>>

So now I have such bypass:
lnk_target = lnk.link_info.path
if not lnk_target:
lnk_target = lnk.path.replace ('%MY_COMPUTER%\', '')

This package introduced breaking API changes in 0.4.x release?

Hello, it is not an issue but more a question about compatibility between 0.3.0 and 0.4.x.

I have a package that depends on pylnk>=3.0.0,<0.4.0 but the system's pylnk package is 0.4.2 so I want to change the dependency to simply pylnk for the package to avoid this problem but I wonder if there are API changes that may break the app using the latest version of pylnk or if it's backwards compatible.

Regards,
Ed

a way to print all link properties using command line only

The utility can be used to print link attributes:

pylnk3 p link.lnk __dict__
pylnk3 p link.lnk _shell_item_id_list.__dict__

But some inner attributes is not accessible:

pylnk3 p link.lnk _shell_item_id_list.items.__dict__
pylnk3 p link.lnk _shell_item_id_list.items[0]

Is there a way to do it from the command line only?

modify lnk throw This is not a valid drive error

Reproduce steps:

  1. use parse to load a lnk file on desktop
  2. use for_file to modify this lnk, all params from step 1's lnk object but arguments
  3. modify this lnk manually, delete arguments in path which added by step 2
  4. repeat step 1 and 2, then throw This is not a valid drive error

step 1 code:
lnk = parse(lnk_fn)
step2 code:
arguments = 'xxx'
for_file( lnk.path, lnk.file, arguments, lnk.description, lnk.icon, lnk.icon_index, lnk.work_dir, lnk.window_mode )

Parse error `IndexError: list index out of range`

  • Windows 8.1 x64
  • Python x64 3.12.1
  • Branch: json

If try to parse that shortcut file:
https://github.com/andry81/contools/blob/master/Scripts/Tools/ToolAdaptors/lnk/mycomputer.lnk

pylnk p mycomputer.lnk --json

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "c:\Python\x64\312\Scripts\pylnk3.exe\__main__.py", line 7, in <module>
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\cli.py", line 77, in main
    lnk = parse(args.filename)
          ^^^^^^^^^^^^^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\helpers.py", line 42, in parse
    return Lnk(lnk)
           ^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\lnk.py", line 122, in __init__
    self._parse_lnk_file(f)
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\lnk.py", line 168, in _parse_lnk_file
    self.shell_item_id_list = LinkTargetIDList(lnk.read(shell_item_id_list_size))
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\id_list\id_list.py", line 24, in __init__
    self._interpret(raw)
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\id_list\id_list.py", line 33, in _interpret
    if len(raw[1]) == 0x17:
           ~~~^^^
IndexError: list index out of range

Note: This is a legit valid shortcut file has been created with shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D} in the TargetPath property.

issue with Recent LNK files

I got this exception when going to C:\Users\user\AppData\Roaming\Microsoft\Windows\Recent (ie. where windows stores LNK links to recently visited items).

  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1451, in __init__
    self._parse_lnk_file(f)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1498, in _parse_lnk_file
    self.shell_item_id_list = LinkTargetIDList(lnk.read(shell_item_id_list_size))
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 859, in __init__
    self._interpret(raw)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 883, in _interpret
    self.items.append(PathSegmentEntry(item))
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 528, in __init__
    self.modified = read_dos_datetime(buf)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 218, in read_dos_datetime
    return datetime(year, month, day, hour, minute, second)
ValueError: month must be in 1..12

I added some debug prints to pylink3 code and it seems that in my case month is = 15 (full printout: 1997 15 30 0 0 0)
And after I fix it with: month = max(min(month, 12), 1)
I got another error:

  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1452, in __init__
    self._parse_lnk_file(f)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 1499, in _parse_lnk_file
    self.shell_item_id_list = [LinkTargetIDList(lnk.read(shell_item_id_list_size))]
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 860, in __init__
    self._interpret(raw)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 884, in _interpret
    self.items.append(PathSegmentEntry(item))
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 535, in __init__
    extra_size = read_short(buf)
  File "C:\msys64\mingw64\lib\python3.8\site-packages\pylnk3.py", line 156, in read_short
    return unpack('<H', buf.read(2))[0]
struct.error: unpack requires a buffer of 2 bytes

Catching and ignoring that exception (as for my case I read all files in that dir) reveals that there are more LNK files in that dir that also throw it. I suspect some buffer underrun - extra data segment is not present? LNK files must be valid, as it's created by operating system.
Anyway I attached LNK file so you can inspect.

Files:
attached_lnk.zip

Can not read long target path shortcuts

Tested version:

python -m pip install git+https://github.com/strayge/pylnk@dev

If try to create a shortcut with the long path, then it would be created:

>pylnk3 c c:\11111\22222222222222222222222222222222222222222222222222\333333333333333333333333333333333333333333333333333\444444444444444444444444444444444444444444444444444\5555555555555555555555555555555555555555555555555\6666666666666666666666666666666666666666666666666\777777777777777777777777777777777777777777777777777\1.txt 1.lnk

>pylnk3 p 1.lnk
Target file:
{ 'archive': False,
  'compressed': False,
  'directory': False,
  'encrypted': False,
  'hidden': False,
  'normal': False,
  'not_content_indexed': False,
  'offline': False,
  'read_only': False,
  'reparse_point': False,
  'reserved1': False,
  'reserved2': False,
  'sparse_file': False,
  'system_file': False,
  'temporary': False}
Creation Time: 2023-08-13 13:36:03
Modification Time: 2023-08-13 13:36:03
Access Time: 2023-08-13 13:36:03
File size: 0
Window mode: Normal
Hotkey:
File Location Info: <not specified>
<LinkTargetIDList>:
  <RootEntry: MY_COMPUTER>
  <DriveEntry: b'C:'>
  <PathSegmentEntry: 11111>
  <PathSegmentEntry: 22222222222222222222222222222222222222222222222222>
  <PathSegmentEntry: 333333333333333333333333333333333333333333333333333>
  <PathSegmentEntry: 444444444444444444444444444444444444444444444444444>
  <PathSegmentEntry: 5555555555555555555555555555555555555555555555555>
  <PathSegmentEntry: 6666666666666666666666666666666666666666666666666>
  <PathSegmentEntry: 777777777777777777777777777777777777777777777777777>
  <PathSegmentEntry: 1.txt>
Used Path: C:\11111\22222222222222222222222222222222222222222222222222\333333333333333333333333333333333333333333333333333\444444444444444444444444444444444444444444444444444\5555555555555555555555555555555555555555555555555\6666666666666666666666666666666666666666666666666\777777777777777777777777777777777777777777777777777\1.txt

But if try to read it:

>pylnk3 p 1.lnk __dict__
{'file': '1.lnk', 'link_flags': <pylnk3.flags.Flags object at 0x0000000B0A2AA990>, 'file_flags': <pylnk3.flags.Flags object at 0x0000000B0A2AAF10>, 'creation_time': datetime.datetime(2023, 8, 13, 13, 36, 3), 'access_time': datetime.datetime(2023, 8, 13, 13, 36, 3), 'modification_time': datetime.datetime(2023, 8, 13, 13, 36, 3), 'file_size': 0, 'icon_index': 0, '_show_command': 'Normal', 'hot_key': '', '_link_info': <pylnk3.structures.link_info.LinkInfo object at 0x0000000B0A2AACD0>, '_description': None, '_relative_path': None, '_work_dir': None, '_arguments': None, '_icon': None, 'extra_data': <pylnk3.structures.extra_data.ExtraData object at 0x0000000B0A2AAC50>, '_shell_item_id_list': <pylnk3.structures.id_list.id_list.LinkTargetIDList object at 0x0000000B0A2AB250>}

>pylnk3 p 1.lnk _link_info.__dict__
{'size': 0, 'header_size': 28, 'local': 0, 'remote': 0, 'offs_local_volume_table': 0, 'offs_local_base_path': 0, 'offs_network_volume_table': 0, 'offs_base_name': 0, 'drive_type': None, 'drive_serial': None, 'volume_label': None, 'local_base_path': None, 'network_share_name': '', 'base_name': '', '_path': ''}

>pylnk3 p 1.lnk _link_info._path

Split API into a separate module and document

I believe pylnk is intended to be used as a library, but it is a single-file that includes the CLI code. I cannot see any documentation for the API.

I would like to be able to:

  • Create links using an API
  • Read documentation for that API
  • Not pay the cost of importing argparse, which will not be used.

Some context: I would like to use pylnk in a piece of software that is packaged using PyInstaller. Because PyInstaller produces a package with an executable file (myapp.exe), it is much harder to arrange to include a pylnk3 excutable (pylnk3.exe) and to run it, than it is to just import a module and call it.

Parse error `KeyError: 2717908993`

  • Windows 8.1 x64
  • Python x64 3.12.1
  • Branch: json

If try to parse that old shortcut format file:
https://github.com/andry81/contools/blob/master/Scripts/Tools/ToolAdaptors/lnk/cmd.lnk

pylnk p cmd.lnk --json

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "c:\Python\x64\312\Scripts\pylnk3.exe\__main__.py", line 7, in <module>
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\cli.py", line 77, in main
    lnk = parse(args.filename)
          ^^^^^^^^^^^^^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\helpers.py", line 42, in parse
    return Lnk(lnk)
           ^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\lnk.py", line 122, in __init__
    self._parse_lnk_file(f)
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\lnk.py", line 188, in _parse_lnk_file
    self.extra_data = ExtraData(lnk)
                      ^^^^^^^^^^^^^^
  File "c:\Python\x64\312\Lib\site-packages\pylnk3\structures\extra_data.py", line 411, in __init__
    block_type = EXTRA_DATA_TYPES[signature]
                 ~~~~~~~~~~~~~~~~^^^^^^^^^^^
KeyError: 2717908993

Note: This is a legit valid shortcut file has been created with %COMSPEC% in the TargetPath property.

Broken PathSegmentEntry

  • windows 7 x64 SP1
  • Python x64 3.10

If try to use 2 different code page characters, then:

python.exe -m pylnk3 c c:\111\222-тест\тест\тест.txt 1.lnk

python.exe -m pylnk3 p 1.lnk

...
File Location Info: <not specified>
<LinkTargetIDList>:
  <RootEntry: MY_COMPUTER>
  <DriveEntry: b'C:'>
  <PathSegmentEntry: 111>
  <PathSegmentEntry: None>
  <PathSegmentEntry: тест>
  <PathSegmentEntry: None>
Used Path: C:\111\тест

python.exe -m pylnk3 p 1.lnk --json

    "shell_item_id_list": {
        "items": [
            {
                "class": "RootEntry",
                "root": "MY_COMPUTER",
                "guid": "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
            },
            {
                "class": "DriveEntry",
                "drive": "C:"
            },
            {
                "class": "PathSegmentEntry",
                "type": "FOLDER",
                "file_size": 0,
                "modified": "2023-01-20T22:25:14",
                "created": "2023-01-20T22:25:06",
                "accessed": "2023-01-20T22:25:14",
                "short_name": "111",
                "full_name": "111"
            },
            {
                "class": "PathSegmentEntry",
                "type": "FOLDER",
                "file_size": 0,
                "modified": "2023-01-20T22:25:18",
                "created": null,
                "accessed": null,
                "short_name": "2",
                "full_name": null
            },
            {
                "class": "PathSegmentEntry",
                "type": "FOLDER",
                "file_size": 0,
                "modified": "2023-01-20T22:25:24",
                "created": "2023-01-20T22:25:18",
                "accessed": "2023-01-20T22:25:24",
                "short_name": "B\u00045\u0004A\u0004B\u0004",
                "full_name": "\u0442\u0435\u0441\u0442"
            },
            {
                "class": "PathSegmentEntry",
                "type": "FILE",
                "file_size": 0,
                "modified": "2023-01-20T22:25:24",
                "created": null,
                "accessed": null,
                "short_name": "B\u00045\u0004A\u0004B\u0004.",
                "full_name": null
            }
        ]
    },

The 2d and 4th segments looks broken.

Links are not builded correctly on linux

If I run the following command on a linux system:


pylnk3 c C:\Windows\notepad.exe notepad.lnk

.. and transfer it on a windows host, the LNK file seems to be corrupt, because the slashes were removed:

lnk_file

Does the link creation only works on windows or is there any other solution?

Thanks a lot!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.