MFC resource.h command/message IDs - mfc

I'm working on an MFC application, that got pretty messy over years and over different teams of developers. The resource.h file, which contains all command/message mappings grew pretty big over time, and has lots of problems (like duplicate IDs). I am not proficient with MFC, so the question might sound pretty stupid...
MSDN docs mention that Command IDs and Message IDs should not be less than WM_USER and WM_APP correspondingly. I saw that most of the command IDs in resource.h generated by Visual Studio begin around 100. Shouldn't this cause some interfering with MFC/Windows commands and messages, that overlap with the application defined IDs? For example, I have a command ID :
#define ID_MY_ID 101
and there is a windows command that has the same ID. When MC send this command to the APP, it's handled like an application defined ID_MY_ID, and the app is taking unnecessary actions. Is it a possible scenario?
Also, is there some third party tool that helps to profile the project resources?
Update 1:
New question showed up:
What is the preferred way of adding new custom commands to the application classes? As I understood, before they were added in the following way: add a command ID to the resouce.h, and then add a message map handler to the handling class.

You are mixing two things:
Message IDs. These must be larger than WM_USER. Message IDs are not defined in resource.h. It seems from your description that you are not using application private messages.
Command IDs. Your application itself must not have duplicate command IDs. The command ID values should also not interfere with the standard MFC IDs defined in afxres.h. Theses command IDs start at 0xE100, so it is unlikely that the values in resource.h. The resource compiler will generate an error for duplicate IDs in you rc file
There is probably no need for you to edit resource.h manually.
I would recommend to use the "Resource symbols" tool (right click on the resources in resource view and choose from the popup menu, I assume you are using VC++), to remove all the unused IDs from resource.h.

command messages are sent in WM_COMMAND with command id in parameter so it won't conflict other messages.

Generally, there is no need to insert or edit the identifiers in resources manually (identifiers assingned by VS automatically in a correct manner). There are some cases that require manual interference in identifiers, but you can start with assumption, that work of previous teams of developers with resources was right. So if you did not encountered a problem because of resources, keep them untouched (IMHO).
"MSDN docs mention that Command IDs and Message IDs should not be less than WM_USER and WM_APP correspondingly." - It seems you something mixed up.

Related

Using a dialog box to graphically retrieve user input

I am not new in C++ but this is my first time developing a Win32 program. It has to be graphical and so I have been attempting to get user input using an input/dialog box with no success.
I have read this topic on MSDN and found it helpful, but I get an error about IDD_PASSWORD and IDE_PASSWORD not being defined. Declaring them in resource.h and giving arbitrary values (like 110, 111) yields no results. Other attempts I have tried to modify the auto-generated about box, which also yields no results after modification, I noticed that if i change the value of IDD_ABOUTBOX in resource.h from 103, this also does not work. I also tried using the .rc under Resource View, but still no results.
So I'd like to know if the resource box templates have predefined constant numbers that i have to use, if so where because I searched that too or if there is another way to obtain user input in a windowed application. I just want to obtain an integer, that's all.
There is nothing magic in the numbers assigned to resources. The numbers are what the code actually uses to identify the resources. Visual Studio just allows you to assign symbolic names to those numbers through the use of C macros (i.e., #define) to make your code easier to read. These values are all defined in the file resource.h by convention, and although you can modify that file manually, you usually should not do so—let the Visual Studio Resource Editor handle that for you.
The problem you're running into is that you actually have to create those resources first before the numbers will mean anything. When you create a new Win32 project, Visual Studio will automatically create an about box dialog and give it the symbolic ID IDD_ABOUTBOX. However, there is no such IDD_PASSWORD dialog created by default in a new project, and there isn't one built into Windows.
You can create this dialog yourself using the Dialog Editor (part of Visual Studio's Resource Editor), which is pretty easy to do as it allows you to drag controls around on the dialog where WYSIWYG. When you add a new dialog box to your project's resources, you will be given the option to name it anything you like. You can use IDD_PASSWORD if you want, or any other name. A numeric ID will be assigned automatically based on an algorithm; generally the lowest available number is used.
The article you linked to is assuming that you have already added a dialog to your project with the symbolic name IDD_PASSWORD (which is probably a mistake on the part of the author). All it shows you is how to display that dialog once it exists as part of your project's resources.
It's going to be somewhat difficult to learn Win32 programming just by reading the MSDN documentation. I strongly suggest getting a book that explains it more clearly and in a more logical order. The canonical text is Charles Petzold's Programming Windows, 5th Edition. Note that you will need to make sure you get the 5th edition, as the newer editions digress from their Win32 roots and start talking about completely unrelated things like C# and Silverlight.
If you absolutely must learn by trial-and-error and MSDN, start reading about dialog box resources here.

Is there a way to choose which files are displayed to the user via the standard OPENFILE dialogs?

Vista introduced an interface: IFileDialog::SetFilter, which allows me to setup a filter that will be called for every potential filename to see if it should be shown to the user.
Microsoft removed that in Windows 7, and didn't support it in XP.
I am trying to customize the our Open file dialog so that I can control which files are displayed to the end user. These files are marked internally with a product-code - there isn't anything in the filename itself to filter on (hence file extension filters are not useful here -= I need to actually interrogate each one to see if it is within the extra filter parameters that our users specified).
I would guess that Microsoft removed the SetFilter interface because too often it was too slow. I can imagine all sorts of similar ideas to this one which don't scale well for networks and cloud storage and what have you.
However, I need to know if there is an alternative interface that accomplishes the same goal, or if I really am restricted to only looking at the file extension for filtering purposes in my File dialogs?
Follow-up:
After looking further into CDN_INCLUDEITEM, which requires the pre-vista version of OPENFILENAME, I have found that this is the most useless API imaginable. It only filters NON-filesystem objects. In other words, you can't use it to filter files. Or folders. The very things one would filter 99.99% of the time for a file open or save dialog. Unbelievable!
There is a very old article by Paul DiLascia which offers the technique of removing each offending filename from the list view control each time the list view is updated.
However, I know from bitter experience that the list view can update over time. If you're looking at a large folder (many items) or the connection is a bit slow (heavily loaded server and/or large number of files), then the files are added to the dialog piecemeal. So one would have to filter out offending filenames repeatedly.
In fact, our current customized file open dialog uses a timer to look at the view's list of filenames periodically to see if any files of a given pattern exist, in order to enable another control. Otherwise it's possible to check for the existence of these files, find none, but a moment later the view updates to have more filenames, and no events are sent to your dialog to indicate that the view has been changed. In fact, my experience with having to write and maintain code for the common controls file dialogs over the years has been that Microsoft is not very cluefull when it comes to how to write such a thing. Events are incomplete, sent at not-useful times, repeated when not necessary, and whole classes of useful notifications don't exist.
Sadly, I think I might have to give up oh this idea. Unless someone has a thought as to how I might be able to keep up with the view spontaneously changing while the user is trying to interact with it (i.e. it would be awkward to go deleting out entries from the list view and changing the user's visual position, or highlighted files, or scroll position, etc.)
You need to initialise the callbacks for your CFileDialog. Then you need to process CDN_INCLUDEITEM notification code to include or exclude items.
You can also check this great article. The author uses some other approaches in addition to callbacks
As you have already discovered, starting in Windows 7 it is no longer possible to filter out files from being displayed based on content, only file extension. You can, however, validate that the user's selected file(s) are acceptable to you before allowing the dialog to close, and if they are not then display a message box to the user and keep the dialog open. That is the best you will be able to do unless you create your own custom dialog.

VC++ 10 MFC: What is the correct way to do localization

I am a .NET guy who is having to do some work on an MFC app. The app is a VS2008 MFC executable which I have converted to VS2010. The original developers did localisation by specifying the name of a .txt file with key value pairs in it on the applications command line. Installed shortcuts to the executable specify a different .txt file depending on which country the app is being installed in. This of course does not work if you just run the .exe directly. This seems like a weird way to do things to me.
I want to do this the propper MFC way, but I am having difficulty finding definitive answers on Google. My understanding is that the String Table in the .rc file should be used for this localisation? Is this the current best practice for MFC?
With respect to the String Table I have read that the practice is to create multiple string tables each for a different language. How do MFC applications choose which language to use? Is it based on the machines current language settings or can I control this (it may be that we want the language to be specified by the Wix .msi installer we are also building)?
I have also read that embedding all resource inside an MFC application has fallen out of favor and that now you should compile seperate resource .dlls? Is this is true ill investigate how to do it...
Finally, do I have to do something special to get MFC to support Unicode or is MFC Unicode by default?
Thanks
The idea is that all localizable items should be stored in resources. Standard UI objects such as menus and dialogs are automatically stored in there (resources) for you but items such as string literals (eg: error messages, messagebox prompts,...) should be pulled from source code to the string table. This short codeproject article of mine demonstrates how to easily pull strings from the string table in your code.
Note: You should have only one string table in your resource script (.rc).
From there on, you can translate your resources and create resource DLLs (aka satellite DLLs). The idea is that you keep a different copy of the .rc file(s) for each language. Each translation is compiled into a codeless DLL that acts as a container for the resources.
This other codeproject article of mine lets you easily load resource DLLs according to system settings or user preferences: The code looks among your resource DLLs which available language best matches user settings (based on user's UI language and regional settings). The code also lets you easily build a menu with all available languages. That way, your user can override the default choice.
DISCLAIMER: My ad follows. Feel free to skip :-)
Regarding the translation of resources, the management of translations and the creation of resource DLLs, you may want to check out appTranslator.
END OF AD :-)
Regarding Unicode, MFC ships with ANSI and Unicode versions of the code. It's up to you to choose if you want to build an ANSI or a Unicode app: Just make your pick in the first page of project settings. Of course, if you are startgin from scratch, you should definitely go Unicode. But if legacy reasons force you to stay ANSI/MBCS, don't worry to much: It won't prevent you from localizing your app.
Years ago when I had to work with multiple languages in MFC, we used separate resource DLLs. All you need do is make one call to switch which handle the resource functions would use and all was automatic from that point forward.
You need to do more than just change the strings. Dialogs in particular will have strings inside of them, and you may need to change the layout if those strings become too long after translation.

How to write a shell extension in C++?

This seemed like a common question but after doing some searching, I wasn't really able to find my answers. There is an article on this here:
http://www.codeproject.com/KB/shell/shellextguide1.aspx
But it's for a very old version of Visual Studio. I'm using VS 2008, so the instructions and interfaces don't seem to match what I'm seeing.
I want to create a simple shell extension using C++ that creates a context menu for files with extension .GZ. When right clicking on these files, I should be able to click my context menu item and have a callback in code to do some sort of operation on that file.
Other context menu items would do things like spawn modless dialogs to accept user input before executing some action.
From what I've seen, ATL is used for this but I have never used ATL, so all of the object types and interfaces are very confusing to me. It wouldn't be so bad if I had a proper tutorial or documentation to read.
Can anyone help me out? Isn't there some sort of tutorial out there that isn't 10 years old?
I can't tell you exactly how to write a shell extension, but I will provide a number of tips. Writing a Shell Extension offers some significant advantages over the much simpler “registry-only” method:
With a Shell Extension, you can dynamically create a context menu item (or submenu) that is more relevant to the selected file(s). For example, if you are writing a Shell Extension for zip files, it is possible to create a submenu within the context menu that shows the entire contents of the zip.
You can handle multiple files simultaneously, which may be more beneficial not just for performance purposes but also so that you can work out what to do based on the selection as a whole rather than just for each file.
Some of the downfalls to Shell Extensions are:
Substantially increased complexity. Be prepared to spend a lot of effort on this to get it working. Have a home-espresso machine installed next to your computer and/or hire someone to make you coffee.
Substantially increased difficulty in debugging. Ditto about coffee.
It's difficult to write a Shell Extension because they can be very hard to debug.
Shell Extensions are loaded by the explorer.exe process, and without specific configuration of Explorer, you need to force-quit the explorer.exe process so that you can install a newer version of your Shell Extension. There is a way to get Explorer to unload DLLs that it is no longer using, but you should only do this on a development machine and not on a deployment target:
In RegEdit, browse to the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer
Add a new DWORD key called “AlwaysUnloadDLL” and set its value to 1.
Restart explorer.
This works most of the time, but there may still be times where you need to close Explorer because the Shell Extension was not unloaded.
Keep in mind that your Shell Extension may be loaded by other applications, for example, if you right-click on a file with an applications “open file” dialog, then your Shell Extension will be loaded into that application, and not Explorer.
If your Shell Extension causes a runtime error, quite often the result will simply be that your context menu item does not show, very rarely will you be told that your Shell Extension failed to load or that it caused a runtime error.
Configuration can be hard, even with an installation, registry data needs to be created in several places, and depending where you want your context menu to show, the places in the registry may differ between different versions of Windows.
What you'll need to do:
Visual Studio offers some shortcuts to creating Shell Extensions, but basically you'll need to create a COM DLL. A Shell Extension for context menu items must implement both the IContextMenu interface and the IShellExtInit interface.
In the IShellExtInit::Initialize() method, you can obtain the selected files from the IDataObject parameter. From memory, the data is in “Drag-n-Drop” format, so you need to get an HDROP handle from the IDataObject and query the files from there (this is from memory, it may actually be different than as I described here, so proceed with caution).
Once your DLL is ready to be “installed”, you must copy it somewhere, and then run regsvr32 to make sure it is registered.
Follow this guide to know where to put registry keys.
There may be issues with 64-bit Windows, if you build a 32-bit DLL it may not load in 64-bit Explorer… so keep this in mind if you are having trouble with 64-bit Windows.
Your DLL will actually have two GUIDs associated with it. I can't remember exactly how it works, but one GUID refers to the DLL itself and the other refers to the actual Shell Extension. Make sure you use the GUID of the actual Shell Extension when creating keys in the registry where a GUID is required.
All things considered… (tl;dr)
Weigh up the costs of whether a Shell Extension is worth it. If you want to create menu items dynamically based on the selected files, then a Shell Extension may be the only way. If you want to handle all files simultaneously then you'll probably need a Shell Extension as well.
An alternative to the context menu method, could be to have a drag-n-drop target on the user's desktop or something. Explore other ways that you could have the user submit your files to your application, because a Shell Extension is often far more effort than it is worth. I found this out the hard way and I think everyone else has too.

MFC data exchange validation

We're using MFC data exchange to validate some data and we're having some problems. We're using the DDV_MinMaxFloat call to ensure that edit boxes in various parts of the application contain floating point numbers within a specified range. When using this validation if a value is entered out of range a dialog is automatically displayed to the user indicating that the value must lie within the range specified. This has been working correctly whilst running the application in debug however when building a release we are getting problems. The validation is still performed in release mode however the message box displayed to the user is blank.
I've tried the usual forcing a rebuild, deleting old resource files and deleting precompiled header files but this continues to happen in release mode. Has anyone come across this before? Are there any obvious things to look for?
I should also add that this application is over 10 years old, so obviously has been working correctly before. Somehow something has gone wrong in the last few weeks to cause this.
Those messages will come from MFC's resource strings. There might be some conflict with your own resources. Check to make sure your resources adhere to Microsoft's guidelines TN020: ID Naming and Numbering Conventions.
Pay particular attention to this bit:
MFC's internal framework implementations reserve two ranges: 0x7000
through 0x7FFF and 0xE000 through 0xEFFF.
Somehow something has gone wrong in the last few weeks to cause this.
Since your application worked fine a few weeks ago, it should be easy: check out the last working version from your revision control system and compare it with the current version. Or try to narrow it down to the first revision which does not work any more.
Check with Spy++ if there are controls on the message box that is displayed and if the text on them is blank, or if there's no controls on them at all. If the text is empty, you'll have to check the resources or the way the messagebox is called/created. Otherwise it may be something like resource being set incorrectly and the message assuming it can read its resource strings from ::AfxGetResourceHandle(). Note that this is a very easy error to make - it's a global handle that can be changed everywhere (including in dll's that you have no control over) so changes in remote parts of the code that at first sight seem unrelated may trigger it.