SETENVIRON doesn't persist outside program

DOS specific questions.
Post Reply
Black_Magic
Posts: 3
Joined: Mar 16, 2017 17:15

SETENVIRON doesn't persist outside program

Post by Black_Magic »

I am on FREEDOS 0.82, using FreeBASIC 1.05

I have a program that I want to set two environment variables, then come out to the console/prompt (exit) and have those persist for use in a batch file... however this is not happening.

Code: Select all

IF RunMode = "B" THEN
	ReturnCode = 0
	ReturnCode = SETENVIRON( "CMOSPATH=" & SavePath )
	ReturnCode = SETENVIRON( "CMOSNAME=" & SysName & ".SAV" )
	
	IF ReturnCode = 0 THEN
		PRINT " The environment variable CMOSPATH is: "
		PRINT TAB(8); ENVIRON( "CMOSPATH" )
		PRINT
		PRINT " The environment variable CMOSNAME is: "
		PRINT TAB(8); ENVIRON( "CMOSNAME" )
		PRINT
		PRINT "These may not exist yet! You may need to create the folder"
		QUIT(0, Verbosity, BeginDir)
	ELSE
		PRINT "Unable to create environment variables"
		QUIT(15, Verbosity, BeginDir)
	END IF
END IF
The above code is a snippet - the program compiles, and I see what is expected on screen when this code is executed, but when the program exits to the prompt...
  • "SET" shows the environment variables that existed before running the program and not the two new ones.
    Setting the two variables to something
    Running the program,
    Issuing the "SET" command
    ... shows that they were not modified.
In the code, I set two environment variables - and then read them back out of the environment - and they show up fine?!

Any ideas?
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: SETENVIRON doesn't persist outside program

Post by MrSwiss »

Black_Magic wrote:Any ideas?
Seems logical, because you're settings are done, in a "temporary" command interpreter.
Why "temporary" ? ... because it's opened by your Program, running in the "main instance"
of command (DOS specific).

However, what is preventing you, to set them inside the *batch-job* itself?
Alternative:
call the batch-job, after setting environment, from within your program, thereafter quit it.
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: SETENVIRON doesn't persist outside program

Post by marcov »

The problem is that every launched program gets a copy of its parents environment. You can change the copy, but it will only propagate to programs that you call.

However under plain dos, you can access the parents environment, the so called master environment. IIRC you had to walk the PSP up to the parent. Search the web for master enviroment, there were a lot of examples back then when dos was still alive.
Black_Magic
Posts: 3
Joined: Mar 16, 2017 17:15

Re: SETENVIRON doesn't persist outside program

Post by Black_Magic »

MrSwiss wrote:However, what is preventing you, to set them inside the *batch-job* itself?
Because my whole point is to probe the system (Motherboard/BIOS) to get some information, take that information and process it into something useful, set that data in the environment for use later in the batch file that calls this program.
If the information would always be the same for our purposes - your suggestion is the path I'd take.

My patience for 2 hour long phone calls walking people people through their BIOS settings after battery failure is not what it used to be.
Black_Magic
Posts: 3
Joined: Mar 16, 2017 17:15

Re: SETENVIRON doesn't persist outside program

Post by Black_Magic »

marcov wrote:The problem is that every launched program gets a copy of its parents environment. You can change the copy, but it will only propagate to programs that you call.
Ahh - I was suspicious of that given the observations. I thought that only happened if I used "shell" or the like to run another instance of the command interpreter.
marcov wrote:However under plain dos, you can access the parents environment, the so called master environment. IIRC you had to walk the PSP up to the parent. Search the web for master enviroment, there were a lot of examples back then when dos was still alive.
Good pointer - I didn't have the words to know what I was looking for... came across this which appears promising.
http://www.piclist.com/techref/dos/pss.htm
xlucas
Posts: 334
Joined: May 09, 2014 21:19
Location: Argentina

Re: SETENVIRON doesn't persist outside program

Post by xlucas »

Oh... I'm a few months late... Hopefully my reply will still be useful to you, or to somebody else.
I know two ways in which you can manage to change the master environment variables. One is not exactly the "right way" of doing it, but ends up being safer and relatively easier. I'll start with the other one, which one could say is the "right way", though it involves some risks:

Whenever a DOS program is run, memory for the code is allocated at a segment start. Another memory block is allocated too for the program environment and it is inside that memory block that you will find the variables. You don't want your currently running program variables, though. You want the ones that belong to the command interpreter when it first loaded. So what you should do is probe the whole DOS memory block by block and see who owns each block. Once you find one owned by COMMAND.COM that looks like an environment block, that's the one. Because FBC compiles 32 bit DPMI based programs, you can't just access DOS memory directly. You have to use DPMI functions to do it. I honestly don't know what DPMI functions you have to use to be able to modify already-allocated DOS memory. You can read the DPMI docs to find out or you may want to write a small real-mode program (in QB, for example) to do the dirty work and call it from your main FB program if you want to do something bigger. Once you are able to modify the first 640K of memory freely, look for the first MCB (Memory Control Block) and go one by one. See here: http://helppc.netcore2k.net/table/mcb. The blocks that contain a program will typically start with the bytes CDh 20h (int 20h instruction). Environment blocks will begin with text and you'll recognise the variables. The idea is that you'll write on top of the contents. You can't write past the end of the memory block!! So you can't give a variable a value longer than it had before unless you drop another variable. There is a chance you just won't find the block because some DOS's may erase the COMMAND.COM name from the block by filling it with zeroes (for security?), in which case, you'll have to guess.

Now, my recommendation and easy trick, but still requiring some DOS hocus pocus is that you instead modify the keyboard buffer. Sounds like nothing to do with it, but here's the thing: your program was likely invoked from the command line. The keyboard buffer is located at 0040:001A. The first two words are the head and tail offsets of the buffer, which is circular. Next, at 0040:003E, there's the actuale keys pending (32 bytes, that is 16 keys. Each key has a scancode and ASCII code). If you play with this a little, you'll see how it works. Try in real mode with QB and read the memory while you type and then when InKey is called and the buffer is flushed. If you fill the buffer with something like "x.bat" + Chr(13) (I believe you can leave the scancodes at zero) and properly set the head and tail, when your program exits, COMMAND.COM will read the keys from standard input and will believe this command was typed. If before exit, you creat a file called "x.bat" and write something like "set myvar=myvalue" in it, this variable will be assigned by COMMAND.COM and therefore, will remain in memory. It's dirty, but works. This same trick is useful when calling other programs without keeping your code in precious conventional memory.
Post Reply