Jump to content

Passing an LFN to a .BAT script through Send To function or file assoc


Sfor

Recommended Posts

Honestly, I haven't even figured out how some of those examples work (the author appears to abuse formatting a lot so comments are mingled in with commands and he has a fondness for using debug). Good link though.

Honesty for honesty, neither have I. ;)

Fact is that the "pure-DOS" batch language is so limited that people over the years invented so many workarounds, mostly using "quirks" or "undocumented side effect of some commands" that is nearly impossible to keep track of them, and often not even to actually understand how they work.

You need some act of faith and trust them, or you need to test them one line at the time to understand what happens.

jaclaz

Link to comment
Share on other sites


Ok so, I've refined things some so that environment variable space is much less of an issue and to handle much longer path names. It still can't handle file names that contain spaces. I still haven't tested under XP (or anything besides 98SE); I know my %~n2 check works, but don't know what happens if this batch file is called via a file association (does XP pass a capitalized short file name?).


@echo off
goto chk
:pth

echo %NAME%
goto fin

:chk
if ?%1?==?? goto use
if ?%1?==?/auto? goto :ver
if ?%1?==?[?? goto :prs

cls
set NAME=%1
:add
shift
if ?%1?==?? goto pth
set NAME=%NAME% %1
goto add

:ver
if ?%2?==?? goto use
if ?%~n2?==?~n2? goto w9x
set NAME=%~n2
goto pth

:w9x
lfnfor on
echo ;> "%TEMP%.\BUILDTMP.BAT"
if not exist "%TEMP%.\BUILDTMP.BAT" goto use
for %%A in ("%2*") do if not exist "%2.*" copy /Y "%TEMP%.\BUILDTMP.BAT" "%%A.tmp" > nul
for %%A in ("%2*") do choice /S /T:;,1 /C:?%%A; ;BUILDASM.BAT< "%TEMP%.\BUILDTMP.BAT" > "%TEMP%.\BUILDTMP.BAT"
for %%A in ("%2*") do if exist "%%A.tmp" del "%%A.tmp"
set NAME=
:: set PATH=%0\..
call "%TEMP%.\BUILDTMP.BAT"
del "%TEMP%.\BUILDTMP.BAT"
goto pth

:prs
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
if ?%0?==?.? goto per
set NAME=%NAME%%0
goto prs
:per
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
goto per
:sla
set NAME=
goto prs

:use
echo Usage: BUILDASM.BAT Project Name

:fin
echo Press any key to exit . . .
pause > nul
cls
:end

The commented out line:

:: set PATH=%0\..

can be uncommented only if you redefine PATH manually, and lets BUILDASM.BAT exist outside of PATH; basically, it's only for if you want BUILDASM.BAT to be in an arbitrary location (not the working directory or in the system PATH) AND if you plan to redefine PATH (which I do in my personal use of this file.

As before, the file needs to be named BUILDASM.BAT, or the single reference to BUILDASM.BAT needs to be changed to whatever you want to name the file.

There's a little bit of wasteful file writing, but it lets me drastically reduce the length of the string to be parsed by removing the entire path from the string (which was causing limitations).

Obviously this has deviated a bit from what Sfor originally asked for help with, but it's been a fun experiment and certainly still has a viable use.

Edit - I'm dumb, and forgot %2 is a short file name, so if not exist "%2.*" and del "%2.tmp" are both no good for any file names longer than 8.3. I'm trying really hard to come up with a way to avoid saving %%A from either for loop in an environment variable to save on environment variable space (which is pretty limited at its default size).

Queue

Edited by Queue
Link to comment
Share on other sites

Well, under 2K/XP there is variable expansion already:

http://www.msfn.org/board/index.php?showtopic=143572&st=1

You don't need anything "fancy", a simple "%~n1" or "%~n2" would do.

To get short and long filenames in 2k/Xp you can parse the output of a DIR /X in a FOR loop.

jaclaz

P.S.:

Since noone took the hint, I just quickly checked Win95cmd.exe:

What about trying the 9x enhanced command processor?

http://www.boot-land.net/forums/?showtopic=2392

and it DOES have the DIR /X option.

Edited by jaclaz
Link to comment
Share on other sites

Check the :ver section; it accomodates %~n2.

The dumb fast post option ate my post, so I really don't feel like retyping everything I had. -_-

The gist of it was, thanks for the suggestions, and I do have Win95cmd, but the point of this exercise is to accomplish it without using non-default tools (and using default settings, which is why I accomodate limited environment variable space, but don't have a safety for if Command Extensions are off).

While I know my %~n2 check works, what I don't know is if, when passed a file name via a file association, if a batch file gets a short or long file name piece from %~n2 on XP.

Edit - Currently I'm wrestling with if not exist "%%A.*" in a for loop saying a file doesn't exist when it clearly does.

Edit2 - And I realized my problem. %%A.* really doesn't exist due to what my loop is doing. Rather, when %%A changes on the next iteration of the loop, that means the new %%A.* doesn't exist.

Edit3 - Edited my previous post to make changes to the for loops. I've made some improvements, but things aren't perfect; with the changes, you can have a really long path, but the file name has to be 8.3 in size for it to work; conversely, longer than 8.3 file names work as long as the path isn't too long. File names still can't have spaces in them.

Queue

Edited by Queue
Link to comment
Share on other sites

I still can't figure out why, in 2010, poeple are still programing scripts in DOS while VBScript exists.

VBScript would handle your comandline and your short/long file names in two lines, if it's even necessary at all.

Link to comment
Share on other sites

I still can't figure out why, in 2010, poeple are still programing scripts in DOS while VBScript exists.

VBScript would handle your comandline and your short/long file names in two lines, if it's even necessary at all.

In my case, it's because it's a fun challenge. The more limited your resources, the more satisfying it is to solve a problem using them.

Considering I'm using a batch script to parse out a file name to automate compiling assembly code, and I could've written a simple assembly program to handle everything my batch file does in maybe 5 minutes, and it would use less memory and execute faster, it is a waste, but that's not the point. Instead I've spent a little time over the course of like 3 days refining a batch script that has no built-in string handling, to handle formatting an input string, and it's been a blast.

Queue

Link to comment
Share on other sites

Ok, I think I'm nearly done with this. I've solved, I think, any path / file name length issues (within reason), and can deal, decently, with spaces in file names.


@echo off
goto chk
:pth

echo %NAME%
goto fin

:chk
if ?%1?==?? goto use
if ?%1?==?/auto? goto :ver
if ?%1?==?]?? goto :pre
if ?%1?==?[?? goto :prs

cls
set NAME=%1
:add
shift
if ?%1?==?? goto pth
set NAME=%NAME% %1
goto add

:ver
if ?%2?==?? goto use
if ?%~n2?==?~n2? goto w9x
set NAME=%~n2
goto pth

:w9x
if not exist "%2" goto use
lfnfor on
type nul > "%TEMP%.\BUILDTMP.BAT"
if not exist "%TEMP%.\BUILDTMP.BAT" goto use
for %%A in ("%2*") do if not exist "%2.*" copy /Y "%TEMP%.\BUILDTMP.BAT" "%%A.tmp" > nul
for %%A in ("%2*") do %COMSPEC% /C for %%B in ("%%A*") do call %0 ]? %%B
for %%A in ("%2*") do if exist "%%A.tmp" del "%%A.tmp"
set NAME=
:: set PATH=%0\..
call "%TEMP%.\BUILDTMP.BAT"
del "%TEMP%.\BUILDTMP.BAT"
goto pth

:pre
cls
shift
shift
if ?%0?==?? goto end
if ?%1?==?? goto ch0
if ?%2?==?? goto ch1
if ?%3?==?? goto ch2
if ?%4?==?? goto ch3
if ?%5?==?? goto ch4
if ?%6?==?? goto ch5
if ?%7?==?? goto ch6
if ?%8?==?? goto ch7
if ?%9?==?? goto ch8
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4*%5*%6*%7*%8*%9; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch8
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4*%5*%6*%7*%8; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch7
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4*%5*%6*%7; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch6
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4*%5*%6; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch5
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4*%5; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch4
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3*%4; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch3
echo ;|choice /S /T:;,1 /C:?%0*%1*%2*%3; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch2
echo ;|choice /S /T:;,1 /C:?%0*%1*%2; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch1
echo ;|choice /S /T:;,1 /C:?%0*%1; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch0
echo ;|choice /S /T:;,1 /C:?%0; BUILDASM.BAT > "%TEMP%.\BUILDTMP.BAT"
goto end

:prs
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
if ?%0?==?.? goto per
if ?%0?==?*? goto ast
set NAME=%NAME%%0
goto prs
:sla
set NAME=
goto prs
:per
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
goto per
:ast
set NAME=%NAME%
goto prs

:use
echo Usage: BUILDASM.BAT Project Name

:fin
echo Press any key to exit . . .
pause > nul
cls
:end

The if ?%0?==?*? goto ast line handles spaces in file names, with the flaw of multiple spaces in a row in a file name aren't handled (they'd be compacted down to a single space).

Queue

Link to comment
Share on other sites

While DEFINITELY not the answer to the ultimate question about DOS batches ;), I played a bit with a 98 in a VM.

A lot of things can be done even without using DEBUG or the "updated command processor":

@ECHO OFF
REM sh2long.bat
REM Intended for usage in a WIN98 Command Window
REM Usage:
REM sh2long.bat <shortfilename without path but with extension>
REM WILL NOT work with spaces in the long file name

CD|CHOICE /N /C:ABCDEFGHIJKLMNOPQRSTUVWXYZ SET CURDRIVE=>ENTER.BAT
FOR %%A IN (CALL DEL) DO %%A ENTER.BAT

CD > TEMP.TMP
ECHO.>> TEMP.TMP
TYPE TEMP.TMP | DATE >TEMP.BAT
>>ENTER.BAT ECHO SET CURDIR=%%4
CALL TEMP.BAT

%CURDRIVE%:
CD %CURDRIVE%:\
CLS
DEL ENTER.BAT

DIR /S /B /Z %1 > TEMP.TMP
ECHO.>> TEMP.TMP
TYPE TEMP.TMP | DATE >TEMP.BAT
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET FULLSHORT=%%4
CALL TEMP.BAT
CLS
DEL ENTER.BAT

ECHO.
DIR /S /B %1 > TEMP.TMP
ECHO.>> TEMP.TMP
TYPE TEMP.TMP | DATE >TEMP.BAT
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET FULLLONG=%%4
CALL TEMP.BAT
CLS
DEL ENTER.BAT

ECHO.
DIR %FULLLONG% | FIND "." > TEMP.TMP
ECHO.>> TEMP.TMP
TYPE TEMP.TMP | DATE >TEMP.BAT
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET SHORT=%%4.%%5
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET SHORTNAME=%%4
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET EXTENSION=%%5
>>ENTER.BAT ECHO IF NOT "%%4"=="" SET LONG=%%9
>>ENTER.BAT ECHO %%8
CALL TEMP.BAT
CLS

CD %CURDIR%

ECHO Full Short is %FULLSHORT%
ECHO Short is %SHORT%
ECHO.
ECHO ShortName is %SHORTNAME%
ECHO Extension is %EXTENSION%
ECHO.
ECHO Full Long is %FULLLONG%
ECHO Long is %LONG%

FOR %%F IN (TEMP.BAT TEMP.TMP ENTER.BAT) DO IF EXIST %%F DEL %%F
SET FULLSHORT=
SET SHORT=
SET SHORTNAME=
SET EXTENSION=
SET FULLLONG=
SET LONG=
SET CURDRIVE=
SET CURDIR=

This should work, as long as the batch is on the SAME drive as the target file.

jaclaz

Link to comment
Share on other sites

FYI...

LFNFOR is an internal batch command, and enables the use of LFNs strictly for the "FOR" batch command.

Wikipedia:

http://en.wikipedia.org/wiki/COMMAND.COM

BATutil (with practical examples):

http://users.cybercity.dk/~bse26236/batutil/help/how/VARIOUS.HTM#jerry

Can be enabled system-wide every time upon (re)boot [no matter if it is native DOS mode or Windows 9x GUI mode or DOS box/console mode] by adding a line for it in AUTOEXEC.BAT:

LFNFOR ON

Windows ME users must add it in each separate MS-DOS Configuration File (PIF) shortcut Properties [which makes it available only for that particular DOS box/session/console], since MS removed autoexec.bat + config.sys (boot files) support from WinME.

If one cares to restore native DOS mode, autoexec.bat + config.sys support in WinME, please use 1 of these free tools:

http://www.mdgx.com/dos.htm#ME

HTH

Link to comment
Share on other sites

I finally took the time to test things out on WinXP and had to make some adjustments. I also added drag&drop support. The script is a bit more skewed towards only working for .asm files, as that's the purpose my batch file was built for.


@echo off
:: Set project name
goto chk
:pth
if "%NAME%"=="" goto use
if not exist "%NAME%.asm" goto use

:: Set compiler paths
path ;
path "D:\My Documents\Development\masm32\include"
set INCLUDE=%PATH%
path ;
path "C:\Program Files\Microsoft Visual C++ 6.0 Standard Edition\VC98\LIB"
set LIB=%PATH%
path ;
path "C:\Program Files\Microsoft Visual C++ 6.0 Standard Edition\VC98\BIN"

:: =======================================================================================

:: Put stuff to do to your target file in place of the following three placeholder lines
cd
echo %NAME%
goto fin

:: .......................................................................................

:chk
if ?%1?==?? goto use
if ?%1?==?]?? goto pre
if ?%1?==?[?? goto prs
if ?%2?==?? if exist %1 goto ver

cls
path ;
set NAME=%1
if ?%2?==?? goto pth
set NAME=%NAME% %2
if ?%3?==?? goto pth
set NAME=%NAME% %3
if ?%4?==?? goto pth
set NAME=%NAME% %4
if ?%5?==?? goto pth
set NAME=%NAME% %5
if ?%6?==?? goto pth
set NAME=%NAME% %6
if ?%7?==?? goto pth
set NAME=%NAME% %7
if ?%8?==?? goto pth
set NAME=%NAME% %8
if ?%9?==?? goto pth
set NAME=%NAME% %9
goto pth

:ver
if "%~n1"=="~n1" goto w9x
path ;
set NAME=%~n1
if "%NAME%"=="" goto use
if not exist "%NAME%.asm" cd /D "%~dp1"
goto pth

:w9x
rem > "%TEMP%.\BUILDTMP.BAT"
if not exist "%TEMP%.\BUILDTMP.BAT" goto use
lfnfor on
for %%A in (%1*) do if not exist %1.* move /Y "%TEMP%.\BUILDTMP.BAT" "%%A.tmp"
for %%A in (%1*) do %COMSPEC% /C for %%B in ("%%A*") do call %0 ]? %%B
for %%A in (%1*) do if exist "%%A.tmp" del "%%A.tmp"
if not exist "%TEMP%.\BUILDTMP.BAT" goto use
echo %1| choice /N /C:ABCDEFGHIJKLMNOPQRSTUVWXYZ:\ | set _=
for %%A in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [) do if errorlevel H%%A set _=%%A
if ?%_%?==?[? set _=
set NAME=
call "%TEMP%.\BUILDTMP.BAT" %0
del "%TEMP%.\BUILDTMP.BAT"
if "%NAME%"=="" goto use
if not exist "%NAME%.asm" cd %1\..
if not exist "%NAME%.asm" if not ?%_%?==?? %_%:
goto pth

:: .......................................................................................

:pre
cls
shift
shift
if ?%0?==?? goto end
if ?%1?==?? goto ch0
if ?%2?==?? goto ch1
if ?%3?==?? goto ch2
if ?%4?==?? goto ch3
if ?%5?==?? goto ch4
if ?%6?==?? goto ch5
if ?%7?==?? goto ch6
if ?%8?==?? goto ch7
if ?%9?==?? goto ch8
echo ;| choice /S /C:?%0*%1*%2*%3*%4*%5*%6*%7*%8*%9; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch8
echo ;| choice /S /C:?%0*%1*%2*%3*%4*%5*%6*%7*%8; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch7
echo ;| choice /S /C:?%0*%1*%2*%3*%4*%5*%6*%7; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch6
echo ;| choice /S /C:?%0*%1*%2*%3*%4*%5*%6; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch5
echo ;| choice /S /C:?%0*%1*%2*%3*%4*%5; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch4
echo ;| choice /S /C:?%0*%1*%2*%3*%4; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch3
echo ;| choice /S /C:?%0*%1*%2*%3; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch2
echo ;| choice /S /C:?%0*%1*%2; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch1
echo ;| choice /S /C:?%0*%1; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end
:ch0
echo ;| choice /S /C:?%0; %%1 > "%TEMP%.\BUILDTMP.BAT"
goto end

:: .......................................................................................

:prs
path ;
:sla
set NAME=
:chr
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
if ?%0?==?.? goto per
if ?%0?==?*? goto ast
set NAME=%NAME%%0
goto chr
:per
shift
if ?%0?==?? goto end
if ?%0?==?]?? goto end
if ?%0?==?\? goto sla
if ?%0?==?[?? goto sla
goto per
:ast
set NAME=%NAME%
goto chr

:: .......................................................................................

:use
echo Usage: BUILDASM.BAT Project Name
echo or: BUILDASM.BAT X:\FOLDER~1\FILENAME.ASM
echo or: BUILDASM.BAT "X:\Long Folder Name\Long File Name.asm"

:fin
echo Press any key to exit . . .
pause | rem | cls

:end

Unfortunately, cmd.exe is pretty dumb about nesting commands on a single line. For example, pause | cls works fine with command.com, but with cmd.exe, the cls clears the screen during the pause instead of after it, hence why I had to do pause | rem | cls instead. cmd.exe also chokes on path ; | path "drive:\real path" (a nice space saver), so I had to spread out the '':: Set compiler paths'' section a little.

In this version I removed any nul redirections; I read that handles opened to devices (nul is a device) aren't closed properly the way file handles are. Whether it's true or not, finding redirection replacements for nul wasn't hard.

Queue

Edited by Queue
Link to comment
Share on other sites

  • 4 years later...

I've been trying to feed a .BAT script with Long File Names using Send To folder or file association. For some reason Windows 98 sends just the short names, always. Is there a way to force an LFN to be passed through command line parameters.

 

After unsuccessfully trying to do lots of things in the bat files themselves I ended replacing the bat and pif drophandlers in the registry by the windows script host drophandler.

 

From:

 

[HKEY_CLASSES_ROOT\batfile\shellex\DropHandler]

@ = "{86C86720-42A0-1069-A2E8-08002B30309D}"

[HKEY_CLASSES_ROOT\piffile\shellex\DropHandler]

@ = "{86C86720-42A0-1069-A2E8-08002B30309D}"

 

To:

 

[HKEY_CLASSES_ROOT\batfile\shellex\DropHandler]

@ = "{60254CA5-953B-11CF-8C96-00AA00B8708C}"

[HKEY_CLASSES_ROOT\piffile\shellex\DropHandler]

@ = "{60254CA5-953B-11CF-8C96-00AA00B8708C}"

 

 

Works nicely, now the output of my batch files using %1 arguments is always LFN. However, this would presumably break working with 16bit dos programs that can't handle LFNs but in this case it would be easy to temporarily toggle those values with a couple of registry files.

 

 And btw processing multiple files using forfiles.exe from the Win98 resource kit and bat files always results in LFN output regardless of which drop handler is being used.

Edited by loblo
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...