News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Using MASM32 to assign a PATH/DIR by VOLUME NAME over DRIVE LETTER

Started by MtheK, August 03, 2013, 04:16:25 AM

Previous topic - Next topic

MtheK

  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?


Vortex

Did you try the subst command?

http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/subst.mspx?mfr=true

MtheK

  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?


Vortex

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

jj2007

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
)

MtheK

  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

dedndave

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

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

MtheK

  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.

dedndave

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

MtheK

...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.

dedndave

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

MtheK

. 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.

Magnum

Take care,
                   Andy

Ubuntu-mate-18.04-desktop-amd64

http://www.goodnewsnetwork.org

MtheK

  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.

dedndave

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