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

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.

Related

Directory picker dialog in WebExtension

From a Firefox add-on implemented as a WebExtension, I'd like to let the user choose a local directory, if possible with the standard directory picker dialog (a variant of the "open file" dialog).
Can this be done from a WebExtension? If so, how?
(In regular JavaScript/HTML on a website, it's not possible for security reasons. See e.g. Select directory path in JavaScript. But as an Add-on should be somewhat trusted by the user, I wonder whether it's possible there.)
Context: I'd like to make a simple bulk downloader, that lets the user choose a target directory for multiple to-be-downloaded files rather than just throwing all of them into the default Downloads folder, but without showing the "Save as" dialog for each individual download.
As far as I'm aware, WebExtensions can't write to arbitrary folders even with user intervention.
However, you can partially achieve your requirement if you accept to use a subfolder inside the default donwloads folder.
browser.downloads API allows you to put a "suggested filename" that contains a folder in it. It can only be a relative path, and it's relative to the default folder.
If you're initiating the download yourself:
function dowloadToFolder(url, name, subfolder) {
browser.downloads.download({
url: url,
filename: `${subfolder}/${name}`
});
}
If you don't know the final name, or the user initiates the download, sadly Firefox does not have an equivalent of Chrome's onDeterminingFilename event. But for a bulk downloader you should be the one initiating it, and not knowing what filename the server will report can in principle be checked with a HEAD request before the download (haven't tested).

How to hide the preview window in windows explorer?

I am making a batch file to password protect a hidden folder.
How can I make it so the user cant view the preview window at the side, since the preview window allows them to see the password that is set in the .bat file.
To make the code of your batch file both hidden and un-editable, the best option is to convert it to an exe. I would recommend you use this bat-to-exe converter.
Also FYI, making a folder hidden is a rather ineffective protection step that only works against layman tech users. Perhaps encrypting the folder may be a better solution for you.

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.

Display PDF file in LocalState folder in Windows 8 app in Cordova

My application downloads a PDF and stores it in the LocalState folder for my Windows 8 app.
I have a link within the app that I would like to show the PDF when the user clicks it.
I've tried displaying it using ms-appdata:///local/pdfs/filename.pdf in a window.open call and I also tried using the InAppBrowser plugin within cordova with no luck. Additionally, I've tried the following:
var uri = new Windows.Foundation.Uri('ms-appdata:///local/pdfs/filename.pdf');
var file = Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri);
Windows.System.Launcher.launchFileAsync(file).done();
I know the file exists as I'm getting a file result back. Just not sure how to allow the user to view it.
By design, the local appdata folder on Windows is accessible only to that app, or to full-trust desktop applications (and this is probably true of similar sandboxed locations on other platforms). As a result, a Windows Store app that gets launched with Launcher.launchFileAsync won't be able access that location (nor can a webview process, which is also sandboxed). If a desktop application gets launched, on the other hand, it probably can access the file, but you can't tell ahead of time if that's the case. Bottom line is that local appdata isn't a good location for letting other apps get at the file.
You'll need to save the file in another location that is accessible to other apps. There are two approaches here, both of which will require a little user interaction to select a location, so they can place the PDFs anywhere they want:
Have the user select a save folder for your app, which they can do once. You would invoke the FolderPicker for this purpose, and save the selected folder in the FutureAccessList. This way you can have the user select the save folder, which grants you consent to save there, and by saving it in the FutureAccessList you can retrieve it in subsequent sessions without having to ask the user again. Refer to the File Picker Sample and the File Access Sample for more.
Have the user select a save location for each individual file, using the FilePicker (see the same sample), and you can also use the access cache to save permissions to those individual locations if you need them later.
There might be Cordova plugins that work with these APIs too, but I haven't checked. Either way, once the file is in an accessible location, launching the file should work just fine.
As an alternate solution, you could consider rendering the PDFs directly in your app. Windows has an API for this in Windows.Data.Pdf, with an associated sample. There might be a plugin or other JS libraries that could also work for this.

Can the last opened file location be directly altered?

As I understand it, when a file open dialog box (such as GetOpenFileName) is used, Windows will automatically remember where the last file was that was opened by the program, and Windows remembers these locations separately for each program. Is there a way to directly alter this, in order to cause the file picking dialog for program X to start in C:\Example\Directory?
I'm attempting to automate a program which has been programmed to work only through a GUI, and I don't have any access to the internals of this program (such as being able to alter how it calls the file picker). Instead, I'm using a mouse macro (via AutoHotkey). If I can be completely sure that the file picker will start in a particular place, I should be able to automate the rest with mouse clicks.
If you had access to the source code, I'd suggest you just change the lpstrInitialDir property of the OPENFILENAME passed to GetOpenFileName().
Outside of that, you'll want to change the registry keys for the MRUs:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32
What might make more sense, and might fix the issue you're having, is also changing the Working Directory so that the default location isn't "My Documents", if you're experiencing that.
Depending on the operating system, the results vary:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839%28v=vs.85%29.aspx

Resources