IWebBrowser2 blocks IFileDialog - c++

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

Related

SHOpenFolderAndSelectItems for explorer replacement program

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

How to unload ActiveX's ocx without terminating main application to allow the ocx to be overwritten?

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.

How can I change the language in AfxMessageBox?

I have an MFC app that uses AfxMessageBox to display message boxes. The app itself lets an end-user to change the user interface language. On the inside it does so by loading resources using LCIDs (or FindResourceEx API.) My issue is that I can't seem to make AfxMessageBox to take LCID to change the language for OK, Cancel buttons, etc. This also affects File and Folder Open dialog windows.
Any ideas how to do this?
PS. This approach must work under Windows XP and up.
According to this SO article, there are no standard functions for this, there's a link to a CodeProject article "Localizing System MessageBox" with source code for a DLL (it's in c# but seems simple enough to be rewritten in C++) which uses Windows Hook so that you can supply your own text for the MessageBox buttons; there's even a suggestion for sizing buttons to the text in the discussion part of the same article.

How do I get a reference to a Win7 library from a common controls dialog hook?

I am implementing an OFNHookProc to instrument a common controls GetOpenFileName() dialog on Windows 7. My instrumentation is written in C++. Things work fine until the user selects a Library (like Documents or Pictures). When this happens, I get the CDN_FOLDERCHANGE notification like I expect, but when I send the dialog the CDM_GETFOLDERPATH message to retrieve the newly selected folder, I get an error return of -1, with CommDlgExtendedError returning 0. In some ways, this makes sense, since it's not a folder, but none of the other messages seem to work either (like CDM_GETFOLDERIDLIST or CDM_GETFILEPATH).
So, how do you tell from an OFNHookProc that the currently selected item or folder is a library? Once you can tell that it's a library, how do you get an IShellItem or IShellLibrary interface to it such that you can figure out what file system folders constitute the library?
(The code that creates the GetOpenFileName dialog is legacy code, so I can't replace it with the Windows-7-recommended IFileOpenDialog interface that supports Libraries in a sane manner).

Handling Messages in Console Apps/DLLs in C++ Win32

I would like to have the ability to process Win32 messages in a console app and/or inside a standalone DLL.
I have been able to do it in .NET with the following article and it works great in C# inside a console app and standalone DLL
http://msdn.microsoft.com/en-us/magazine/cc163417.aspx
Is there a way to do the equivalent with C/C++ Win32 APIs? I have tried doing RegisterClassEx(...) and CreateWindow(...) even passing in HWND_MESSAGE to hWndParent but the trouble is that after the "invisible" window is created messages are not being processed probably due to the lack of a message pump.
Where would the message pump go if you had a DLL entry point? I have tried creating another thread in a DLL and put while(GetMesage(..)) there but that did not work either.
Any ideas?
You need a message pump yes. The window also has thread affinity so it needs to be created on the same thread that you're running the message pump on. The basic approach is sound, if you include more code it may become clear what the problem is.
In addition to what Logan Capaldo said, you also have the problem that, as a DLL, you don't know at compile time what kind of process is going to be loading you at runtime.
If you are being loaded by a console application (/SUBSYSTEM:CONSOLE), then creating a hidden window of your own and setting up a message pump on that same thread will work fine (as long as you are the first window created).
If you are being loaded by a windows app (/SUBSYSTEM:WINDOWS) then you might run into problems getting messages. They will be sent to the top-level window in the hierarchy, which you didn't create. You'll need to get the hWnd of the main process and subclass it (if you aren't already).
If you are being loaded by a service, then you aren't going to get window messages at all. You instead need to use the RegisterServiceCtrlHandlerEx Function