I have 2 laptops. My code resides on 2 SDHC cards which I keep sync'd up.
I have a TEST.BAT for each of my MASM programs. The problem is that
each laptop has a different drive letter, yet I do not want to have to
hard-code my .BATs based on which machine is running my code (that's
what I WAS doing).
Googling around, I found something which works pretty well. Tho that
URL used some high-level language (C++ I think), I found a way to do it
using MASM.
Basically, I wanted to use an old IBM MAINFRAME DOS technique that,
instead of referencing a volume by a hard address (ie: drive letter),
rather, to find it by VOLSER (ie: volume name).
I know about MOUNTVOL, but that GUID is so long that I need something
simpler. I also know that volume names don't have to be unique, so, to use
this technique, all desired volume names on the machine should be unique.
And, this won't work under the GUEST LID due to permissions.
This is what I've come up with:
1. an MASM program (mine is called FINDVOL) to find the drive letter
given a volume name(s):
a. use the Win32API functions:
I. GetLogicalDrives, SetErrorMode, GetVolumeInformation
II. u can use SetEnvironmentVariable, but I wanted the .BAT to name it
b. pass the RC (ERRORLEVEL) of the drive letter (ie: E is 45h).
2. a FINDVOL.BAT to run the MASM .exe and set an Environment Variable
to the drive letter found by the MASM .exe (snippets):
SET FINDVOLvols=%1
FINDVOL.exe %FINDVOLvols%
if ERRORLEVEL 69 GOTO ERROR69
(1 for each possible drive letter (26; 65-90))
:ERROR69
set MyCURRdrive=E:
3. 1 of my TEST.BATs (1 per MASM program) that ties this all together:
from a DOS prompt, Working DIR whatever, run it:
e:\D\TOOLS\MYPROGS\FIND\test.bat (snippets):
set PATHSETpgm=FIND
call c:\dad\tools\myprogs\pathset.bat E
(set PATH for all my programs)
(c: is common on LTs, so don't have to change any TEST.BATs)
call FINDVOL.bat "021-IV ,014-I "
(the volume names of each of my 2 SDHC cards; 1 will match up)
(extra blank after each vol to ensure not a generic compare)
path %MyCURRdrive%\D\TOOLS\MYPROGS\FIND;%PATH%
(temp add my test DIR in front of all others for testing)
SET MyCURRdir=%MyCURRdrive%\D\TOOLS\MYPROGS\FIND
pushd %MyCURRdir%
(set Working DIR to start search from)
IF ERRORLEVEL 1 GOTO BAD
call FIND.bat "" %MyCURRdrive%\D\TOOLS\MYPROGS\FIND\
(in my case, parm2 is the DIR containing the search string DSN)
popd
(revert back to orig Working DIR)
:BAD
(any error code)
call c:\dad\tools\myprogs\pathset.bat D
(revert back to orig PATH)
So, now, all my TEST.BATs run un-changed on each laptop.
Comments anyone? Is there something simpler yet? It's hard to believe
that Windows can't/won't do what IBM did 40 years ago via a simple
JCL statement...perhaps I'm missing something fundamental here?
Did you try the subst command?
http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/subst.mspx?mfr=true
Hhhmmm...wouldn't I still have the same problem? In that example:
subst z: b:\user\betty\forms
the B: appears to still be needed, and that's what I'm trying to avoid.
Where would that B: come from? I mean, how could I get that in there
dynamically so that it doesn't have to be hard-coded anywhere?
You can try this batch file :
@ECHO OFF
FOR %%d in (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 EXIST %%d:\masm32 SET drv=%%d
)
@ECHO ON
SUBST R: %drv%:\masm32
There are plenty of more or less unique identifiers you can use...
@echo off
set thisPC=MyDesktop
echo HOMEDRIVE=%HOMEDRIVE%
echo HOMEPATH=%HOMEPATH%
echo HOMESHARE=%HOMESHARE%
echo LOGONSERVER=%LOGONSERVER%
echo NUMBER_OF_PROCESSORS=%NUMBER_OF_PROCESSORS%
echo OS=%OS%
echo PATH=%PATH%
echo PATHEXT=%PATHEXT%
echo PROCESSOR_ARCHITECTURE=%PROCESSOR_ARCHITECTURE%
echo PROCESSOR_IDENTIFIER=%PROCESSOR_IDENTIFIER%
echo PROCESSOR_LEVEL=%PROCESSOR_LEVEL%
echo PROCESSOR_REVISION=%PROCESSOR_REVISION%
echo PROMPT=%PROMPT%
echo RANDOM=%RANDOM%
echo TIME=%TIME%
echo USERDOMAIN=%USERDOMAIN%
echo USERNAME=%USERNAME%
echo USERPROFILE=%USERPROFILE%
echo WINDIR=%WINDIR%
if %USERNAME%==user (
echo hello user
) else (
echo you are not user
)
if %thisPC%==MyNotebook (
echo hello notebook
) else (
echo must be the desktop
)
I was using USERNAME, but I still had to hard-code the drive.
So, instead of searching for the VOLUME NAME, look for a
unique DIR or DSN to get the drive (snippets):
SET MyCURRdir=D\TOOLS\MYPROGS
IF [%1]==[] GOTO NODIR
SET MyCURRdir=%~1
:NODIR
echo %MyCURRdir%
SET MyCURRdrive=
@ECHO OFF
FOR %%d in (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 EXIST %%d:\%MyCURRdir% SET MyCURRdrive=%%d
)
@ECHO ON
IF [%MyCURRdrive%]==[] GOTO NOTFOUND
set MyCURRdrive=%MyCURRdrive%:
SET PATHSETcurr=%PATH%
path %MyCURRdrive%\D\TOOLS\MYPROGS\FIND;%PATH%
SET MyCURRdir=%MyCURRdrive%\D\TOOLS\MYPROGS\FIND
pushd %MyCURRdir%
IF ERRORLEVEL 1 GOTO BAD2
call FIND.bat "" %MyCURRdrive%\D\TOOLS\MYPROGS\FIND\
popd
:BAD2
path %PATHSETcurr%
GOTO EXIT
:NOTFOUND
echo DIR not found on any DRIVE
:EXIT
don't specify a drive letter, but make the paths root-relative
it's the same way the masm32 include files are typically referenced
\folder\folder\file
otherwise, there are batch tricks to manipulate drive letters and paths
%~d0
will get you the current drive letter with a colon
so, you could assign that to a variable at the beginning
set MyDrive=%~d0
then, to form a full path
MyDrive\folder\folder\file
there are a few other examples in the Bild.bat file that i use to assemble...
http://masm32.com/board/index.php?topic=1770.msg18068 (http://masm32.com/board/index.php?topic=1770.msg18068)
one more thing...
the help for the SET command has a lot of info
at the prompt:
set/?>set.txt
will create a text file to read
do the same with the FOR command
it has several additional %~ tricks
I couldn't get root-relative to work unless I pre-set the drive in
DOS prompt first. However, that %~d0 works PERFECTLY when I call them
manually, tho I still need my program/FOR if I call them from another
.BAT which, in my case, the latter resides on c:! Thankx.
maybe it would help to extract the drive from a full path string
sometimes, the "%~" tricks are only good if the parm is passed on the batch command line
however, you can use some standard string manipulation on any string
so, if you have a full path string, you only need the first letter
@echo off
set MyString=xyzzy
echo %MyString%
set FirstLetter=%MyString:~0,1%
echo %FirstLetter%
results:
xyxxy
x
now, you can tack a colon on there and use it as a drive letter
or - grab 2 characters and hope it already is a colon :P
it depends on where you get the path string, i suppose
but, usually, if there is a drive letter, it is followed by a colon
%cd% always gets you the current path, including a drive letter, colon, and backslash
set DriveLetter=%cd:~0,2%
echo %DriveLetter%
results:
C:
set DriveLetter=%cd:~0,3%
echo %DriveLetter%
results:
C:\
%~d0 works because it is getting the full path of the batch file, and extracting the drive letter only
%0 is the batch file, itself - always a valid parm
...and that seems to be the catch-22. I need a full path, yet I don't have
it since I don't know the drive letter (or, it's variable). The %~d0 works
great to test 1, but when another .BAT calls my TEST.BAT (my daily .BAT
calls all my TEST.BATs, basically to make sure they all still work), I need
something dynamic to determine the drive letter. I guess I'll stick w/my
program/FOR for this since it does the job.
But, thankx for the sub-string manipulation code. That helped me in 1 of
my TEST.BATs to process USERNAME.
give me exact examples of what you want to do
it can probably be done
another approach, altogether.....
use the computer management snap-in to change the drive letter so they match :P
. from a DOS prompt:
C:\Windows\System32>\temp\daily.bat
call FINDVOL.bat "021-IV ,014-I "
echo %~n0 FINDVOL=%MyCURRdrive%
call %MyCURRdrive%\temp\test.bat
The drive letter is variable.
So, all your laptops have the same volume label ?
Andy
No, although I suppose they could, but since they are separate devices,
I'd rather keep them unique. In my case, I supply them both and let my
program match on whatever is mounted.
Unfortunately, that Computer Management/Storage/Disk Management seems
too similar to an old, rather lousy, IBM DOS Mainframe technique in the
70's, when jobs had to assign a hard address (ie: DRIVE LETTER) to a volume.
As an operator back then, this caused conflicts and forced delays.
When we implemented a "new" technique that let the OS assign the hard
address given a VOLSER (ie: VOLUME NAME), we saved hours each night by
allowing us to run multiple jobs at the same time (a rarity back then),
limited only by the # of physical drives we had available to mount volumes.
As I have a few dozen volumes total, I'd rather not go back to a technique
like this (having to manually assign a drive letter). I'd rather let the
OS assign a drive letter and just find where the volume is, then use that
in the full path. I'm just surprised that this is even an issue.
here's what i would do
i would place a text file in the root folder of the drives you want found - it can be an empty file
or, perhaps there is already a unique path\filename that you can use
to illustrate the example, let's use
?:\xyzzy.txt
then, in your batch file....
@echo off
for %%X in (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 exist %%X:\xyzzy.txt set MyDrive=%%X:\
echo %MyDrive%
notice that the list does not include A, B, or C drives
A and B used to be assigned to floppies, and C is usually the boot drive
we can generally assume your drive will not be one of those
on my machine, i placed an empty "xyzzy.txt" file in the root folder of the G: drive
results of the above batch....
G:\
if more than one drive in the list has the file, the highest drive letter will result
that's because the loop completes the list, regardless of the result
here's another (similar) approach
@echo off
for %%X in (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 exist %%X:\temp\test.bat call %%X:\temp\test.bat
this one will CALL the \temp\test.bat file on any and all drive(s) from D-Z that it is found
I am confused as to what exactly is being sought.
Lot of talented batch filers here.
Might try here.
https://groups.google.com/forum/?fromgroups&hl=en#!forum/alt.msdos.batch.nt
FYI; Here's an interesting problem when I use the VOLSER.BAT w/the FOR loop:
SET MyCURRdrive=
FOR %%d in (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 EXIST %%d:%MyCURRdir% SET MyCURRdrive=%%d
)
After I eject a DVD+RW from my drive G, then run this .BAT, I get this CRITICAL STOP: "There is no disk in the drive. Please insert a disk into drive G:".
I can't get around this unless I go into explorer.exe, click on the drive, get
"insert a disc", cancel that, and then re-run the .BAT; the CRITICAL STOP then goes away. I do NOT get this using my own FINDVOL program. Any Comments?
there is probably a way to use CALL to avoid that - let me think on it, a bit :P
deleted
Well, this is kinda what my FINDVOL program does, which doesn't get this
CRITICAL STOP, I think because I use:
MOV NEWMODE,SEM_FAILCRITICALERRORS ; prevent a dialog box for drive failures
; * IE: CD/DVD
INVOKE SetErrorMode,
OFFSET NEWMODE
MOV NEWMODE,EAX ; now is previous mode
Since VOLSER.BAT only shows the drive containing the last DIR/DSN searched,
what I do in my daily .BAT is to call both, VOLSER.BAT and my FINDVOL program.
I then compare the results, kinda to ensure that my program is working properly,
but any differences I find, I use the results of my program:
call VOLSER.bat
set MyCURRdriveV=%MyCURRdrive%
set CloneApplVol="021-IV ,021-V "
IF [%2] == [] GOTO NOADDLVOL
set CloneApplVol="%~2 "
:NOADDLVOL
call FINDVOL.bat %CloneApplVol%
IF [%MyCURRdrive%] == [%MyCURRdriveV%] GOTO SAMEDRIVE3
echo %~n0 %date% %time% drive mis-match (mult VOLs?); using FINDVOL...
:SAMEDRIVE3
set MyCURRdriveV=
But, due to this CRITICAL STOP in the VOLSER.BAT, the daily .BAT hangs.
It's the VOLSER.BAT that I want to fix, or if I'm forced to, to stop
using it. Sorry if I wasn't more specific in my question...
deleted
Using DIR's errorcode ?, look here (http://www.netikka.net/tsneti/info/tscmd053.htm)
EDIT
@ninud
pass that VolumeName from GetVolumeInformation() to variable too, if OP is interested that too ?
interesting link
i was thinking of opening another shell with COMMAND /F
it's an undocumented switch that we used to use with win95/98 :P
when the Abort/Retry/Fail question came up for floppies, it automatically assumed Fail
FYI: I fixed VOLSER.BAT. The 'IF EXIST' was the problem:
IF EXIST %%d:%MyCURRdir% SET MyCURRdrive=%%d
Now I use:
DIR %%d:%MyCURRdir% >nul 2>&1 &&SET MyCURRdrive=%%d
and now, when I eject the DVD+RW, there is no longer a CRITICAL STOP pop-up.
Glad you found a fix. :t
Andy
good job, MtheK :t