I did a script that when focusing on a Shortcut / Symbolic Link / Hardlink / Junction it navigates to it's target.
It's a mix of MC Script, Python and an executable (because it seems no one care about enumerating hardlinks targets)
If there's more than 2 instances of a hardlink or junction, the script asks the user witch one he likes.
I'm posting the main Python code (I used some custom libs I did). If people get interested I can post the full code.
MC Script:
@var $source_focus_path = '"' + GetSourceFocusPath() + '"';
@var $python_script_path;
@var $link_target;
@var $link_target_temp_file;
@var $link_target_file_size;
@var $findlinks_path;
@var $aux[];
@var $aux2;
$python_script_path = '"' + GetTagValue("${mcinstallpath}") ^ 'Tools\Links\Resolve Link.py' + '"';
$link_target_temp_file = GetTagValue("${mcinstallpath}") ^ 'Tools\Links\link_target.txt';
$findlinks_path = '"' + GetTagValue("${mcinstallpath}") ^ 'Tools\Links\Hardlink\FindLinks.exe' + '"';
if (FileExists($link_target_temp_file) == 1)
{
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
DeleteFile($link_target_temp_file, $aux);
}
// There's a bug in StrReplace when using ^ in parameter
$aux2 = '^"';
$python_script_path = StrReplace($python_script_path, '"', $aux2);
$source_focus_path = StrReplace($source_focus_path, '"', $aux2);
$findlinks_path = StrReplace($findlinks_path, '"', $aux2);
$link_target_temp_file = StrReplace($link_target_temp_file, '"', $aux2);
// Run Python script to get link target and store it in a temp file
LogAppInfo('"H:\Programas\MultiCommander - Projetos\Tools\Command Line Utilities\nircmd\nircmd_x64.exe" execmd "^"C:\Python35\python.exe^" ' + $python_script_path + ' ' + $source_focus_path + ' ^"' + $link_target_temp_file + '^" ' + $findlinks_path + '"');
MC.Run CMD='"H:\Programas\MultiCommander - Projetos\Tools\Command Line Utilities\nircmd\nircmd_x64.exe"' ARG={'execmd "^"C:\Python35\python.exe^" ' + $python_script_path + ' ' + $source_focus_path + ' ^"' + $link_target_temp_file + '^" ' + $findlinks_path + '"'} WAIT
// Clear selected files in the case of the link target being on the same folder
arrayAdd($aux, '');
SetSourceSelected($aux, 1);
// Ao rodar o nircmd ele retorna o sinal de terminado para o MultiComander antes de o Python ter terminado de rodar
// Então temos que esperar manualmente até o Python ter terminado de rodar
// A cada 50ms checamos se o arquivo $link_target_temp_file foi criado, até um timeout de 1s
@var $n;
for ($n = 0; $n < 20; $n++)
{
if (FileExists($link_target_temp_file) == 1)
{
break;
}
Sleep(50);
}
// Go to target
if (FileExists($link_target_temp_file) == 1)
{
Sleep(100);
//LogAppInfo($link_target_temp_file);
$link_target_file_size = GetFileSize($link_target_temp_file);
if ($link_target_file_size > 0)
{
$link_target = LoadStringFromFile($link_target_temp_file);
//LogAppInfo($link_target);
// Delete temp file
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
//DeleteFile($link_target_temp_file, $aux);
// Clear selected files in the case of the link target being on the same folder
arrayAdd($aux, '');
SetSourceSelected($aux, 1);
// As Mathias said here
http://forum.multicommander.com/forum/index.php/topic,1929.0.html // "the UI can't be updated until the script is finished since the script is running in the same thread"
// So there's no way to break going to the folder, then selecting the file in 2 operations
// We can do it in 1 go using MC.RunCmd ID="Core.1312" that is CTRL+V with the target path on the clipboard
// The ony downside is that we loose the clipboard content
SetClipboardText($link_target);
// Check if there's more than 1 link target (hardlinks and junctions)
@var $link_targets[] = StrLines2Array($link_target);
// If more than 1, ask the user
if (arrayCount($link_targets) > 1)
{
@var $link_targets_answer = AskOption('Select target', $link_targets, 0);
if ($link_targets_answer == -1)
{
// User cancelled
break;
}
SetClipboardText($link_targets[$link_targets_answer]);
}
// Go To Link Target
MC.RunCmd ID="Core.1312"
}
else
{
LogAppInfo('Error');
}
}
else
{
MessageBox('Resolve Link', 'Operation timeout', 0);
}
Python:
# -*- coding: utf-8 -*-
# argv[1] = link file/folder path
# argv[2] = path to exchange text file with Multi Commander
# argv[3] = path to FindLinks.exe
# argv[1] can't end with /
# Doesn't work when running inside Multi Commander and argv[1] is a symbolic link inside a junction (but it works inside cmd for example)
import sys
import os
import win32com.client
import mylib.windows.windows as lib_windows
import mylib.files.file_handling as lib_file_handling
file = open(sys.argv[2], 'w')
if sys.argv[1][-3:].lower() == 'lnk':
print('Shortcut detected')
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(sys.argv[1])
print(shortcut.Targetpath)
file.write(shortcut.Targetpath)
elif os.path.islink(sys.argv[1]):
print('Symbolic Link detected')
link_target = lib_file_handling.get_symlink_target(sys.argv[1])
if link_target is not None:
print(link_target)
file.write(link_target)
elif lib_file_handling.is_junction(sys.argv[1]):
print('Junction detected')
link_target = lib_file_handling.get_junction_target(sys.argv[1])
print(link_target)
file.write(link_target)
elif os.stat(sys.argv[1]).st_nlink > 1:
print('Hard Link detected')
stdout, stderr, returncode = lib_windows.run_command_line('"' + sys.argv[3] + '" "' + sys.argv[1] + '"')
findlinks_return = stdout.splitlines()
if int(findlinks_return[7][8:]) > 0:
for line in range(10, len(findlinks_return)):
if findlinks_return[line].lower() != sys.argv[1].lower():
print(findlinks_return[line])
file.write(findlinks_return[line] + '\n')
file.close()
And the executable is here
https://technet.microsoft.com/en-us/sysinternals/hh290814