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
}