I maintain a explorer/file manager tool (xplorer2) that can replace windows explorer for opening folders. However I cannot trap the "open folder and select item" operation performed by SHOpenFolderAndSelectItems API.
I found an old thread by some other file manager programmer which implied that the right way is to register the "explorer-like" tool as a shell window, then respond to some queries to supply interfaces and services like IWebBrowserApp that will allow the item(s) to be selected
I registered my top level window with the shell windows successfully as such
CComPtr<IShellWindows> pShellWindows;
HRESULT hr = pShellWindows.CoCreateInstance(CLSID_ShellWindows);
hr = pShellWindows->Register(static_cast<IDispatch*>(this),
(SHANDLE_PTR)hwTop, /*SWC_3RDPARTY*/SWC_EXPLORER, &m_dwCookie);
ATLASSERT(SUCCEEDED(hr));
the window does appear if enumerated among the shell windows. However when it is launched as a result of SHOpenFolderAndSelectItems (it is declared as an explorer replacement in HKEY_CLASSES_ROOT\Directory\shell), there are no attempts to QueryInterface or any other action on the IDispatch registered. I have tried both SWC_3RDPARTY and SWC_EXPLORER registration flags without any luck
any ideas what am I doing wrong?
ok, I figured it out. The trick is really going round the buggy documentation
Related
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 ) )
In our 32-bit Windows MFC application we use IWebBrowser2 to display HTML content. We also (because MFC does it for us and we're running on Windows 10) use the new IFileDialog COM interface to the common file open dialog.
When we have a web browser window visible in the application, the file dialog will not open, or will open once but never again unless you run the application down and back up again. What usually happens is that this MFC call:-
HRESULT hr = (static_cast<IFileDialog*>(m_pIFileDialog))->Show(m_ofn.hwndOwner);
simply returns "0x800704c7 The operation was canceled by the user" without even displaying the dialog.
Closing the HTML view/window allows the IFileDialog to work as expected, so the two components seem to be interfering with each other in some way.
This is now happening with software we haven't changed for months, and it seems only to be restricted to Windows 10, but we can find nothing online that gives any clues about the cause.
David.
I have the answer to this. a) Your syntax for calling ->Show() is all wrong. b) There are nested guards in the include file 'shobjidl.h' that are blocking processing of the definitions for IFileDialog COM classes, hence many people have been getting compilation errors, unable to generate that elusive output .exe
Essentially all you need when calling the ->Show method is the following loc:
HRESULT hr = pFileDialog->Show(NULL);
See the explanation & example program at:
https://github.com/InventorDave/IFileDialog-gcc-Fix
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
I have ActiveX controls implemented in VB6 and are instantiated inside MFC42 application.
I have a tree view structure on the left panel of the application and when different items in the tree are selected, different ActiveX are loaded accordingly on the right panel to display the details of the selected item.
Whenever I want to modify the VB code for the ActiveX, I will need to restart the application. This greatly interrupts the development flow since the application starts pretty slowly.
In some ActiveX we have dummy code/data to allow the ActiveX to be executed inside Internet Explorer, which is faster to load, but not all of our ActiveX have it.
I am expecting that when I click different item in the tree view, the previous ActiveX is unloaded and I can overwrite it with a new version.
If the ActiveX has never been instantiated/displayed, I am able to replace the ocx while the application is still running.
I searched in the internet and found two articles on ActiveX, both of them suggest that the proper way to clean up is to:
m_pControl = new CWnd;
m_pControl->CreateControl(strControlProgid,
"",
WS_VISIBLE,
rc,
this,
5000,
NULL,
FALSE,
NULL);
// ...
m_pControl->DestroyWindow();
delete m_pControl;
The ActiveXs we have are already destroyed using this method but I still need to exit the application in order to overwrite the ocx.
EDIT:
Alternatively, for VC++ 6 (with MFC42), instead of CoFreeUnusedLibrariesEx which is mentioned by Noseratio in his answer; I can use CoFreeUnusedLibraries which will work without delay for Single Threaded Apartement (STA).
Provided the COM reference counting works correctly in your app, you could try forcing to unload the no-longer-in-use ActiveX DLL with CoFreeUnusedLibrariesEx.
I have a legacy ActiveX component which runs embedded in IE. Now I want to perform some action when IE window minimized and maximized by the user. Can anybody provide any clue on how to do that?
I'm not an expert in this topic. But after some research what I could find was,
To sink Internet Explorer events from the activex control, you have to
set up the event sink, which means you must obtain the IWebBrowser2
interface implemented by Internet Explorer when it loads.
See this document for more info on Handling internet explorer events
In IWebBrowser2 I could find only find IWebBrowser2::FullScreen and IWebBrowser2::TheaterMode to be somewhat similar to your requirement.
However, there is another property IWebBrowser2::HWND that you can use to get the window handle of internet explorer.
On a wild thought, (I don't know whether its applicable for activeX controls) consider Using hooks.
Also found: IE add-on development: capturing keyboard input outside tabs