' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ' After compilation, drag & drop this executable onto "setdos.exe" ! ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #COMPILE EXE "linkbatch.exe" #RESOURCE "linkbatch.pbr" #DIM ALL '------------------------------------------------------------------------------ ' Usage: linkbatch "c:\path\to\*.lnk" -Opt1:Field1 "arg 1" "arg 2" -Opt2:Field2... '------------------------------------------------------------------------------ ' List of '-Opt' options: ' -p = print (display) ; no argument ' -w = write (overwrite) ; 1 argument = "any string" ' -r = string replacement ; 2 arguments = "source string" "target string" '------------------------------------------------------------------------------ ' List of Fields: ' exe = the target .exe path and name ' arg = the .exe arguments ' dir = working directory ' rem = remark or comment ' ico = icon path (can be .dll, .exe, .ico) ' idx = icon index, zero based '------------------------------------------------------------------------------ ' Notes: ' You can operate on a single .lnk, or on all shortcuts in a folder (*.lnk) ' You can chain as many operations as wanted ' Options and Fields are case insensitive: you can write -r:exe or -R:EXE ' Arguments need double quotes only if they contain spaces ' linkbatch does not make any backup! Make manual backups or be extra careful '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Includes ** '------------------------------------------------------------------------------ #INCLUDE ONCE "WIN32API.INC" #INCLUDE ONCE "DOSPRINT.INC" #INCLUDE ONCE "SHORTCUT.INC" '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Main Application Entry Point ** '------------------------------------------------------------------------------ FUNCTION PBMAIN() LOCAL lnk AS LINKTYPE LOCAL tgt AS STRING ' linkbatch tgt -optn:field arg1 arg2 -optn:field arg1 ... LOCAL tgt() AS STRING ' tgt = tgt() in case of multiple files LOCAL ope AS STRING ' ope = -optn:feild LOCAL optn AS STRING LOCAL feild AS STRING LOCAL arg1 AS STRING LOCAL arg2 AS STRING LOCAL e AS STRING LOCAL i, j AS LONG LOCAL n AS LONG IF COMMAND$ = "" THEN CALL FreeConsole() ' Win32 mode -> hide console ?"This utility is to be called from the command line."+$CR+$CR _ +"Please execute Win+R > ""cmd"" and type:"+$CR+"linkbatch /?" _ , %MB_ICONINFORMATION, "linkbatch" END IF ' Any argument: parse! tgt = TRIM$(COMMAND$(1), ANY $SPC+$TAB+$DQ) ' No valid shortcut as first argument > show full usage IF RIGHT$(LCASE$(tgt), 4) <> ".lnk" THEN ShowFullUsage() EXIT FUNCTION END IF '************************************************************************** ' Test existence of target file(s) to operate '************************************************************************** ' Special case: when called without path, add current path: IF INSTR(tgt, "\") = 0 THEN tgt = RTRIM$(CURDIR$, "\") + "\" + tgt IF INSTR(tgt, "*") = 0 AND INSTR(tgt, "?") = 0 THEN ' Treating a single file REDIM tgt(0) IF NOT EXISTS(tgt) THEN GOTO ErrFile tgt(0) = tgt ELSE ' Treating multiple files n = -1 e = DIR$(tgt) WHILE e <> "" INCR n REDIM PRESERVE tgt(n) tgt(n) = PATHNAME$(PATH, tgt) + e e = DIR$(NEXT) WEND DIR$ CLOSE IF n < 0 THEN GOTO ErrFile END IF n = 2 '************************************************************************** DO ' Analyze all arguments for errors '************************************************************************** ' Check valid "-Optn:Field" operation syntax ope = TRIM$(LCASE$(COMMAND$(n)), ANY $SPC+$TAB+$DQ) IF LEFT$(ope,1) <> "-" OR MID$(ope,3,1) <> ":" THEN GOTO ErrOpe ' Get Optn from "-Optn:Field" and test against available options: -p -w -r optn = MID$(ope,2,1) IF INSTR("pwr", optn) = 0 THEN GOTO ErrOpe ' Get Field from "-Optn:Field" and test against allowed fields feild = MID$(ope,4) IF feild <> "exe" AND feild <> "arg" AND feild <> "dir" _ AND feild <> "rem" AND feild <> "ico" AND feild <> "idx" THEN GOTO ErrOpe ' All good > analyze arguments IF optn = "w" THEN ' -w = write = 1 non-empty argument needed INCR n arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) IF arg1 = "" OR LEFT$(arg1, 1) = "-" THEN GOTO ErrArg ELSEIF optn = "r" THEN ' -r = replace = 2 non-empty arguments needed INCR n arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) IF arg1 = "" OR LEFT$(arg1, 1) = "-" THEN GOTO ErrArg INCR n arg2 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) ' arg2 can actually be an empty string, if we want to ' remove something, e.g. linkbatch shortcut.lnk -r:exe " (x86)" "" ' to replace "C:\Program Files (x86)\myprog.exe" ' with "C:\Program Files\myprog.exe" ... IF LEFT$(arg2, 1) = "-" THEN GOTO ErrArg ELSEIF optn = "p" THEN ' -p = print = no argument needed END IF INCR n LOOP UNTIL COMMAND$(n) = "" '************************************************************************** ' We completed the analysis without meeting any error :) ' --> for each target file, run the parsing again ' and this time execute the operations! '************************************************************************** '************************************************************************** FOR i = 0 TO UBOUND(tgt) ' For each target file DosPrint "File: " + tgt(i) ' Parse path and filename lnk.zLinkFolder = PATHNAME$(PATH , tgt(i)) lnk.zLinkName = PATHNAME$(NAMEX, tgt(i)) ' And read shortcut information ReadShortcut(lnk) n = 2 DO ' Treat all operations ' Get Optn and Field from "-Optn:Field" ope = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) optn = LCASE$(MID$(ope,2,1)) feild = LCASE$(MID$(ope,4)) ' Execute operation! SELECT CASE optn CASE "p" ' -p = print (no argument) SELECT CASE feild CASE "exe" : DosPrint "- " + feild + " = " + lnk.zExeName CASE "arg" : DosPrint "- " + feild + " = " + lnk.zArguments CASE "dir" : DosPrint "- " + feild + " = " + lnk.zWorkDir CASE "rem" : DosPrint "- " + feild + " = " + lnk.zComment CASE "ico" : DosPrint "- " + feild + " = " + lnk.zIconFile CASE "idx" : DosPrint "- " + feild + " = " + FORMAT$(lnk.IconIndex) END SELECT CASE "w" ' -w = write (1 argument) INCR n arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) SELECT CASE feild CASE "exe" : e = $DQ + lnk.zExeName + $DQ : lnk.zExeName = arg1 CASE "arg" : e = $DQ + lnk.zArguments + $DQ : lnk.zArguments = arg1 CASE "dir" : e = $DQ + lnk.zWorkDir + $DQ : lnk.zWorkDir = arg1 CASE "rem" : e = $DQ + lnk.zComment + $DQ : lnk.zComment = arg1 CASE "ico" : e = $DQ + lnk.zIconFile + $DQ : lnk.zIconFile = arg1 CASE "idx" : e = FORMAT$(lnk.IconIndex) : lnk.IconIndex = VAL(arg1) END SELECT DosPrint "- " + feild + ": " + e + " <<< " + IIF$(LEFT$(e,1)=$DQ,$DQ,"") + arg1 + IIF$(LEFT$(e,1)=$DQ,$DQ,"") CASE "r" ' -r = replace (2 arguments) INCR n arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) INCR n arg2 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ) SELECT CASE feild CASE "exe" j = INSTR(LCASE$(lnk.zExeName), LCASE$(arg1)) IF j = 0 THEN DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace" ELSE e = lnk.zExeName lnk.zExeName = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1)) DosPrint "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zExeName + $DQ END IF CASE "arg" j = INSTR(LCASE$(lnk.zArguments), LCASE$(arg1)) IF j = 0 THEN DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace" ELSE e = lnk.zArguments lnk.zArguments = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1)) DosPrint "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zArguments + $DQ END IF CASE "dir" j = INSTR(LCASE$(lnk.zWorkDir), LCASE$(arg1)) IF j = 0 THEN DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace" ELSE e = lnk.zWorkDir lnk.zWorkDir = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1)) DosPrint "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zWorkDir + $DQ END IF CASE "rem" j = INSTR(LCASE$(lnk.zComment), LCASE$(arg1)) IF j = 0 THEN DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace" ELSE e = lnk.zComment lnk.zComment = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1)) DosPrint "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zComment + $DQ END IF CASE "ico" j = INSTR(LCASE$(lnk.zIconFile), LCASE$(arg1)) IF j = 0 THEN DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace" ELSE e = lnk.zIconFile lnk.zIconFile = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1)) DosPrint "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zIconFile + $DQ END IF CASE "idx" IF lnk.IconIndex <> VAL(arg1) THEN DosPrint "- " + feild + ": skipping icon index not equal to " + FORMAT$(VAL(arg1)) ELSE e = FORMAT$(lnk.IconIndex) lnk.IconIndex = VAL(arg2) DosPrint "- " + feild + ": " + e + " <<< " + FORMAT$(VAL(arg2)) END IF END SELECT END SELECT INCR n LOOP UNTIL COMMAND$(n) = "" ' Save modified shortcut WriteShortcut(lnk) DosPrint "" NEXT i ' Normal termination FUNCTION = 0 EXIT FUNCTION '************************************************************************** '****** ErrFile: '****** DosPrint "Error: no matching file " + $DQ + tgt + $DQ FUNCTION = 1 EXIT FUNCTION '****** ErrOpe: '****** DosPrint "Error: invalid ""-Opt:Field"" operation " + $DQ + ope + $DQ DosPrint "" ShowShortUsage() FUNCTION = 2 EXIT FUNCTION '****** ErrArg: '****** DosPrint "Error: invalid argument, or number of arguments, for " + $DQ + ope + $DQ DosPrint "" ShowShortUsage() FUNCTION = 3 EXIT FUNCTION END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ SUB ShowShortUsage() DosCol 10, 0 DosPrint "Usage: linkbatch ""c:\path\to\*.lnk"" -Opt1:Field1 ""arg 1"" ""arg 2"" -Opt2:Field2..." DosPrint " -Opt = -p (print, 0 arg), -w (write, 1 arg), -r (replace, 2 args)" DosPrint " Fields = exe, arg, dir, rem, ico, idx DosPrint " You can type ""linkbatch /?"" for more details" DosCol 7, 0 END SUB '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ SUB ShowFullUsage() DosCol 10, 0 DosPrint "Usage: linkbatch ""c:\path\to\*.lnk"" -Opt1:Field1 ""arg 1"" ""arg 2"" -Opt2:Field2..." DosPrint "" DosPrint "List of '-Opt' options:" DosPrint " -p = print (display) ; no argument" DosPrint " -w = write (overwrite) ; 1 argument = ""any string""" DosPrint " -r = string replacement ; 2 arguments = ""source string"" ""target string""" DosPrint "" DosPrint "List of shortcut ':Fields':" DosPrint " :exe = target .exe path and name" DosPrint " :arg = executable arguments" DosPrint " :dir = working directory" DosPrint " :rem = remark or comment" DosPrint " :ico = icon path (.dll, .exe, .ico)" DosPrint " :idx = icon index, zero based" DosPrint "" DosPrint "Notes:" DosPrint " You can operate on a single .lnk, or on all shortcuts in a folder (*.lnk)" DosPrint " You can chain as many operations as wanted" DosPrint " Options and Fields are case insensitive: you can write -r:exe or -R:EXE" DosPrint " Target .lnk and arguments need double quotes only if they contain spaces" DosPrint " linkbatch does not make any backup! Please backup your shortcuts manually" DosCol 7, 0 END SUB '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ FUNCTION EXISTS(BYVAL fileOrFolder AS STRING) AS LONG LOCAL Dummy& Dummy& = GETATTR(fileOrFolder) FUNCTION = (ERRCLEAR = 0) END FUNCTION '------------------------------------------------------------------------------