Win32 current directory, locking & shell integration - windows

In Win32, your main thread's current working directory is set to the location the executable was launched from. My problem is that even after a call to SetCurrentDirectory() to somewhere else, the process apparently still has a filesystem object referencing this initial startup directory (verifiable with a tool like Process Explorer) - which means this director cannot be deleted by the process.
Does anybody here know of a not-too-hacky solution? I'm specifically running into the problem with a program that integrates with explorer (adding a verb to HKCR\Directory\shell registry key), I need to process files in a right-clicked directory and the remove the source directory, which is impossible because the initial working directory is set to, you guessed it, the right-clicked directory.
EDIT: I'll go for the "use helper launch-from-sane-directory" approach. It might not be super elegant, but it will work and doesn't require any nasty hacks.

Your easiest solution may be to just spawn a little helper process that runs in whatever directory you specify (c:\, e.g.) and then just exit and let it do its thing. It may need to be synchronized with a mutex, or perhaps just retry two or three times on a timer...
I had another thought: You may be able to use CreateFile() with FILE_FLAG_DELETE_ON_CLOSE. Then it should go away when everyone lets go of it, but only if it was opened with FILE_SHARE_DELETE.

Related

How can an empty directory be in use and how do I do it on Windows?

On Windows I have an empty directory which I cannot delete because it is "in use". After restarting, I can delete this directory. This happens occasionally, and it confuses me.
I am quite familiar with the Win32 API, but I have no idea what it means for an empty directory to be "in use". (And yes, I have hidden files and folders set to visible.)
How do I make this happen myself? What Win32 API calls should I make to make an empty directory of my choice "in use"?
Somebody has a open handle to the directory. Usually by SetCurrentDirectory, or the current directory in cmd.exe or sometimes by CreateFile.
Use the handle search in Process Explorer to find open handles to a specific directory.

issues adding components to vb6 after registering them

I'm having issues with a few .ocx files in vb6. I have 2 components registered but when I attempted to add both into my project it says that I need to register them. I have tried copying new files into the sysWOW64 folders and still it does not work.
This occasionally happens when there is some corruption and conflict in the registry. One way to fix this is to place the two items in a folder within the project and add them by manually going to the reference and selecting that local copy, it will automatically register it as a new object and often (although not always) will fix the corruption by tagging the new path and it often resolves the issue you are facing. The only problem is that in the future projects, you may need to repeat the process or have access to the items.
The cleaner approach is to find all instances of the files on the system by doing an advanced search and finding ALL COPIES of them on the system, often they are all over the place. Once you have those paths, you need to regsvr32 /u <filepath.filename> each one to clean remove them from the registry and then place them in a common area and then register them from ONE location using regsvr32 <filepath.filename> and now things should work fairly cleanly.
Easiest way to find all instances on your machine (at least for me) is to simple go to your command prompt (if using more recent than XP, then as administrator) and then simply type:
C:
cd\
dir /s <filename.ext> > c:\files.txt
and wait until its done, at that point you open that file and it should give you all the paths to the files you need and you can easily turn the text file into a batch file by adding the commands you need to unreg and run it, voila, quick and fairly painless. If at anytime you unreg and it whines about it not being registered or can't do it, don't worry, just acknowledge and move on. Some OCX and DLL don't have registration entry points. If you register and it complains saying it can't do it, then you pretty much have no choice but to it the way I mentioned at the very beginning, by direct linking in your reference and having it drop into your project.
Final note, unless they are 64 bit compatible, you don't need and often shouldn't put them in the WOW system folder but rather system and system32 folders depending on version control and binary control of the original OCX.

How to let Windows know that a file is "being used" by my application?

I'm making a simple VB.net application, which basically asks the user for multiple files and later it will need to access the selected files and modify them.
Right now, I'm saving the full paths of the selected files, and in the future, the application will iterate through each path, open the file from such path, and modify it.
The problem with that is that the user could select a file (so the full path is saved) and then they delete or move the file before my application modifies it.
Normally, I'd throw an error saying "File not found", but I'm under the impression that Windows had a feature that would disallow you from deleting/moving/renaming a file because "a program was using it" - which is a feature that would fit way better for my application.
I'm not very advanced with VB.NET, but I suppose that if I "open" a file using my application (with some IO thing), the feature I mentioned earlier would indeed trigger and the user would be unable to modify the file because it is "opened" by my application.
However, since my only desire is to "reserve" files, it seems to be quite wasteful to actually open them when I don't really need to (yet). Is there a way to tell Windows I need a certain file to be intact?
Opening files (with specifying desired sharing mode) is the way to do that.
I don't believe there is anything really wrong with opening multiple files (also you still will not be able to do anything for cases like removing of removable drive). In old times there were restrictions on number of opened files per process, but I it no longer practical limitation - Pushing the Limits of Windows: Handles
There is an easy solution: open each file in exclusive mode.
It should look like this:
Sub test()
Dim FS = System.IO.File.Open("path", IO.FileMode.Open, IO.FileAccess.ReadWrite, IO.FileShare.None)
End Sub
But beware: You have opened a file handle and if you code responsible for closing files fails without terminating the application files will still be locked for very long (till app shuts down).
You can use a using clause or a try/catch/finally clause - I don't know enough about your program to recommend anyone.

How to get a process exclusive lock on a folder in Windows?

Is it possible to lock a directory in Windows so as to ensure that no other process is reading or modifying files inside the directory for the duration of the lock, while at the same time allowing the process with the lock to modify and move files and directory itself freely?
This is not a real answer, but as a workaround:
Move the directory to a subdirectory specific to your application, which is on the same volume.
Advantages:
Prevents users and other programs from modifying the file at the old location, as the files will no longer be there
Importantly, will fail if a process already has a file open within that directory, thus ensuring that the "acquired" lock is indeed "exclusive"
Disadvantages:
It's a hack
The software will need to be adapted to work with the directory at a different path than where it was initially
Users and programs attempting to access the files will encounter unusual behavior or errors ("Path not found" instead of "Access denied")
Does not protect against programs that may poke into your application-specific subdirectory
Will leave the directory "locked" (moved to a location the user probably can't find) if your program crashes while the "lock" is "held"

Renaming A Running Process' File Image On Windows

I have a Windows service application on Vista SP1 and I've found that users are renaming its executable file (while it's running) and then rebooting, thus causing it to fail to start on next bootup because the service manager can no longer find the exe file since it's been renamed.
I seem to recall that with older versions of Windows you couldn't do this because the OS placed a lock on the file. Even with Vista SP1 I still cannot copy over the existing file when it's running - Windows reports that the file is in use - makes sense. So why should I be allowed to rename it? What happens if Windows needs to page in a new code page from the exe but the file has been renamed since it was started? I ran Process Monitor while renaming the exe file, etc, but Process Mon didn't report anything strange and just logged changing the filename like any other file.
Does anyone know what's going on here behind the scenes? It's seem counter intuitive that Windows would allow a running process' filename (or its dependent DLLs) to be changed. What am I missing here?
your concept is wrong ... the filename is not the center of the file-io universe ... the handle to the open file is. the file is not moved to a different section of disk when you rename it, it's still in the same place and the part of the disk the internal data structure for the open file is still pointing to the same place. bottom line is that your observations are correct. you can rename a running program without causing problems. you can create a new file with the same name as the running program once you've renamed it. this is actually useful behavior if you want to update software while the software is running.
As long as the file is still there, Windows can still read from it - it's the underlying file that matters, not its name.
I can happily rename running executables on my XP machine.
The OS keeps an open handle to the .exe file,. Renaming the file simply changes some filesystem metadata about the file, without invalidating open handles. So when the OS goes to page in more code, it just uses the file handle it already has open.
Replacing the file (writing over its contents) is another matter entirely, and I'm guessing the OS opens with the FILE_SHARE_WRITE flag unset, so no other processes can write to the .exe file.
Might be a stupid question but, why do users have access to rename the file if they are not suppose to rename the file? But yeah, it's allowed because, as the good answers point out, the open handle to the file isn't lost until the application exits. And there are some uses for it as well, even though I'm not convinced updating an application by renaming its file is a good practice.
You might consider having your service listen to changes to the directory that your service is installed in. If it detects a rename, then it could rename itself back to what it's supposed to be.
There are two aspects to the notion of file here:
The data on the disk - that's the actual file.
The file-name (could be several or none) which you can give that data - called directory entries.
What you are renaming is the directory entry, which still references the same data. Windows doesn't care about your doing so, as it still can access the data when it needs to. The running process is mapped to the data, not the name.

Resources