Preview handler dll permissions issue - winapi

I'm creating a preview handler dll for a custom graphics file type associated with an application I've developed. For various reasons the preview handler dll is not able to render the graphic for the preview itself. Instead I'm attempting to do it in the following way.
My graphics application associated with the file has been modified to accept specific command line parameters (file path, width, height). With these parameters the application loads the file, renders an image and saves it as a .png file in the user's AppData/Roaming folder and then terminates. This works fine if I call the application from the command line with valid parameters. The .png is created as expected.
When the preview handler is run it calls the application with command line parameters for the file being previewed and dimensions of the preview pane. It does this using the windows function CreateProcess and waits for the application to terminate before continuing.
The preview handler then loads the .png file and draws it to the preview pane.
The problem I'm experiencing is in the second step. The preview handler calls the application but the application gives an error that it is unable to save the .png file ("Cannot create file. Access is denied"). It seems that the application is being run with less permissions when executed by the preview handler than when I run it myself from the command line.
I have tried changing the save location of the file such as user's AppData/Local the shared ProgramData folder and the application's location, but all give the same result. I've also tried setting various CreationFlags in the call to CreateProcess, but none of them help.
Does anyone know why the application doesn't have permissions to save a file when called from a preview handler and is there anything I can do to get it to work? I realise that this is an unusual way of implementing a preview handler, but it's the easiest way without porting a lot of code. Another advantage is that I'm not replicating the rendering code in the main application and the preview handler, which means that the preview handler can be much smaller.
Note that I'm running on Windows 10.

Does anyone know why the application doesn't have permissions to save a file when called from a preview handler and is there anything I can do to get it to work?
Per the documentation:
Preview Handlers and Shell Preview Host
Preview handlers are called when an item is selected to show a lightweight, rich, read-only preview of the file's contents in the view's reading pane. This is done without launching the file's associated application.
...
By default, preview handlers run in a low integrity level (IL) process for security reasons. You can optionally disable running as a low IL process by setting the following value in the registry. However, it is not recommended to do so. Systems could eventually be configured to reject any process that is not low IL.
HKEY_CLASSES_ROOT
   CLSID
      {YOUR HANDLER'S CLSID}
         DisableLowILProcessIsolation
Another advantage is that I'm not replicating the rendering code in the main application and the preview handler, which means that the preview handler can be much smaller.
I would suggest moving the rendering code into a DLL. Export a function that takes a file name/pidl/stream and a target HDC as parameters. The function can read from the file and draw to the HDC as needed. The main app and the preview handler can then share the DLL, calling the function when needed to render the file directly to their respective UIs. You won't need to create a temp .PNG file at all.

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.

Determining if currently renaming a file in Windows Explorer

I am trying to check a Windows Explorer view to see if a file name is currently being renamed / edited when typing.
I have a system hook installed that monitors the keyboard for specific keystrokes and fires certain events. This is done in this manner:
If the keyboard hook sees the key pressed it fires a message to another thread and continue processing other system hooks.
Other thread receives the message and checks to see if an Explorer window is active and gets the interface to the IFolderView2.
Call IFolderView2::GetFocusedItem() to get the focused item in the folder view.
Check if the focused item is being renamed / is in edit mode (SVSI_EDIT) using IFolderView2:: GetSelectionState() - this is the part that fails
If not in rename mode perform an action on that file.
I've tried everything on Windows 7 but the SVSI_EDIT flag (0x00000002 specifically) is never returned. It's always (SVSI_FOCUSED | SVSI_SELECT) regardless of if the file is being renamed. Setting the SVSI_EDIT flag with works with IFolderView::SelectItem with the flag puts it into rename mode but I want to determine if it's in this mode already.
This has only been tested on Windows 7 x64 so far.
Does anyone know a way to determine if Explorer / the IFolderView etc. is currently in the rename file state? Any sneaky method will do if it's not possible through these interfaces.
If one file in in renaming mode, Windows will create a EDIT control at the position of the item. So things got straight:
Find the currently-focused control.
Get the CLASS of the control.
Check whether it's CLASS is an EDIT.
On CodeProject there is a great example about how to find the focused control. To get the CLASS name of that control, use GetClassName API.

Create an application and attach it on right-click on a file

I want to make an application in C# VS12 preferably, and I want to attach it on right click menu passing the filepath as an argument, it would be great if I could do that on multiple selection too. How do I make that happen?
in the installer of your application you need to add a file extension association. (for development you can test that by registering the extension manually: right click, open with...). the file name that was clicked will be passed to your app as a command line argument (those are the args[] in the main method of you app).
multiple selection is a bit trickier but certainly doable. when your app starts you need to check if you have an instance of the app already running (using a mutex for example) and send a message to that instance with the file name you received.
If you have not worked with context menu handling, you should take a look at this tutorial.
For the file path handling, you could take a look at this image editing example.

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.

Microstation launching into a blank window (no menus or anything)

We have a VB6 application here that automates the process of opening drawings and printing them with a specific printer that turns them into TIFF files.
I'm in the process of testing the application as we upgrade from V8 to V8i and I'm running into some problems just launching the application.
If I open the Microstation normally via the exe file everything works ok. But when I do:
Set msApp = CreateObject("MicrostationDGN.Application")
It opens a blank microstation window with no menus or anything (basically what the window looks like behind the file open dialog)
And then I do
msApp.OpenDesignFile ("dummy.dgn")
that looks like this: imgur.com/A5rc4.png
Is there something new with v8i where it doesn't bother loading the gui when opened as an object?
Did your application depends on some user preference of Microstation? I think you can debug your aplication step by step.
You can call the ustation.exe with the parameter -debug. This creates a file called debug.txt in the current working directory.
There you might find some helpful info.

Resources