In Windows -- and probably Unix for that matter -- using the chdir() function in a (32-bit) program doesn't change the directory when the program exits. (It does in a 16-bit Windows program.)
Does anybody know how to do that in a Windows 32-bit program?
Uhm... IMHO it's exactly one of the things that the OS must guarantee not to happen. The current dir is a per-process property, a child process usually inherits it from the parent process, but the reverse should not happen (and it doesn't).
To obtain what you want, the parent could actively watch some information (message, file, shared memory...) in which the child process stores the new directory, and then call chdir() with the new value.
As far as I know, Windows' cmd.exe doesn't have any mechanism like that.
Actually, by using code injection techniques (e.g. CreateRemoteThread) on the parent process it could be possible to force it to do something unexpected, but it's a very dirty trick, not at all good neither general.
Win16 was different: there was a single "msdos" state for all the programs, but it was a limitation, not a feature.
It sounds like you're asking one process (your Win32 program) to change the CWD of another process (your shell). As far as I know, this is impossible without the latter process providing an API for such a purpose. The nearest I can come to any sort of reference for this assertion, however, is the following quote from MSDN:
A parent process can directly alter the environment variables of a child process during process creation. This is the only situation when a process can directly change the environment settings of another process.
Well yeah it's true the popular API calls to change directory change it for the process. ... BUT ...
(1.) 16-bit windows programs can change the global directory; probably because they run in the same process as the command.com thing. That's what I've been happily using for years; I assume XP somehow emulates this? ... But now Windows 7 64-bit won't run 16-bit programs anymore! (?)
(2.) Both Windows and Unix "cd" commands can of course change directories for the calling process -- presumably because they are built-in commands of the command shell. But successor Windows shells manage to accomplish this, or at least I hope PowerShell can do that. All built-ins?
(3.) The way I've wound-up doing it is modifying my programs that used to call the API to simply emit "cd \dst\directory" to stdout, then in a procedure do
chdirprogram >t~.bat
call T~.bat
Which works great. And of course the usual point of a change-directory program is to provide the functionality in a batch procedure with a computed destination. Which of course you can do in Unix with Bash etc. variables, but not in Windows batch files, although maybe (?) in the numerous successor Windows procedure things, which I don't want to use. ... Since this functionality is obviously useful, I was hoping someone knew of a sneaky Windows call what'd do it. The explanation that it's somehow wrong for a process to change the directory for a calling process is one of those bogus, "you're not supposed to do that and I won't tell you why" excuses. ... But I guess I'll just stick to my pitiful little batch files.
Are you talking about the SetCurrentDirectory function of Windows API? The article says that the function "changes the current directory for the current process". In for instance Delphi, there is a function ChDir that actually calls this API function.
Related
We are running a Windows .EXE file via a Cygwin script and are encountering performance issues. I have seen various posts about Cygwin performance issues, including this one, one of whose answers delves enough into Cygwin internals to make me think there could be a problem. However, these posts do seem to be more about startup time, tab completion, etc. Before we launch on a benchmarking witch hunt, I was hoping to ask: is there any intrinsic reason why a Windows .EXE could run slower if kicked off from Cygwin vs. BAT?
Not the actual program, no.
Housekeeping and stuff before running the program may vary. Cmd probably calls CreateProcess directly. Cygwin's bash may first do argument parsing, wildcard expansion, fork via Cygwin's slow implementation and call exec with the parsed arguments, which Cygwin has to piece together into a string again to pass to CreateProcess. But in the end, a new process is created which has no ties to its parent anymore. So how fast your program runs entirely depends on that program, not on who launched it.
Is it's possible to detect inside app from where it was run? From cmd/bash or from GUI? Assume that we are working in graphical mode, not in pure console.
Not really, but sort of. Short answer: better not to try, get the user to tell you via an argument, which you can pre-fill in a shortcut.
Long answer:
In both cases, the program is launched in a similar way: the shell application (whether cmd/bash or Windows explorer/whatever gui launcher linux has) call CreateProcess or ShellExecute on Windows or fork+exec on Linux and the way the user executed it gets lost.
However, the process does have a parent ID which might be useful.... but it isn't reliable either for a few reasons: telling if it is a gui or command line shell isn't easy (best you can do is look at the image name) and the parent might terminate as soon as you launch, so there'd be no parent! (Linux gui apps often fork themselves to detach from the terminal. Of course, if you do this you'd probably know, but if you use a library it might happen without you realizing it.)
Well, the fact that I'm going off on parenthetical asides after every sentence shows how unreliable and complicate that is. If you want to try though, looking at your parent process ID before doing any fork/detaching might be helpful.
BTW looking for a parent console isn't very helpful: a Windows GUI subsystem program won't attach to the parent console even if one exists and a Linux GUI program may attach to the controlling tty of the X window manager.
What I'd actually recommend though is passing an argument to your function to tell it how it got started. When you create the GUI shortcut, make it automatically pass the "started by gui" argument to you. Then you can check args for it and react accordingly.
It still isn't perfect, but it is fairly easy to implement and probably good enough - gui launchers would probably use a shortcut anyway and you can pass arguments through them, so the user doesn't need to know about how it is implemented.
Or you could install two programs, one which is convenient from the command line and one which is optimized for the gui environment.
But I think that's the best you can do.
I want to be able to detect whether a given exe was shellex'd programmatically or if it was entered and executed interactively in, say, CMD.EXE.
Is there anything about the way an exe is launched that indicates the mechanism that was used to launch it?
Context: Windows XP, Visual Studio 6 languages.
There might be an easier way, but the only way I can think of is to check the parent process name, which involves a few steps:
Get the ID of the parent process.
Get the handle of the process, using the ID.
Use GetModuleFileNameEx with the handle found (and NULL as the module) to get the executable's name.
Check if the executable's name is cmd.exe or whatever.
Bear in mind that the parent process might already be gone when (or while) you do this check.
Edit:
If your program is a console application, you can also check the console it's running in. If it was run from cmd, it will usually use the same console. So, you can use GetConsoleTitle, for instance, and see if it's "Command Prompt". This might not work on localized or different versions of Windows, but it's easy if you have limitated cases. You can also use GetConsoleWindow and GetWindowThreadProcessId instead of steps 1 and 2.
You can differ between say CMD and Explorer by inspecting the parent process, but you can't tell if it happened due to user action or not. Also AFAIK all ways to launch a process result in the same NtCreateProcess/PspCreateProcess call, so you can't tell which API was used either.
I would like to write a C++ function, on Microsoft Windows, that spawns a process and returns, in addition to the process's termination status, a list of all the files the process read or wrote. It should not require any cooperation from the spawned application.
For example, if the program spawned is the Visual Studio C++ compiler, the function would produce a list containing the source file the compiler opened, all header files it read, and the .OBJ file it created. If it also contained things like .DLL files the program contained, that would be fine. But again, it should work regardless of the program spawned; the compiler is just an example.
A twist: if the process creates subprocesses, I need to monitor their file accesses as well.
A second twist: if the process tries to open a file, I would like to be able to make it wait until I can create that file—and only then let it resume and open the file. (I think this rules out ETW.)
I know this probably sounds like an ingredient for some horrible kludge. But if I can get this working, the end result will be really cool.
A second twist: if the process tries to open a file, I would like to be able to make it wait until I can create that file—and only then let it resume and open the file
You just put yourself into Hack City with that requirement - you're right that ETW would've been a far easier solution, but it also has no way to block the file call.
Basically, here's what you're going to have to do:
Create the process suspended
Create two named pipes in opposite directions whose names are well known (perhaps containing the PID of the process)
Hook LoadModule, and the hook will watch for Kernel32 to get loaded
When Kernel32 gets loaded, hook CreateFileW and CreateFileA - also hook CreateProcessEx and ShellExecute
When your CreateFile hook hits, you write the name to one of the named pipes, then execute a ReadFile on the other one until the parent process signals you to continue.
When your CreateProcessEx hook hits, you get to do the same process all over again from inside the current process (remember that you can't have the parent process do the CreateProcess'ing because it'll mess up inherited handles).
Start the child process.
Keep in mind that you'll be injecting code and making fixups to an in-memory image that may be a different bitness than yours (i.e. your app is 64-bit, but it's starting a 32-bit process), so you'll have to have both x86 and amd64 versions of your shim code to inject. I hope by writing this lengthy diatribe you have convinced yourself that this is actually an awful idea that is very difficult to get right and that people who hook Win32 functions make Windows OS developers sad.
Many Windows apps (like Skype or MSN for instance) don't let you start multiple instances, rather trying to run it a 2nd time just leaves the existing version running.
Is this typically done in some simple way - the start-menu shortcut is a 'wrapper' app around the main app - or is there some registry magic you can do to delegate the problem to Windows itself?
Specifically dealing with Win32 here (unmanaged C++) but happy to hear more general solutions as long as they are workable on Windows XP or later.
EDIT: this seems the best duplicate.
Named Mutex or similar OS-specfic named object. If it exists - app is running.
Lock file somewhere (in temporary directory, etc - create it on program start, remove on program end). Linux software frequently operates this way (some programs store PID in lockfile), but it isn't safe - if you suddenly lose power (electricity cut off), it is possible that lock file won't be deleted.
And you can always enum all running processes and try to find yourself.
There could be more ways to do it, but those are the first ones I could think of.
As far as i remember, there exist system-wide Mutexes. Set Mutex on first launch, if on launch already set, immediately exit.
Use CreateMutex() call an prepend the name with "Global\" should to the trick.
I just check to see if the process is already running: if it's not start the application, if it's already running bring the window to foreground. The check is done in the Main method.
I get the process name with System.Diagnostics.Process.GetCurrentProcess().ProcessName and check if it's already running System.Diagnostics.Process.GetProcessesByName(). If there are more than 1 processes focus the first of them and then exit.