You can see my previous article on showing the pick icon dialog. I did not just update that article, because for those who only want to show this dialog, it is a simple solution. In this article, I am going to customize this dialog. Actually, all this started as I am working on a project which needs me to install a hook in a DLL. So as a start and simple way to know how hooks work, I created this and it worked.
The first change I made is that now it is a simple class which wraps all the hell of calling API, making a Unicode string and converting it back and the hooking.
Hooking the Dialog
What I want to do is to show the index of the currently selected icon on that dialog. For this purpose, I want to put another static control on the dialog. But where do I place that static control. First I tried to shrink the icon list box but could not succeed. For a brief discussion, see my blog. Then I made the actual dialog taller, and moved the buttons down. For all this, I set a hook with
SetWindowsHookEx() of type
WH_CALLWNDPROC. In this hook's procedure, I made my changes. I handled two messages
As most of you have seen, most window dialog boxes and other such APIs provide us a facility of callback. What are these? A callback is a function in our application (or DLL) which is called by Windows operating system. Why is it called? When setting a callback for a dialog, it is stated in that dialog's documentation what the purpose of that callback is. When is it called? This will also be stated there. For example,
SHBrowseForFolder dialog also provides us a way to tap it by setting a callback in
BROWSEINFO.lpfn member. After setting this callback, you will be able to easily know what is happening in that dialog. But in the case of
PickIconDlg(), I have no such option, meaning this dialog does not give us a proper way to know about its events. That is why I hooked it.
How Hook Works
The working of the hook process is not much difficult, Just set a hook, then show the dialog you want to be hooked, and remember to unhook after you finished, normally after dialog is dismissed. After a hook is set, it is the same as you have set a callback for that dialog. Now for the lifespan of that dialog, you can watch every event of that dialog from creation to destruction of that dialog. In that hook function which is told at the time, the hook is set (here
CallWndProc() is the function which will be called).
mhHook = SetWindowsHookEx(WH_CALLWNDPROC ,CallWndProc, NULL, AfxGetApp()->m_nThreadID);
You will receive all messages of that dialog. Now it is upon you which messages you want to handle and which you want to ignore.
WM_INITDIALOG message is the place in which I make all visual changes of the dialog, I make the dialog taller, then move the buttons (there are three buttons, not two. One is hidden.) down and place my newly created static between listbox and buttons.
LRESULT CALLBACK CPickIconDialog::CallWndProc(int nCode,WPARAM wParam, LPARAM lParam)
if (nCode < 0) return CallNextHookEx(mhHook, nCode, wParam, lParam);
CWPSTRUCT *msg = (CWPSTRUCT *)lParam;
WM_COMMAND message is actually handled only for a notification
LBN_SELCHANGE, which is sent every time selection changes in
listbox. Here I update my static control.