在Go中创建Windows快捷方式(.lnk)

I would like to create a Windows Shortcut (.lnk) to the desktop and the startmenu in Golang.

I actually got the Desktop & Startmenu folders via the gowin module and I would like to create a shortcut to thoses locations.

I searched but I did not find any golang project for it. Should I create it ? Is there an other pretty method ?

Using https://github.com/go-ole/go-ole:

ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_SPEED_OVER_MEMORY)
oleShellObject, err := oleutil.CreateObject("WScript.Shell")
if err != nil {
    return err
}
defer oleShellObject.Release()
wshell, err := oleShellObject.QueryInterface(ole.IID_IDispatch)
if err != nil {
    return err
}
defer wshell.Release()
cs, err := oleutil.CallMethod(wshell, "CreateShortcut", dst)
if err != nil {
    return err
}
idispatch := cs.ToIDispatch()
oleutil.PutProperty(idispatch, "TargetPath", src)
oleutil.CallMethod(idispatch, "Save")

No, there isn't any pretty method for creating .lnk file, in golang.

Primary reason is that, .lnk files are windows specific.

In Windows, even a native program need to use OLE (Object linking and embedding) and COM (component object model) to create a shortcut file, as described in this answer.

In my opinion, One way to approach this problem in golang is to use gowin, and try to communicate with OLE COM.

OR

Write a native windows component that does actual work of creating .lnk file, and just spawn its process through your go program.

Solution via external program from this subject:

Shortcut executable from NirSoft

shortcut "f:\winnt\system32\calc.exe" "~$folder.desktop$" "Windows Calculator" 
shortcut "f:\winnt\system32\calc.exe" "~$folder.programs$\Calculators" "Windows Calculator" 
shortcut "f:\Program Files\KaZaA\Kazaa.exe" "c:\temp\MyShortcuts" "Kazaa" 
shortcut "f:\Program Files" "c:\temp\MyShortcuts" "Program Files Folder" "" "f:\winnt\system32\shell32.dll" 45 
shortcut "f:\Program Files" "c:\temp\MyShortcuts" "Program Files Folder" "" "" "" "max"

Shortcut executable from Optimumx

Shortcut.exe /f:"%USERPROFILE%\Desktop\sc.lnk" /a:c  /t:%USERPROFILE%\Desktop\scrum.pdf

.vbs

Set oWS = WScript.CreateObject("WScript.Shell")
sLinkFile = "C:\MyShortcut.LNK"
Set oLink = oWS.CreateShortcut(sLinkFile)
    oLink.TargetPath = "C:\Program Files\MyApp\MyProgram.EXE"
 '  oLink.Arguments = ""
 '  oLink.Description = "MyProgram"   
 '  oLink.HotKey = "ALT+CTRL+F"
 '  oLink.IconLocation = "C:\Program Files\MyApp\MyProgram.EXE, 2"
 '  oLink.WindowStyle = "1"   
 '  oLink.WorkingDirectory = "C:\Program Files\MyApp"
oLink.Save

Powershell script

set TARGET='D:\Temp'
set SHORTCUT='C:\Temp\test.lnk'
set PWS=powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile

%PWS% -Command "$ws = New-Object -ComObject WScript.Shell; $s = $ws.CreateShortcut(%SHORTCUT%); $S.TargetPath = %TARGET%; $S.Save()"

The AWFUL Working golang solution using VBS;

package main

import(
    "bytes"
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
)

func createShortcut(linkName string, target string, arguments string, directory string, description string, destination string) {
    var scriptTxt bytes.Buffer
    scriptTxt.WriteString("option explicit

")
    scriptTxt.WriteString("sub CreateShortCut()
")
    scriptTxt.WriteString("dim objShell, strDesktopPath, objLink
")
    scriptTxt.WriteString("set objShell = CreateObject(\"WScript.Shell\")
")
    scriptTxt.WriteString("strDesktopPath = objShell.SpecialFolders(\"")
    scriptTxt.WriteString(destination)
    scriptTxt.WriteString("\")
")
    scriptTxt.WriteString("set objLink = objShell.CreateShortcut(strDesktopPath & \"\\")
    scriptTxt.WriteString(linkName)
    scriptTxt.WriteString(".lnk\")
")
    scriptTxt.WriteString("objLink.Arguments = \"")
    scriptTxt.WriteString(arguments)
    scriptTxt.WriteString("\"
")
    scriptTxt.WriteString("objLink.Description = \"")
    scriptTxt.WriteString(description)
    scriptTxt.WriteString("\"
")
    scriptTxt.WriteString("objLink.TargetPath = \"")
    scriptTxt.WriteString(target)
    scriptTxt.WriteString("\"
")
    scriptTxt.WriteString("objLink.WindowStyle = 1
")
    scriptTxt.WriteString("objLink.WorkingDirectory = \"")
    scriptTxt.WriteString(directory)
    scriptTxt.WriteString("\"
")
    scriptTxt.WriteString("objLink.Save
end sub

")
    scriptTxt.WriteString("call CreateShortCut()")
    fmt.Print(scriptTxt.String())

    filename := fmt.Sprintf("lnkTo%s.vbs", destination)
    ioutil.WriteFile(filename, scriptTxt.Bytes(), 0777)
    cmd := exec.Command("wscript", filename)
    err := cmd.Run()
    if err != nil {
        fmt.Println(err)
    }
    cmd.Wait()
    os.Remove(filename)
    return
}