- "current directory" when calling programs
- Posted by eliben on November 14th, 2007
Hello,
Suppose I want to distribute software that comes with several .exe
files. Consider, for example that my installation dir is "c:\mysoft\"
and its contents:
c:\mysoft\main.exe
c:\mysoft\aux.exe
main.exe is the main program and it calls "aux.exe" from inside to do
some work. Now, if I want to call my program from some outside
directory:
c:\somedir> ..\mysoft\main.exe <file>
I will get the "aux.exe is not recognized as an internal or external
command" error, because main.exe looks for aux.exe in the "current
directory", which is "somedir".
I know of two techniques to tackle this problem:
1) Add "c:\mysoft" to the PATH env var. This way, "aux.exe" will
always be found.
2) Make main.exe check where it was called from, using the argv[0]
argument to main() (in C code). It can see its own path this way, and
try aux.exe from there
My questions:
a) Which of the ways above is recommended?
b) Are there any other methods that I'm not aware of ? I suppose the
same happens when aux.exe is a .dll and main.exe needs to load it, so
there must be other standard solutions.
Thanks in advance,
Eli
- Posted by Alf P. Steinbach on November 14th, 2007
* eliben:
None of them.
(1) is just needless complication.
(2) is not guaranteed to work, first because you're not guaranteed that
the process' command line includes the path of the executable in the
command part, and second because what you get as main() arguments in C
depend on the C runtime library version you linked with.
You can use the Windows API function call GetModuleFileName(0) (if I
recall the name correctly) to obtain the path of the executable.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
- Posted by Charlie Gibbs on November 14th, 2007
In article <1195014376.785511.121050@o38g2000hse.googlegroups .com>,
eliben@gmail.com (eliben) writes:
Usually. However, I've found that occasionally Windows will pick
some random directory to set as the "current directory" when a
program runs. In your case, even if you're in \mysoft when you
run main.exe, there's no assurance that main.exe will have \mysoft
as its current directory. It doesn't happen often, but when your
package is running several times a day at a couple of thousand
sites, a low probability of strange behaviour still translates
into many headaches for the support staff.
I've come to the conclusion that when a program begins executing,
it cannot depend on the "current directory" being anything predictable,
or even sane.
My solution (which I find repulsive but effective) is to use
GetModuleFileName() to find out which directory my program
loaded from, then use chdir() to jam my current directory to
the directory from which my program loaded. It's ugly, because
it doesn't allow the program to run in any directory other than
the one in which it lives - but at least I can predict where
it'll be, and for my package I want to be in the .exe's directory
anyway.
You could probably use a variant of this. In main.exe, call
GetModuleFileName(). Replace "main.exe" at the end of the
result string with "aux.exe", and use that to call your
auxiliary program. That ought to work whatever your current
directory might be.
Since you're talking about using argv[0] I presume you're writing
a console program. I use GetModuleFileName() instead because it
works for both console and GUI programs.
I'd avoid polluting the PATH variable for something like this.
--
/~\ cgibbs@kltpzyxm.invalid (Charlie Gibbs)
\ / I'm really at ac.dekanfrus if you read it the right way.
X Top-posted messages will probably be ignored. See RFC1855.
/ \ HTML will DEFINITELY be ignored. Join the ASCII ribbon campaign!
- Posted by Christian ASTOR on November 14th, 2007
eliben wrote:
GetModuleFileName() (+ _splitpath())
- Posted by eliben on November 14th, 2007
However, is there any reason for argv[0] not to work as well as
GetModuleFileName ? I'm quite concerned with platform portability
here, and would like the solution to work on Unix-es as well.
Does anyone know of the best way to achieve this on Unix ?
Eli
- Posted by Alf P. Steinbach on November 14th, 2007
* eliben:
See my reply else-thread.
Didn't you read it?
There may be something in the Boost filesystem.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
- Posted by Grzegorz Wróbel on November 14th, 2007
eliben wrote:
On all unixes I ever worked on argv[0] returned filename only. Older
version of Windows (win9x) was the only systems that returned filename
with full path for me (which I always found quite annoying). On nt
systems it's filename only too.
It probably depends how the shell launches your exe so you can't rely on
argv[0]. Use GetModuleFilename() API instead as suggested by others.
comp.os.ms-windows.programmer.win32 is a great place to ask 
--
Grzegorz Wróbel
http://www.4neurons.com/
677265676F727940346E6575726F6E732E636F6D
- Posted by Richard Russell on November 14th, 2007
On Nov 14, 5:49 am, "Charlie Gibbs" <cgi...@kltpzyxm.invalid> wrote:
I see nothing repulsive about using GetModuleFileName to find the
directory from which your program was loaded, but why do you then use
it to change the Current Directory? Far better simply to use it to
provide fully-qualified paths for those files your program needs to
access, as you later describe.
The Current Directory is far too useful to be overridden as soon as
your program runs. When your program is launched from a shortcut
(e.g. on the desktop) the Current Directory is determined by the
shortcut's 'Start in' property, and hence is selectable by the user.
This can be handy in, for example, providing two shortcuts to the same
application which differ in the Current Directory selected. I've also
used it as a convenient way of allowing the user to choose, say, what
directory should be used to store data files; a sort of poor man's
registry setting!
Not predictable, no - the usefulness of the Current Directory would be
much reduced if it was 'predictable'. But sane? In my experience the
Current Directory is always sensible. When run from a shortcut it's
as specified in the 'Start in' property; when run using ShellExecute
it's as specified in the 'lpDirectory' parameter; when run from a
command prompt it's the current directory being used by CMD.EXE etc.
The Current Directory can provide valuable information to a program,
much as the command-line parameters can. Don't throw that information
away unnecessarily.
Richard.
http://www.rtrussell.co.uk/
To reply by email change 'news' to my forename.
- Posted by Scott Seligman on November 14th, 2007
eliben <eliben@gmail.com> wrote:
Neither. Option #1 is really rude to do, and won't guarantee that the
aux.exe you want is the one that's called. Option #2 also won't always
work. Argv[0] is the executable as it's called. This may or may not
include a path, or it could include some complicated relative pathname.
Use GetModuleFileName to get the fully qualified path for your module,
then use PathRemoveFileSpec to strip off the file name.
When one uses LoadLibrary() to load a DLL, the system hides a lot of
this trouble for you by automatically searching you're executable's
path first, then the current directory, then the system directory,
then the 16-bit system directory, then the windows directory, then any
directories in the PATH environment variable. (This search order can be
different depending on the OS version and a few other variables)
--
--------- Scott Seligman <scott at <firstname> and michelle dot net> ---------
Anger is the most useless emotion, .. destructive to the mind and
hurtful of the heart.
-- Henchick in Dark Tower, Song of Susannah by Stephen King
- Posted by Charlie Gibbs on November 14th, 2007
In article <1195062865.470845.256800@k79g2000hse.googlegroups .com>,
news@rtrussell.co.uk (Richard Russell) writes:
That's not the repulsive part.
That's the repulsive part.
Now that's an interesting thought. Alas, I'd have to find and change
the open routines for every single file in all my programs, which is
an awful lot of code. (Also, it would preclude moving the programs
somewhere else on the path, but I can't do that now anyway.)
As true as this may be, I've found that the situation is a lot uglier
when my program is launched by another program.
Generally, that's true. But occasionally, as I've discovered the
hard way, it's not. If my program starts in the wrong directory,
it gets upset about not being able to find its files, and spits
out log messages. My log routine opens a log file (in the current
directory) for append, writes the message it's been given, then
closes the log file immediately to guarantee that the log is up
to date at all times. I've found log messages in random directories
all over the disk. I'm using CreateProcess() with lpCurrentDirectory
set to NULL, which according to the documentation is supposed to
make the new process inherit the calling process's current drive
and directory. Apparently it ain't necessarily so.
Believe me, I wish I didn't have to. I'm the first to agree that it
would make life so much easier. But I've been burned once too often,
and if my method, as horrible as it is, stops the anguished calls from
customers, I'll hold my nose and use it. If there was any way that
I could guarantee that the current directory was what I expect it to
be (typically, the same as the current directory of the program which
calls mine), then I'd gladly let it stand. Unfortunately, the current
directory gets scrambled relatively infrequently - and as with any
intermittent problem, even if it doesn't appear for a while, you never
_really_ know whether it's gone away for good or is just waiting until
your back is turned. Unless I can come up with some definite reason
why this is happening to me and how to avoid it, it's just not worth
the risk to mess with a working, if ugly, solution.
I'd welcome suggestions as to
--
/~\ cgibbs@kltpzyxm.invalid (Charlie Gibbs)
\ / I'm really at ac.dekanfrus if you read it the right way.
X Top-posted messages will probably be ignored. See RFC1855.
/ \ HTML will DEFINITELY be ignored. Join the ASCII ribbon campaign!
- Posted by Richard Russell on November 14th, 2007
On Nov 14, 7:33 pm, "Charlie Gibbs" <cgi...@kltpzyxm.invalid> wrote:
Do you know how the program calls yours? If it uses ShellExecute (or
ShellExecuteEx) then the current directory you receive should be that
specified as 'lpDirectory'. The docs for ShellExecute don't seem to
allow for this being empty or NULL, but ShellExecuteEx does permit
lpDirectory to be "not specified" (whatever that's supposed to mean)
in which case "the current directory is used as the working
directory".
If your program is called using CreateProcess (and friends) then the
'lpCurrentDirectory' parameter should determine what you receive.
This time the docs are a bit more precise: "If this parameter is NULL,
the new process will have the same current drive and directory as the
calling process".
Richard.
http://www.rtrussell.co.uk/
To reply by email change 'news' to my forename.
- Posted by Charlie Gibbs on November 16th, 2007
In article <1195073606.100906.293130@19g2000hsx.googlegroups. com>,
news@rtrussell.co.uk (Richard Russell) writes:
So it says. I wrote both caller and callee, and everything uses
CreateProcess() with lpCurrentDirectory set to NULL. And most of
the time it works fine. But 99.9% reliability just isn't enough
when you're running 24/7 at a couple of thousand installations.
This might be something that's been improved lately; I first noticed
the problem on Win95 systems. Most (but not all) of our customers
are now running Win2K or later - but even if the problem was fixed,
we're not big enough to force everyone to upgrade.
Maybe someday when the last vestiges of Win9x have disappeared,
I'll try again. But I'm busy enough chasing down other bugs and
quirks (some mine, many belonging to various third-party vendors)
that I'm content to fall back on the old rule: If it ain't broke,
don't fix it.
Still, it would be nice to hear whether anyone else has ever
encountered this problem, and whether they managed to come up
with a more satisfactory fix.
--
/~\ cgibbs@kltpzyxm.invalid (Charlie Gibbs)
\ / I'm really at ac.dekanfrus if you read it the right way.
X Top-posted messages will probably be ignored. See RFC1855.
/ \ HTML will DEFINITELY be ignored. Join the ASCII ribbon campaign!