How to prevent "How do you want to open this file" dialog? - c++

In my app I open a report using HTML file as such:
//pStrPath is file:///C:/Users/appts/AppData/Local/Temp/Report_View.htm
ShellExecute(hParentWnd, L"", pStrPath, NULL, NULL, SW_SHOW);
On my development machine it opens up in a web browser, but when I just tested it on a new installation of Windows 10, it showed this dialog instead:
So how can I prevent it from being shown and go with "keep using this app" option from the get-go? Otherwise it may be very confusing for my users.
PS. Note that Edge is installed and can open .htm files if I double-click them.

Referring to Launching Applications (ShellExecute, ShellExecuteEx, SHELLEXECUTEINFO) we note the text
Object Verbs
The verbs available for an object are essentially the items that you find on an object's shortcut menu. To find which verbs are available, look in the registry under HKEY_CLASSES_ROOT\CLSID{object_clsid}\Shell\verb
Commonly available verbs include:
edit - Launches an editor and opens the document for editing.
find - Initiates a search starting from the specified directory.
open - Launches an application. If this file is not an executable
file, its associated application is launched.
print - Prints the document file.
properties - Displays the object's properties.
Given that a double-click is the generally equivalent to selecting "open" in the object's shortcut menu, if we supply the function with the open verb, we can expect the behaviour to mirror that of a user's double-click. - Please see Ken's comment below
As such, we can expect the following code to achieve the desired result.
//pStrPath is file:///C:/Users/appts/AppData/Local/Temp/Report_View.htm
ShellExecute(hParentWnd, L"open", pStrPath, NULL, NULL, SW_SHOW);

If you are trying to open the default program FROM a 32 bit program in 64 bit Windows the ShellExecute and ShellExecuteEX may display the "How do you want to open this file?" dialog box each time. This is due to the way that the default program registered itself in Windows I think.
I could reproduce this error on Windows 11 fresh install where the Photos is set to the Default Program for .jpg files.
In my case, I found that if I use the ShellExecuteExW function and pass the extension into the .lpClass of SHELLEXECUTEINFOW Type that it works.
It should also work with the ShellExecuteExA function
Make sure it's not an exe, reg, bat file, or a URL you are trying to open. It has to be a document type of file.
Use the .lpClass to pass the extension like ".jpg"
Add the SEE_MASK_CLASSNAME As Long = &H1 to the .fMask parameter you are passing in like .fMask = YourMaskValue Or SEE_MASK_CLASSNAME
The reason I think this works is it bypasses any redirection and reads directly from the HKEY_CLASSES_ROOT.jpg

Related

Modifying the Windows Explorer Toolbar with WinApi / c++

My task is to program change sorting parameter of files and folders in my operating system.
In the article on the MSDN:
under
Modifying the Windows Explorer Toolbar
indicated
In addition to modifying the Windows Explorer menu bar, you can also add buttons to the toolbar. And an example code.
But example of this modifying the Windows Explorer menu bar is not there, the only thing is there it's button adding example.
An alternative article has an example of opening it, so my question is: is it even possible, and if it is, how to do it?
The folder sort settings are saved to:
HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags\
HKCU\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\BagMRU
The entries look like:
You would need to loop through all of these registry entries and change the 'Sort' key. This would only affect folders which have already been accessed.
If you want to see how these lists are parsed, run ShellBagsView while running ProcMon and log all the interactions with the registry.
To do it, not programatically you can follow these instructions:
https://superuser.com/a/1481763/1043059

Load URL in Default Browser and Bring to Front

I have a fullscreen application written in c++ using straight winapi. The application contains an embedded web browser (using CEF, but I don't think that matters in this case). I am currently intercepting any popup windows as the result of clicking on a link and opening them in the systems default browser using ShellExecute. However, on many of our test systems the browser window is displayed behind my application window, which is a problem since my window covers up the task bar so the user has no indication that a new window has been displayed.
I've read everything I can find on this site and others and have not been able to find a single solution that works:
Using ShellExecuteEx to get the process handle, then using the process handle to find the window handle and bringing it to the front - Many times the process handle is NULL, which appears to be related to the browser opening a new tab in an existing window. In addition, if Edge is the default browser then the process handle always seems to be NULL.
Using ShellExecute (or Ex) then finding the new window based on the name - I have no idea what the name of the window will be. It's based on the content that is opened, which may be many different things depending on the link the user clicked (html, pdf, etc).
Attempting to figure out the path to the default browser and then launching it using CreateProcess - So far I haven't had any luck with this if Edge is the default (since apparently Edge is a "modern" application that doesn't have an executable that can be launched with CreateProcess). If anyone knows how to make this work I could see this actually being a decent solution.
So right now I'm heading down a path of enumerating all of the windows before and after launching the browser and attempting to figure out which one is the correct one to bring forward. I'm envisioning all sorts of issues that could possibly occur (a tab opening on an existing browser for instance). If anyone has any solution to the issue I would appreciate it!
Edit: Code I'm using for ShellExecuteEx:
SHELLEXECUTEINFO sxi = { 0 };
sxi.cbSize = sizeof( sxi );
sxi.nShow = SW_NORMAL;
sxi.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
sxi.lpVerb = _T( "open" );
sxi.lpFile = url;
if( ShellExecuteEx( &sxi ) )

MFC CFileDialog open only select files

Using CFileDialog as a file open, I need to allow the user to only select a file that is displayed in the dialog list area, such as by clicking on it. We don't want the user to be able to type in a name in the File Name control. The OPENFILENAME (OFN) struct has several different flags (http://msdn.microsoft.com/en-US/library/ms646839%28v=vs.80%29.aspx), but I don't see one that prevents the user from typing in a filename.
The closest thing I saw was OFN_FILEMUSTEXIST, but that only specifies that the file exists; it still allows the user to type in a name.
Is there any way to do this without inheriting a new class?
MORE INFO
We need to prevent them from typing in a filename because they could open an inappropriate one. With the lpszFilter parameter, we filter the filenames so it only displays files with ABC in the filename (not the extension). So if they typed in a filename, they could enter something like myCoolFileDEF.ext. If the file exists, it will go ahead and let them open it (the dialog will close w/o an error message) even though they were only supposed to open files with ABC in the filename.
Since you are using MFC, just inherit a CFileDialog and disable the file name edit control and combobox. I don't see the point of using CFileDialog AND writing another OFNHookProc callback, though you could start from GetOpenFileName if you want to.
As a previous answer notes, you could root around in the dialog for the filename control and disable it. This is not without penalty though - if you turn on the CFileDialog hook callback logic, you get the "old style" file dialog on Vista and above, not the "new style" one. The "new style" file dialog is a lot more restrictive in what can be customized, and, as far as I know, doesn't provide a supported way to get at the filename control.
Reading your question, my first instinct is that you're over-designing your solution: if you supply a filter then the user has to go to quite a lot of trouble to select the wrong sort of file, and most users won't do that. If they do, it's possible that the user knows better than your program. If it were me, I would just use a filter, then after the file dialog has closed, check the returned filename - if it doesn't match the required pattern, I'd put up a message dialog to ask if the user if they're really sure, and open the file anyway if they insist that they are.

Is there a special method to remove a shortcut from a desktop?

I created a shortcut (.lnk) file on the desktop using the IShellLink interface similar to the code described at the bottom of this page.
So my assumption was that to remove this shortcut I could simply call DeleteFile on the .lnk file, but evidently it is not enough... if I do that I get a remnant of the shortcut file that looks like this:
But what is interesting is that if I browse files in the desktop folder, say with Windows Explorer, the .lnk file is not actually there. What I see is some artifact on the desktop GUI surface.
Any idea how to remove a shortcut (the way Microsoft wants it done?)
OK, per suggestion above, here's the API that needs to be called afterwards to refresh the shell:
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH | SHCNF_FLUSHNOWAIT, pDeletedFilePath, NULL);

How to restrict FileDialog to specific path

Is it possible to restrict a file dialog(open/save) to a specific folder is winapi?
OPENFILENAME fileDialogSettings;
...
fileDialogSettings.lpstrInitialDir = "Some path";
...
if(GetOpenFileName(&fileDialogSettings))
{
}
I want to have "Some path" as root path in the dialog and to restrict navigation to this folder and it's sub folders only. May I use lpfnHook for this?
If you're targeting Vista+ only, you can make use of the IFileDialogEvents::OnFolderChanging method to block the change altogether.
For older versions of Windows, the OpenFileDialog allows you to specify a hook procedure in which you can pick up on the CDN_FOLDERCHANGE notification.
While I can't see any message to disallow the change, you may be able to post a message to tell it to go "back", or just disable the "OK" button.
Another option is to handle CDN_FILEOK notification and refuse paths outside your required directory.
See this MSDN article for more details about the hook procedure.
This question also talks about changing the directory in an open dialog.
Look into OFN_NOCHANGEDIR flag, although the documentation says this:
Restores the current directory to its original value if the user
changed the directory while searching for files.
This flag is ineffective for GetOpenFileName.
Edit: Reading your question again, I guess you don't want the user to navigate up from that directory, not sure if this is possible with GetOpenFileName, you might have to create your own dialog with a directory list view and restrict them that way.