Windows api for locking a file - fileapi

When we open a word or an excel file. It gets exclusive lock, so if somebody tries to edit and save the changes, he gets an error stating "file is already used by some other user", he only has the read-only copy of that document which is created in temp folder. So can somebody tell me which api is used by windows for locking a file on open.

See dwShareMode param from CreateFile API. Can give you the file or device cannot shared or not opened until the handle to the file or device is closed. Also see LockFile.

Related

Windows Explorer and Reparse Point Files: keep Explorer from opening my files

I've implemented a user mode program and a Windows file system minifilter that creates a skeleton view of users files for a remote file storage system. It maps the remote files to the local drive. The user mode program creates a reparse tag for each file on the remote system. When a create request (e.g., CreateFile for read) is detected, the minifilter asks the user mode program to download the file. This should only happen when a program wants to open the file for viewing or editing.
But, I'm finding that Windows Explorer is triggering my files to download. I'd like to prevent the Explorer File windows and File Open/Save dialogs from
triggering downloads. And, I also want to display the file thumbnails and file
size.
[Update: I've found I can use Windows sparse files to show my remote
file size in Explorer. ]
Therefore, I have also implemented a Shell Extension, IThumbnailProvider, that downloads a rendition of the file. This provides the file thumbnails.
For my testing, I've registered the IThumbnailProvider for all files (*) and for .jpg files.
I'm seeing two interesting behaviors using a combination of Process Monitor and DebugView (both from SysInternals):
1. If I make my minifilter reject requests to open the file from Explorer, then my IThumbnailProvider is invoked.
2. If I permit open requests from Explorer, I see thumbcache.dll in the call stack trying to open the file and my IThumbnailProvider is not called. It appears that the default thumbnail provider reads the downloaded file and creates the thumbnail.
I must be missing something.
Update: if I use InitializeWithStream instead of InitializeWithFile, it appears my handler is invoked. But, that also triggers a download of the file.
There are many shell extension types which can access to your files. Icon handler can read file to create icon, Info tip handler can read file to create text hint, Data object handler can read file to create clipboard data and so on.
Questions from developer with the same problem: first and second. Solution was to create namespace shell extension. NSE can control all access to your files.

Internet Explorer file download Excel file filename

I have a bespoke application that downloads an Excel file from the network
The Excel file has a macro within the Workbook Open event. I have noticed that if I put the following code in the event
MsgBox Application.ThisWorkbook.Name
I can see that when the file "PWABCD.XLS" is opened from Internet Explorer 8, the messagebox shows "PWABCD(1).XLS". When the same operation is done from Internet Explorer 10, the message box shows "PWABCD.XLS".
Where is the setting that says the file download name should have (1) inserted? Or is there some other conflict that is causing the (1) to be inserted into the filename? I have inherited logic that assumes the (1) will be there and removes it - rather than amend the code to check for the existence of the (1), is there a setting the user can amend?
Many thanks
The (1) is automatically added to the filename if another file with the same name exists in the destination directory. There is no way to avoid this other than testing to see if the file already exists and deleting it if it does.

Why does .MSI file open read-only?

I am attempting to open a .MSI installer package file to modify it. Whenever I try to open it, it opens in read-only mode. I see this with Orca, with InstEd, or when opening the file directly via code:
`MsiOpenDatabase()` (ERROR_OPEN_FAILED with MSIDBOPEN_DIRECT or
MSIDBOPEN_TRANSACT persistence modes).
The file itself does not have the read-only attribute set (in fact, has no attributes set)
I am using an account with Administrators group access
As far as I can tell, no other process has the file open
No installs are in progress or suspended
I can copy the file to another location, and open it read/write there. But the original, I cannot touch
Thanks in advance for your help.
My guess is that this is caused by one of the following factors:
Custom NTFS access rights - defined for the file in its security descriptor
The file might be "blocked" - marked with a special flag after being downloaded via Internet Explorer.
The resolution for the latter is to right click the file and select properties and click the unblock button at the bottom of the property page and pressing OK.
The resolution for custom NTFS rights are done in a similar way by going into the security
tab of the property page for the file, but it is easier just to copy and paste the file and use the fresh copy with the default security.
Found it.
#Glytzhkof, you almost had it but there's a detail I did not know about, and left out. This is a package that lies in a folder under "access protection" by my system's anti-virus program: a filesystem hook that blocks modification of critical system and AV files. Turn off access protection temporarily, and the file is wide open.
Fortunately, one of my teammates had some experience with this, and suggested I try it. Bingo.
Thanks, all.
What I have done to get it working was to create first a backup of the MSI file, and then open that backup. It worked for me
Try to close/kill processes that might interfere, for example:
Other running Install shield instances
Installshield updater
Installshield licensing service
Antivirus

Windows API hook, custom save as file dialog to save directly to webserver via POST

I want to write a custom save as dialog that is hooked into the File -> "Save As" of most Windows program. This custom dialog will allow the user to enter their username, password, destination folder and uploads the file to the web server via a POST. If the user clicks cancel, it will call the original file dialog.
I've been reading up about Windows API hooking and this is vaguely how I think I would approach this:
Intercept "Save As"
Display my custom dialog, return some temporary path on the drive
Let the program write file to the temporary path, assume it calls WINAPI CreateFile(...) for now
Read the temporary file and upload to web server
Clean up temporary file
But I still can't get my head around the steps required to pull this off. Assuming I can intercept the "Save As" and CreateFile function, how do I detect the CreateFile was called from a "Save As" and not just any random file creation? I can think of a hack where I keep track of the time difference of when the File dialog got open and CreateFile got called.
My alternative solution is to use the existing file dialog and create a special folder on the disk, that is constantly monitored. When a file gets written there it will call an external program that uploads the file. I haven't looked into how to do this yet. I suspect this is easier.
UPDATE
As a first baby step, I wrote a .NET task tray application that allows the user to enter their login details and a folder to monitor. Whenever a file gets dropped in there there it will upload to the web server. So far it seems to work. Now I just need to figure out how to add a nice shortcut to the left pane of the file dialog. Once that's done I think I got a solution I'm happy with.
There is no need to hook or patch anything. Create a shell namespace extension that supports IStorage::CreateStream and implements it by returning a stream that POSTs its data to the Web server. The user can then choose to save the file to your namespace extension in order to upload the file.
Hooking the standard save dialog requires you to inject a DLL into every running process and have it replace the import stub of the the Win32 API GetSaveFileName() function in the process's PE header (something anti-virus and anti-malware apps are not likely to be happy about).
Then there is the new-style save dialog that was introduced in Vista using the new IFileSaveDialog COM interface instead of GetSaveFileName(). For that, you would have to uninstall and replace Microsoft's default FileDialog COM object with a custom implementation.
That does not count custom-made save dialogs, which you are not likely to hook.
If, by some miracle, you can hook the dialog and have it return a custom path of your own creation, you don't need to hook CreateFile() itself, Just monitor the folder that you create for your purposes. Place it where it is unlikely that any other app (or user) besides you will write files to. You can create a custom subfolder in the user's or system'ss AppData folder for that purpose. You can use SHGetSpecialFolderPath() and/or SHGetKnownFolderPath() to find those folders.
The tricky part will be detecting when the file is finished being written to and has been closed. You will have to monitor the folder for changes, such as with ReadDirectoryChangesW() or SHChangeNotifyRegister(), and periodically open new/modified files for exclusive access. If a file is still open by someone else, you won't be able to open it yourself. But once you do open it, you can do whatever you want with it.

How to get the actual path of a file in Vista with UAC?

I am calling CreateFile() to create a file in the Program Data directory. I'm using SHGetSpecialFolderPath() to get the dir name.
I have a user with Vista for whom CreateFile() is returning error 5 (Access Denied). It would help if I knew where CreateFile() was actually attempting to create the file so we can check his folder permissions. The problem with Vista (UAC) is, it's not attempting to create the file in the directory I passed in. It could also be in a VirtualStore directory. An added source of confusion is this user is German and although SHGetSpecialFolderPath() is returning "C:\Program Data\blah blah" as the path, I don't think that's actually where the path is. I think German Vista uses the German word for "Program Data". I would like to be able to tell the user "This is the exact path where we are trying to create the file. Check your permissions on this folder."
I know you can get the a path from an open file handle, but in this case the CreateFile() is failing so I don't have an open handle. How can I get Vista to tell me the actual path where it's attempting to create the file?
Fire up Process Monitor and watch what it does:
http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
If with UAC the paths used are not the ones you want, then the redirection is in effect.
To make sure that redirection does not occur, add a manifest to your application which indicates to Vista that your application is properly coded and aware of access restrictions (i.e., you don't write to e.g., HKLM or the programs folder if your app doesn't need admin privileges to run).
But your application should be able to write to the APPDATA folder (if that's what you really use).
Make sure you're using CSIDL_APPDATA and not CSIDL_COMMON_APPDATA (the latter one being accessible only with admin privileges).
To find the real path (the one you would expect) tell the user to type %APPDATA% into the explorer bar (or hit Windows+R, then type %APPDATA%, enter). This will open the explorer on that folder.
My understanding is that ProgramData is used by Vista to write files that were attempting to be written inside C:\Program Files, but failed, since unless you are running the app as Admin you can't write inside program files. Maybe you should try saving your files to the AppData folder under the current user.

Resources