Index: src/platform/win/umywindows.pas
===================================================================
--- src/platform/win/umywindows.pas	(revision 8763)
+++ src/platform/win/umywindows.pas	(working copy)
@@ -137,6 +137,10 @@
 }
 procedure CreateShortcut(const Target, Shortcut: String);
 {en
+   Extracts target full file path from windows shortcut file (.lnk)
+}
+function GetShortcutTarget(const ShortcutFilename: string): string;
+{en
    Extract file attributes from find data record.
    Removes reparse point attribute if a reparse point tag is not a name surrogate.
    @param(FindData Find data record from FindFirstFile/FindNextFile function.)
@@ -860,6 +864,26 @@
   OleCheckUTF8(IPFile.Save(PWideChar(LinkName), False));
 end;
 
+function GetShortcutTarget(const ShortcutFilename: string): string;
+var
+  Psl: IShellLink;
+  Ppf: IPersistFile;
+  WideName: array[0..MAX_PATH] of WideChar;
+  pResult: array[0..MAX_PATH-1] of ansiChar;
+  Data: TWin32FindData;
+const
+  IID_IPersistFile: TGUID = (
+    D1:$0000010B; D2:$0000; D3:$0000; D4:($C0,$00,$00,$00,$00,$00,$00,$46));
+begin
+  CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IID_IShellLinkA, psl);
+  psl.QueryInterface(IID_IPersistFile, ppf);
+  MultiByteToWideChar(CP_ACP, 0, pAnsiChar(ShortcutFilename), -1, WideName, Max_Path);
+  ppf.Load(WideName, STGM_READ);
+  psl.Resolve(0, SLR_ANY_MATCH);
+  psl.GetPath(@pResult, MAX_PATH, Data, SLGP_UNCPRIORITY);
+  Result := StrPas(pResult);
+end;
+
 function ExtractFileAttributes(const FindData: TWin32FindDataW): DWORD; inline;
 begin
   // If a reparse point tag is not a name surrogate then remove reparse point attribute
Index: src/uglobs.pas
===================================================================
--- src/uglobs.pas	(revision 8763)
+++ src/uglobs.pas	(working copy)
@@ -1018,6 +1018,7 @@
       AddIfNotExists(['Alt+Right'],[],'cm_ViewHistoryNext');
       AddIfNotExists(['Alt+Shift+Enter'],[],'cm_CountDirContent');
       AddIfNotExists(['Alt+Shift+F9'],[],'cm_TestArchive');
+      AddIfNotExists(['Ctrl+Shift+S'],[],'cm_CreateShortcut');
       AddIfNotExists([
          'Alt+1','','index=1','',
          'Alt+2','','index=2','',
Index: src/umaincommands.pas
===================================================================
--- src/umaincommands.pas	(revision 8763)
+++ src/umaincommands.pas	(working copy)
@@ -27,8 +27,9 @@
 interface
 
 uses
-  Classes, SysUtils, ActnList, uFileView, uFileViewNotebook, uFileSourceOperation,
-  uGlobs, uFileFunctions, uFormCommands, uFileSorting, uShellContextMenu, Menus, ufavoritetabs,ufile;
+  Classes, SysUtils, ActnList, uFileView, uFileViewNotebook, uFileSourceOperation, uTypes,
+  uGlobs, uFileFunctions, uFormCommands, uFileSorting,
+  uShellContextMenu, Menus, ufavoritetabs, ufile, uMyWindows;
 
 type
 
@@ -295,6 +296,7 @@
    procedure cm_RightSortBySize(const Params: array of string);
    procedure cm_RightSortByAttr(const Params: array of string);
    procedure cm_SymLink(const Params: array of string);
+   procedure cm_CreateShortcut(const {%H-}Params: array of string);
    procedure cm_CopySamePanel(const Params: array of string);
    procedure cm_DirHistory(const Params: array of string);
    procedure cm_ViewHistory(const Params: array of string);
@@ -832,10 +834,24 @@
       begin
         // Change file source, if the file under cursor can be opened as another file source.
         try
+          if LowerCase(aFile.Extension) = 'lnk' then
+          begin
+            NewPath := GetShortcutTarget(aFile.FullPath);
+            if mbDirectoryExists(NewPath) then
+              ChooseFileSource(TargetPage.FileView, NewPath)
+            else  // file
+            begin
+              ChooseFileSource(TargetPage.FileView, ExtractFilePath(NewPath));
+              TargetPage.FileView.SetActiveFile(NewPath);
+            end;
+          end
+          else
+          begin
           if not ChooseFileSource(TargetPage.FileView, SourcePage.FileView.FileSource, aFile) then
             TargetPage.FileView.AddFileSource(SourcePage.FileView.FileSource,
                                               SourcePage.FileView.CurrentPath);
           TargetPage.FileView.SetActiveFile(aFile.Name);
+          end;
         except
           on e: EFileSourceException do
             MessageDlg('Error', e.Message, mtError, [mbOK], 0);
@@ -1158,6 +1174,7 @@
 var
   aFile: TFile;
   NewPage: TFileViewPage;
+  NewPath: string;
 begin
   aFile := FrmMain.ActiveFrame.CloneActiveFile;
   if not Assigned(aFile) then
@@ -1170,6 +1187,17 @@
     else if FileIsArchive(aFile.FullPath) then
       NewPage := OpenArchive(aFile)
     else
+    if LowerCase(aFile.Extension) = 'lnk' then
+    begin
+      NewPath := GetShortcutTarget(aFile.FullPath);
+      if mbDirectoryExists(NewPath) then
+        NewPage := OpenTab(NewPath)
+      else  // file
+      begin
+        NewPage := OpenTab(ExtractFilePath(NewPath));
+        NewPage.FileView.SetActiveFile(NewPath);
+      end;
+    end else
       NewPage := OpenTab(aFile.Path);
   finally
     FreeAndNil(aFile);
@@ -3290,6 +3318,49 @@
   end;
 end;
 
+procedure TMainCommands.cm_CreateShortcut(const Params: array of string);
+var
+  sExistingFile, sLinkToCreate: String;
+  SelectedFiles: TFiles;
+begin
+  with frmMain do
+  begin
+    // Shortcut links work only for file system.
+    if not (ActiveFrame.FileSource.IsClass(TFileSystemFileSource)) then
+    begin
+      msgWarning(rsMsgErrNotSupported);
+      Exit;
+    end;
+
+    SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles;
+    try
+      if SelectedFiles.Count > 1 then
+        msgWarning(rsMsgTooManyFilesSelected)
+      else if SelectedFiles.Count = 0 then
+        msgWarning(rsMsgNoFilesSelected)
+      else
+      begin
+        sExistingFile := SelectedFiles[0].Path + SelectedFiles[0].Name;
+
+        if Length(Params) > 0 then
+          sLinkToCreate := Params[0]
+        else
+          sLinkToCreate := ActiveFrame.CurrentPath;
+
+        sLinkToCreate := sLinkToCreate + SelectedFiles[0].Name;
+        try
+          CreateShortcut(sExistingFile, sLinkToCreate);
+        finally
+          ActiveFrame.Reload;
+        end;
+      end;
+
+    finally
+      FreeAndNil(SelectedFiles);
+    end;
+  end;
+end;
+
 // Uses to change sort direction when columns header is disabled
 procedure TMainCommands.cm_ReverseOrder(const Params: array of string);
 begin
