• CreateProcess() randomly changes current directory (old? fixed?)

    From Charlie Gibbs@21:1/5 to All on Tue Nov 29 23:29:14 2022
    When calling CreateProcess() with lpCurrentDirectory set to NULL, the
    child process is supposed to inherit the parent's current directory -
    but I've learned the hard way that occasionally it doesn't. I've
    had several instances where the child's current directory is set to
    something random. The child program then fails because it can't find
    files it's expecting to see in the current directory. Before it shuts
    down it opens a log file in the current directory (wherever that now
    may be), and writes an error message to it; log files have shown up
    all over the disk.

    This doesn't happen very often - but if you have 1000 customers running
    your programs daily, it doesn't take long before anguished phone calls
    start coming in.

    So far the only completely reliable solution I've found is to include
    code in my initialization routines to set the current directory to a
    known value; I call GetModuleFileName() to determine where the program
    loaded from, and set the current directory there. This works, but has
    the disadvantage that my programs cannot run in a directory that is
    different from the one in which their .EXE files live.

    This might be an old bug that has long since been fixed - we had
    a lot of trouble with it back in 2001 and 2002, and my belt-and-
    suspenders solution has been in place ever since. It might be
    safe to remove my fixes now, but we were burned so badly that
    I'm reluctant to take the risk.

    Has anyone else encountered this problem?

    <rant>
    Windows seems to take a cavalier attitude toward the concept of
    "current directory". The GetOpenFileName() and GetSaveFileName()
    APIs will change the current directory if the user goes into a
    different directory while searching for files. The OPENFILENAME
    structure passed to these APIs contains the flag OFN_NOCHANGEDIR,
    whose purpose is to restore the current directory in such cases,
    although I prefer to first call getcwd() and save the current
    directory, then use chdir() to restore it afterwards.
    Since I wrote this code myself, I trust it to be bombproof -
    and should it turn out not to be, I can change it until it is.
    </rant>

    --
    /~\ Charlie Gibbs | Life is perverse.
    \ / <cgibbs@kltpzyxm.invalid> | It can be beautiful -
    X I'm really at ac.dekanfrus | but it won't.
    / \ if you read it the right way. | -- Lily Tomlin

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to Charlie Gibbs on Wed Nov 30 07:29:22 2022
    On Tue, 29 Nov 2022 23:29:14 GMT, Charlie Gibbs wrote:
    When calling CreateProcess() with lpCurrentDirectory set to NULL, the
    child process is supposed to inherit the parent's current directory -
    but I've learned the hard way that occasionally it doesn't. I've
    had several instances where the child's current directory is set to
    something random. The child program then fails because it can't find
    files it's expecting to see in the current directory. Before it shuts
    down it opens a log file in the current directory (wherever that now
    may be), and writes an error message to it; log files have shown up
    all over the disk.

    This doesn't happen very often - but if you have 1000 customers running
    your programs daily, it doesn't take long before anguished phone calls
    start coming in.

    So far the only completely reliable solution I've found is to include
    code in my initialization routines to set the current directory to a
    known value; I call GetModuleFileName() to determine where the program
    loaded from, and set the current directory there. This works, but has
    the disadvantage that my programs cannot run in a directory that is
    different from the one in which their .EXE files live.

    This might be an old bug that has long since been fixed - we had
    a lot of trouble with it back in 2001 and 2002, and my belt-and-
    suspenders solution has been in place ever since. It might be
    safe to remove my fixes now, but we were burned so badly that
    I'm reluctant to take the risk.

    Has anyone else encountered this problem?

    <rant>
    Windows seems to take a cavalier attitude toward the concept of
    "current directory". The GetOpenFileName() and GetSaveFileName()
    APIs will change the current directory if the user goes into a
    different directory while searching for files. The OPENFILENAME
    structure passed to these APIs contains the flag OFN_NOCHANGEDIR,
    whose purpose is to restore the current directory in such cases,
    although I prefer to first call getcwd() and save the current
    directory, then use chdir() to restore it afterwards.
    Since I wrote this code myself, I trust it to be bombproof -
    and should it turn out not to be, I can change it until it is.
    </rant>

    `CreateProcess()` never change the working directory. If it's changed, something must have changed it before `CreateProcess()` is called.

    Like the Open/Save dialog that you've mentioned, which may change the
    working directory depending on user input. User code is not the only one
    which may change the working directory.

    Different thread shouldn't change the working directory - even temporarily, because it will create a chance for other threads to use the wrong working directory. At least not without thread synchronization. Be it user code, or API. Directly or indirectly.

    My suggestion is to debug the launcher process and place breakpoints on
    NTDLL functions which change the working directory.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Charlie Gibbs@21:1/5 to jj4public@outlook.com on Wed Nov 30 01:10:33 2022
    On 2022-11-30, JJ <jj4public@outlook.com> wrote:

    On Tue, 29 Nov 2022 23:29:14 GMT, Charlie Gibbs wrote:

    When calling CreateProcess() with lpCurrentDirectory set to NULL, the
    child process is supposed to inherit the parent's current directory -
    but I've learned the hard way that occasionally it doesn't. I've
    had several instances where the child's current directory is set to
    something random.

    <snip>

    `CreateProcess()` never change the working directory. If it's changed, something must have changed it before `CreateProcess()` is called.

    Like the Open/Save dialog that you've mentioned, which may change the
    working directory depending on user input. User code is not the only one which may change the working directory.

    What makes it hard to diagnose is that it's very infrequent (i.e. highly intermittent), and the directory I get changed to is completely random.

    Different thread shouldn't change the working directory - even temporarily, because it will create a chance for other threads to use the wrong working directory. At least not without thread synchronization. Be it user code, or API. Directly or indirectly.

    The programs in question are single-threaded.

    My suggestion is to debug the launcher process and place breakpoints on
    NTDLL functions which change the working directory.

    I've been thinking about doing this. The trick is to find a consistent location in which I can log the results - an absolute path is probably
    needed - and how to notify the support people should it happen at one
    of our many customer sites. We do have e-mail capability - if I can
    detect that something has gone awry I could probably jam the current
    directory back to where we belong, then trigger our e-mail program.

    And then again, since any further occurrences over the past 20 years
    would have been masked by my workaround, there's no telling whether
    it's ever happened since. Between prorgram maintenance and various
    other upgrades, it might no longer be an issue. But I'll have to
    tread softly.

    --
    /~\ Charlie Gibbs | If your nose runs
    \ / <cgibbs@kltpzyxm.invalid> | and your feet smell,
    X I'm really at ac.dekanfrus | you're built
    / \ if you read it the right way. | umop-apisdn.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)