Why is CMFCMenuBar not utilizing the accelerator table? - c++

In a doc/view project using VS2008, a MFCMenuBar seems to load the correct MENU resource (IDR_MAINFRAME) from the project, since adding and removing menu items is reflected in the menu's UI. It even appends the accelerators to the default menu items (e.g. Ctrl+O to the Open... item). However, the accelerator table (IDR_MAINFRAME) doesn't seem to be connected to the menu. Changing the default Ctrl+O for Open... to something like Ctrl+7 doesn't work. The Ctrl+O is still appended to the Open... menu item, and Ctrl+O still invokes the Open... handler. There is only one accelerator table in the resource file, so I have no idea where the CMFCMenuBar is getting its accelerator information.
At this point, I've been able to get the accelerators to work by manually loading the IDR_MAINFRAME accelerator table and translating messages myself. But the CMFCMenuBar is still appending the default accelerators.
Can anyone explain what is going on here? How can I force the MFCMenuBar to utilize my accelerator table and either not append the accelerators or append the correct accelerators?

Having just spent far too much time wrestling with this problem I thought I'd post the solution that appears to work for me.
I call :
theApp.GetKeyboardManager()->ResetAll();
after the MDI framework stuff has been loaded from the registry (I've created a specific function called PostLoadFrame() which I call immediately after calling LoadFrame() which is where the registry seems to get read).
This function call ignores any accelerators loaded from the registry (which is fine for me because I don't allow customisation of them anyway) and uses the accelerators in your resource file instead.
Like I said, it seems to be working for me in my application. If you do allow customisation of the accelerator keys, then it looks like it's possible to merge your resource file and the registry stored values with other functions in CKeyboardManager, but it's a bit more complicated.
I hope that helps somebody somewhere save some of the time I've lost!!

Apparently some CMFCMenuBar settings are persisted to the registry (HKCU I think.) Try clearing your application's registry settings and see if the correct accelerators are shown.
See this MSDN thread for some related CMFCMenuBar troubleshooting.

Related

How can I open an *modal* file dialog with IFileOpenDialog?

I've been trying to implement a file dialog into my C++ application for a while now, and I achieved good success with the code described in this article (It is german, but the code should be understandable):
https://msdn.microsoft.com/de-de/library/windows/desktop/ff485843(v=vs.85).aspx
However, using this code in my window class, which is a CDialogImpl, I just can't find out how to make this file picker modal. If I use this code, I can just spawn multiple file picker.
Of course, I could just keep track of the state by adding a member variable representing the state, but it would still not solve the problem of being able to click around in the main window while the dialog is opened.
Is there any way which would allow me to make this window modal? I've been trying to scan through all available methods, but I couldn't find anything. I didn't find any flags which could be passed in the creation, neither any options which I could set after creation.
Any help is appreciated!
The example you link to is very simple and has no UI other than the file dialog. Your program is more complex, having a window from which the file dialog is invoked.
You need to provide an owner for the file dialog. When you do that the owner is disabled, part of what makes the dialog modal. Failing to pass an owner means that the other windows are not disabled and so still respond to user input.
The example code provides no owner, but since there are no other windows in that program, that is benign. Modality is only meaningful when there are multiple windows.
So, to solve the problem, pass the owner, the handle of your window, to the Show method of the file dialog.
Disabling owner windows is one of the key parts of a modal dialog. You will find that any API for modal dialogs expects you to specify an owner. Get into the habit of expecting to provide that ownwr window, and looking for the means to do so.

MFC application with dynamically created controls suddenly stops responding

I have a MFC application (Visual Studio 2010) which dynamically creates and destroys lots of editboxes, drop-down boxes, and buttons, based on the user's consequent input.
I used "Create" function to dynamically create controls, and when deleting controls the system first calls "DestoryWindow" function for each control, and then delete each control pointer.
After iterating certain amount of creating/deleting controls, if I try to "open" the dropdown menu, the system fails to open it and stops responding to my input - but I can add more controls, if I do not try to open the dropdown menu.
Could somebody please let me know how to workaround this strange issue? This one nearly drives me crazy...
Workaround is simple - don't try to "open" that menu :)
Now I assume that you want to FIX the issue. Then you need to figure out what is going on. The system may be non-responsive for multiple reasons, most likely one of these two:
You are in a busy loop in your main UI thread.
You are waiting for an event that never happens. Deadlock, for example.
When your application is frozen, try to attach debugger to it and do Debug -> Break All. Then see what code is executing. If the reason for this "freeze" will not be obvious, please post relevant code.

ActiveX Property Persistance

I have a question about an ActiveX Control I am developing. I have hashed my way through most problems but I am stuck at a real road block. This ActiveX is being imorted into other software so I have to have a good implementation of the Property Pages. I have managed to get some persistant properties working with one issue. When I make a change in the property page it is updated and persists as long as the application that is development app that is using it is open but it reverts back when I reload the app. I have narrowed this down to the fact that the development app doesnt realize the ActiveX has changed and therfore doesnt save. If i make a unrelated change and save the program all is good and the values persist as expected. I have tried everything and cant seem t get the application that imports my ActiveX to realize when it has changed via the property page. I am wondering if anyone has some work arounds for this type of problem. It seems to me if I could force the DoPropExchange() it would work but I dont know how to call this explicitly.
Thanks in advance
Matt
Thanks for the input. I did have the SetModifiedFlag() but it wasnt working. After poking at it I solved that problem but now I am redirecting my question. I had removed the property above in question from the idl files dispinterface in order to prevent the application that loads the activex from displaying the property in its "Connection List"(3rd party application specific"). It appears that the app loads all the interface into this list but this is not good as some properties should be persistant and only modifiable through the proppages. I tried all the flags like hidden and local but still were displayed in the list. When I removed it from the dispinterface it was how I wanted it but would not signal the IsModified. My new question is in there another way to define properties for an instance like this or is it possible to have a secondary interface(I have not tested if the application would see this interface because I am not sure how I would go about defining this inteface)or to have a property only between the proppage and control. Or is there another way to signal the dirty. The OnMemberVariable of the control was properly executing I know from testing it just seems SetModifiedFlag() doesnt do anything if the property is not in the dispinterface
Thanks Again
You need to mark your control as "modified", so that its host could detect it and re-save persistent properties. In this case IPersistXxx::IsDirty implemented by your control would indicate dirty state.
MFC based control has COleControl::SetModifiedFlag for this purpose:
Call this function whenever a change occurs that would affect your control's persistent state. For example, if the value of a persistent property changes, call this function with bModified TRUE.
Update: To hide a property from property browser you can use nonbrowsable attribute.
Use the [nonbrowsable] attribute to tag an interface or dispinterface member that should not be displayed in a properties browser.

Safety of using \ApprovedExtensionsMigration\ for Auto-BHO enabling?

I'm in the process of looking into auto-enabling an IE9 toolbar so the user does not need to click the enable button, and I noticed another company used the following method.
Delete the registry key HKCU\Software\Microsoft\Internet Explorer\ApprovedExtensionsMigration\
Create a new key under HKCU\Software\Microsoft\Internet Explorer\ApprovedExtensionsMigration\
Add my toolbar's CLSID string value HKCU\Software\Microsoft\Internet Explorer\ApprovedExtensionsMigration{XXXXXXX....-XXXX}
x. Internet Explorer 9 automatically enables my toolbar and proceeds as if the user had clicked enable.
I have not found any documentation for this method, but I believe the way this works is Internet Explorer 9 believes the toolbar is going from IE8->IE9, and enables the toolbar. Should this method be considered unsafe for use (too hacky and will instantly get flagged by anti-virus), or is this considered a valid way of auto-enabling a toolbar?
Also, does anyone know if this method works in Internet Explorer 10?
Can't find any resources about this method. Viruses will use this method for sure (see http://www.threatexpert.com/report.aspx?md5=bde1312b225ad987b57b1dbef0885817 which is an identified virus that do exactly that), but since this registry is deleted (or at least the Time Stamp value is changed) in legitimate scenarios, it is possible that anti-viruses will not freak out, as they don't want to create false positives.
Regardless, what you are trying to do feels bad.
Also you should consider other users on the machine (not currently logged in).

can I set the AppUserModelID of an arbitrary process launched through a jumplist?

I have a simple console application written in C++ that acts as a stub for launching another application through it's jumplist. Purpose is to add jumplist abilities to applications that do not support this. Call it stub.exe. When running stub.exe it creates a custom jumplist using these steps (taken right form the MS samples):
create an ICustomDestinationList
ICustomDestinationList::BeginList()
create an IObjectCollection
for_each item_to_add
create an IShellLink, set its path/arguments/title/icon
add IShellLink to the IObjectCollection
get the IObjectArray interface from the IObjectCollection
call ICustomDestinationList::AddUserTasks( IObjectArray interface )
ICustomDestinationList::CommitList()
When pinning stub.exe to the taskbar and right-clicking it, the jumpilst appears and it contains all IShellLinks added. When clicking an item, it will launch the corresponding process.
Now I'd like a process launched through this jumplist have it's window(s) grouped under stub.exe's taskbar icon, instead of having it's own group. They key to get this working seems to be the AppUsermodelID. This is what I tried so far:
just for testing, create a couple of shortcuts and set the id through IPropertyStore->SetValue( PKEY_AppUserModel_ID, "id" ). Indeed, when launching these shortcuts, they will all group under the same taskbar icon.
since the shortcuts do what I want, I tried adding shortcuts to stub.exe's jumplist: no effect. The shortcuts don't even show up in the jumplist (maybe one cannot have a shortcut to a shortcut?), yet all methods return S_OK
setting the PKEY_AppUserModel_ID on each of the IShellLinks that get added to the jumplist: no effect
calling ICustomDestinationList->SetAppID(): no effect
instead of using SubTasks, tried with SHAddToRecentDocs: no effect. The recent doc list does not show up. But now things get messy. After setting the AppUserModelID on the shortcut that is responsible for the pinned taskbar item (the one in %APPDATA%/Roaming/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar), the jumplist changed: it does not show the 'Tasks' item anymore, but does show 'Recent' and the items I added using SHAddToRecentDocs. Now when clicking them I get a dialog box with a title that starts with 'd:\desktop' followed by Chinese characters. Hovering the items in the jumplist also shows Chinese characters instead of the descirption I set.
Questions:
What's with the Chinese characters in the jumplist?
How come setting the app id on the taskbar shortcut toggles between 'Tasks' and 'Recent' sections, why are they not both there?
What would be the way, if even possible, to achive what I actually want: a custom jump list of which the items launched will group under it's taskbar icon? (note that the processes I plan to laucnh their do not have their app id set currently)
not much reactions here ;]
In the meantime I managed to solve the main problem myself; it's not quite a straightforward solution but it fullfills the requirements: a program runs in the backround and installs a CBT hook. Each time an application creates a window (HookProc code = HCBT_CREATEWND), the hook checks the application's path against a map containing paths and desired application ids. If a match is found, the application id of the HWND is set. Since this occurs before the window is actually shown and is combined with the custom task list, from a user's point of view the application behaves just like one that does support a recent/pinned document list.